diff --git a/.buildkite/pipelines/es_snapshots/verify.yml b/.buildkite/pipelines/es_snapshots/verify.yml index aa49ba5d2641f..9af2e938db49d 100755 --- a/.buildkite/pipelines/es_snapshots/verify.yml +++ b/.buildkite/pipelines/es_snapshots/verify.yml @@ -29,6 +29,7 @@ steps: agents: queue: ci-group-6 depends_on: build + timeout_in_minutes: 150 key: default-cigroup retry: automatic: @@ -40,6 +41,7 @@ steps: agents: queue: ci-group-6 depends_on: build + timeout_in_minutes: 120 key: default-cigroup-docker retry: automatic: @@ -52,6 +54,7 @@ steps: agents: queue: ci-group-4d depends_on: build + timeout_in_minutes: 120 key: oss-cigroup retry: automatic: @@ -61,7 +64,8 @@ steps: - command: .buildkite/scripts/steps/test/jest_integration.sh label: 'Jest Integration Tests' agents: - queue: jest + queue: n2-4 + timeout_in_minutes: 120 key: jest-integration retry: automatic: @@ -72,6 +76,7 @@ steps: label: 'API Integration Tests' agents: queue: jest + timeout_in_minutes: 120 key: api-integration - command: .buildkite/scripts/steps/es_snapshots/trigger_promote.sh diff --git a/.buildkite/pipelines/hourly.yml b/.buildkite/pipelines/hourly.yml index 0dc8ad3e08d08..89541023be8e2 100644 --- a/.buildkite/pipelines/hourly.yml +++ b/.buildkite/pipelines/hourly.yml @@ -1,3 +1,5 @@ +env: + REPORT_FAILED_TESTS_TO_GITHUB: 'true' steps: - command: .buildkite/scripts/lifecycle/pre_build.sh label: Pre-Build @@ -17,7 +19,7 @@ steps: agents: queue: ci-group-6 depends_on: build - timeout_in_minutes: 120 + timeout_in_minutes: 150 key: default-cigroup retry: automatic: @@ -118,14 +120,14 @@ steps: - command: .buildkite/scripts/steps/test/jest_integration.sh label: 'Jest Integration Tests' agents: - queue: jest + queue: n2-4 timeout_in_minutes: 120 key: jest-integration - command: .buildkite/scripts/steps/test/api_integration.sh label: 'API Integration Tests' agents: - queue: jest + queue: n2-2 timeout_in_minutes: 120 key: api-integration diff --git a/.buildkite/scripts/lifecycle/post_command.sh b/.buildkite/scripts/lifecycle/post_command.sh index 14391fdd1e698..23f44a586e978 100755 --- a/.buildkite/scripts/lifecycle/post_command.sh +++ b/.buildkite/scripts/lifecycle/post_command.sh @@ -22,6 +22,5 @@ if [[ "$IS_TEST_EXECUTION_STEP" == "true" ]]; then buildkite-agent artifact upload 'x-pack/test/functional/failure_debug/html/*.html' buildkite-agent artifact upload '.es/**/*.hprof' - # TODO - re-enable when Jenkins is disabled - # node scripts/report_failed_tests --build-url="${BUILDKITE_BUILD_URL}#${BUILDKITE_JOB_ID}" 'target/junit/**/*.xml' + node scripts/report_failed_tests --build-url="${BUILDKITE_BUILD_URL}#${BUILDKITE_JOB_ID}" 'target/junit/**/*.xml' fi diff --git a/.buildkite/scripts/steps/storybooks/build_and_upload.js b/.buildkite/scripts/steps/storybooks/build_and_upload.js index 9d72f518837e9..49e36d2126cd4 100644 --- a/.buildkite/scripts/steps/storybooks/build_and_upload.js +++ b/.buildkite/scripts/steps/storybooks/build_and_upload.js @@ -6,13 +6,21 @@ const path = require('path'); const STORYBOOKS = [ 'apm', 'canvas', + 'codeeditor', 'ci_composite', 'url_template_editor', - 'codeeditor', 'dashboard', 'dashboard_enhanced', 'data_enhanced', 'embeddable', + 'expression_error', + 'expression_image', + 'expression_metric', + 'expression_repeat_image', + 'expression_reveal_image', + 'expression_shape', + 'expression_tagcloud', + 'fleet', 'infra', 'security_solution', 'ui_actions_enhanced', diff --git a/.buildkite/scripts/steps/test/jest_integration.sh b/.buildkite/scripts/steps/test/jest_integration.sh index 9f0228fd910bf..458651df2df2a 100755 --- a/.buildkite/scripts/steps/test/jest_integration.sh +++ b/.buildkite/scripts/steps/test/jest_integration.sh @@ -10,4 +10,4 @@ is_test_execution_step echo '--- Jest Integration Tests' checks-reporter-with-killswitch "Jest Integration Tests" \ - node scripts/jest_integration --ci --verbose + node --max-old-space-size=5120 scripts/jest_integration --ci diff --git a/.eslintrc.js b/.eslintrc.js index 30bc9d7322673..83afc27263248 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1502,7 +1502,7 @@ module.exports = { * TSVB overrides */ { - files: ['src/plugins/vis_type_timeseries/**/*.{js,mjs,ts,tsx}'], + files: ['src/plugins/vis_types/timeseries/**/*.{js,mjs,ts,tsx}'], rules: { 'import/no-default-export': 'error', }, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7831981569225..4c9df7e094ee6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -30,7 +30,7 @@ /src/plugins/vis_types/table/ @elastic/kibana-vis-editors /src/plugins/vis_types/tagcloud/ @elastic/kibana-vis-editors /src/plugins/vis_types/timelion/ @elastic/kibana-vis-editors -/src/plugins/vis_type_timeseries/ @elastic/kibana-vis-editors +/src/plugins/vis_types/timeseries/ @elastic/kibana-vis-editors /src/plugins/vis_types/vega/ @elastic/kibana-vis-editors /src/plugins/vis_types/vislib/ @elastic/kibana-vis-editors /src/plugins/vis_types/xy/ @elastic/kibana-vis-editors @@ -56,6 +56,7 @@ /examples/url_generators_examples/ @elastic/kibana-app-services /examples/url_generators_explorer/ @elastic/kibana-app-services /examples/field_formats_example/ @elastic/kibana-app-services +/examples/partial_results_example/ @elastic/kibana-app-services /packages/elastic-datemath/ @elastic/kibana-app-services /packages/kbn-interpreter/ @elastic/kibana-app-services /src/plugins/bfetch/ @elastic/kibana-app-services diff --git a/.i18nrc.json b/.i18nrc.json index 90afa274c6e6d..4107772e421ca 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -63,7 +63,7 @@ "visTypeMetric": "src/plugins/vis_types/metric", "visTypeTable": "src/plugins/vis_types/table", "visTypeTagCloud": "src/plugins/vis_types/tagcloud", - "visTypeTimeseries": "src/plugins/vis_type_timeseries", + "visTypeTimeseries": "src/plugins/vis_types/timeseries", "visTypeVega": "src/plugins/vis_types/vega", "visTypeVislib": "src/plugins/vis_types/vislib", "visTypeXy": "src/plugins/vis_types/xy", diff --git a/Jenkinsfile b/Jenkinsfile index db5ae306e6e2e..7dd3d0f41d27a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,10 @@ #!/bin/groovy +if (!env.ghprbPullId) { + print "Non-PR builds are now in Buildkite." + return +} + library 'kibana-pipeline-library' kibanaLibrary.load() diff --git a/api_docs/data.json b/api_docs/data.json index e62ddb5e30f12..3012f68b4c0ff 100644 --- a/api_docs/data.json +++ b/api_docs/data.json @@ -2716,19 +2716,19 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "reporting", @@ -2924,11 +2924,11 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "osquery", @@ -3076,35 +3076,35 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" }, { "plugin": "discover", @@ -4972,15 +4972,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "inputControlVis", @@ -5144,15 +5144,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "discover", @@ -5176,15 +5176,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "discover", @@ -6581,27 +6581,27 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "discover", @@ -6874,51 +6874,51 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/types.ts" + "path": "src/plugins/vis_types/timeseries/server/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/types.ts" + "path": "src/plugins/vis_types/timeseries/server/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "maps", @@ -6946,39 +6946,39 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/plugin.ts" + "path": "src/plugins/vis_types/timeseries/server/plugin.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/plugin.ts" + "path": "src/plugins/vis_types/timeseries/server/plugin.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "discover", @@ -6990,27 +6990,27 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "discover", @@ -14937,11 +14937,11 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts" } ], "initialIsOpen": false @@ -16879,11 +16879,11 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "securitySolution", @@ -24265,35 +24265,35 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/lib/fetch_fields.ts" + "path": "src/plugins/vis_types/timeseries/public/application/lib/fetch_fields.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/query_bar_wrapper.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/annotation_row.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/metrics_type.ts" + "path": "src/plugins/vis_types/timeseries/public/metrics_type.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx" }, { "plugin": "visTypeVega", @@ -24483,7 +24483,7 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/plugin.ts" + "path": "src/plugins/vis_types/timeseries/public/plugin.ts" }, { "plugin": "visTypeMetric", @@ -25018,19 +25018,19 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "reporting", @@ -25226,11 +25226,11 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "osquery", @@ -25378,35 +25378,35 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" }, { "plugin": "discover", @@ -27274,15 +27274,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "inputControlVis", @@ -27446,15 +27446,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "discover", @@ -27478,15 +27478,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "discover", @@ -28883,27 +28883,27 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "discover", @@ -29176,51 +29176,51 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/types.ts" + "path": "src/plugins/vis_types/timeseries/server/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/types.ts" + "path": "src/plugins/vis_types/timeseries/server/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "maps", @@ -29248,39 +29248,39 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/plugin.ts" + "path": "src/plugins/vis_types/timeseries/server/plugin.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/plugin.ts" + "path": "src/plugins/vis_types/timeseries/server/plugin.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "discover", @@ -29292,27 +29292,27 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "discover", @@ -29373,51 +29373,51 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/types.ts" + "path": "src/plugins/vis_types/timeseries/server/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/types.ts" + "path": "src/plugins/vis_types/timeseries/server/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "maps", @@ -29445,39 +29445,39 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/plugin.ts" + "path": "src/plugins/vis_types/timeseries/server/plugin.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/plugin.ts" + "path": "src/plugins/vis_types/timeseries/server/plugin.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "discover", @@ -29489,27 +29489,27 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "discover", @@ -30753,11 +30753,11 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts" } ], "initialIsOpen": false @@ -32456,11 +32456,11 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "securitySolution", @@ -37439,11 +37439,11 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts" } ], "initialIsOpen": false @@ -39172,11 +39172,11 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "securitySolution", diff --git a/api_docs/data_index_patterns.json b/api_docs/data_index_patterns.json index cf621b2413975..3ebbf2429948a 100644 --- a/api_docs/data_index_patterns.json +++ b/api_docs/data_index_patterns.json @@ -1111,7 +1111,7 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "graph", @@ -1147,7 +1147,7 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/lib/fetch_fields.ts" + "path": "src/plugins/vis_types/timeseries/public/application/lib/fetch_fields.ts" } ], "children": [], @@ -3639,19 +3639,19 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "reporting", @@ -3847,11 +3847,11 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/types/index.ts" + "path": "src/plugins/vis_types/timeseries/common/types/index.ts" }, { "plugin": "osquery", @@ -3999,35 +3999,35 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx" }, { "plugin": "discover", @@ -5895,15 +5895,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts" }, { "plugin": "inputControlVis", @@ -6067,15 +6067,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "discover", @@ -6099,15 +6099,15 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" + "path": "src/plugins/vis_types/timeseries/target/types/public/application/components/lib/convert_series_to_datatable.d.ts" }, { "plugin": "discover", @@ -7504,27 +7504,27 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts" }, { "plugin": "discover", @@ -7797,51 +7797,51 @@ "references": [ { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/types.ts" + "path": "src/plugins/vis_types/timeseries/server/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/types.ts" + "path": "src/plugins/vis_types/timeseries/server/types.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts" }, { "plugin": "maps", @@ -7869,39 +7869,39 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/plugin.ts" + "path": "src/plugins/vis_types/timeseries/server/plugin.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/plugin.ts" + "path": "src/plugins/vis_types/timeseries/server/plugin.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts" + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts" }, { "plugin": "discover", @@ -7913,27 +7913,27 @@ }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" + "path": "src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx" }, { "plugin": "discover", diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 99f241e81384d..67a9e90c74606 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -926,24 +926,24 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/types.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/types.ts#:~:text=IndexPatternsService)+ 17 more | - | -| | [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern)+ 13 more | - | -| | [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField) | - | -| | [fetch_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/lib/fetch_fields.ts#:~:text=indexPatterns), [combo_box_select.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx#:~:text=indexPatterns), [query_bar_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/query_bar_wrapper.tsx#:~:text=indexPatterns), [annotation_row.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/annotation_row.tsx#:~:text=indexPatterns), [metrics_type.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/metrics_type.ts#:~:text=indexPatterns), [convert_series_to_datatable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts#:~:text=indexPatterns), [timeseries_visualization.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.tsx#:~:text=indexPatterns), [timeseries_visualization.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.tsx#:~:text=indexPatterns) | - | -| | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/plugin.ts#:~:text=fieldFormats) | - | -| | [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig) | 8.1 | -| | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=Filter) | 8.1 | -| | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=Filter) | 8.1 | -| | [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig) | 8.1 | -| | [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/types.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/types.ts#:~:text=IndexPatternsService)+ 17 more | - | -| | [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern)+ 13 more | - | -| | [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=getNonScriptedFields), [fetch_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/lib/fetch_fields.ts#:~:text=getNonScriptedFields) | 8.1 | -| | [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField) | - | -| | [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField) | - | -| | [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern)+ 13 more | - | -| | [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/types.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/types.ts#:~:text=IndexPatternsService)+ 44 more | - | -| | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/common/types/index.ts#:~:text=Filter) | 8.1 | -| | [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig) | 8.1 | +| | [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/types.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/types.ts#:~:text=IndexPatternsService)+ 17 more | - | +| | [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern)+ 13 more | - | +| | [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField) | - | +| | [fetch_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/lib/fetch_fields.ts#:~:text=indexPatterns), [combo_box_select.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx#:~:text=indexPatterns), [query_bar_wrapper.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx#:~:text=indexPatterns), [annotation_row.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx#:~:text=indexPatterns), [metrics_type.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/metrics_type.ts#:~:text=indexPatterns), [convert_series_to_datatable.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts#:~:text=indexPatterns), [timeseries_visualization.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx#:~:text=indexPatterns), [timeseries_visualization.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx#:~:text=indexPatterns) | - | +| | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/plugin.ts#:~:text=fieldFormats) | - | +| | [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig) | 8.1 | +| | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=Filter) | 8.1 | +| | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=Filter) | 8.1 | +| | [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig) | 8.1 | +| | [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/types.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/types.ts#:~:text=IndexPatternsService)+ 17 more | - | +| | [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern)+ 13 more | - | +| | [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=getNonScriptedFields), [fetch_fields.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/lib/fetch_fields.ts#:~:text=getNonScriptedFields) | 8.1 | +| | [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField) | - | +| | [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField), [convert_series_to_datatable.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts#:~:text=IndexPatternField) | - | +| | [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [cached_index_pattern_fetcher.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=IndexPattern), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern), [index_patterns_utils.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts#:~:text=IndexPattern)+ 13 more | - | +| | [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [abstract_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [default_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [cached_index_pattern_fetcher.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [rollup_search_strategy.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/types.ts#:~:text=IndexPatternsService), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/types.ts#:~:text=IndexPatternsService)+ 44 more | - | +| | [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=Filter), [index.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/common/types/index.ts#:~:text=Filter) | 8.1 | +| | [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig), [types.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts#:~:text=EsQueryConfig) | 8.1 | diff --git a/api_docs/vis_type_timeseries.json b/api_docs/vis_type_timeseries.json index 01b211e3da90b..885f037b00a25 100644 --- a/api_docs/vis_type_timeseries.json +++ b/api_docs/vis_type_timeseries.json @@ -24,7 +24,7 @@ ") => data is ", "SeriesData" ], - "path": "src/plugins/vis_type_timeseries/common/vis_data_utils.ts", + "path": "src/plugins/vis_types/timeseries/common/vis_data_utils.ts", "deprecated": false, "children": [ { @@ -37,7 +37,7 @@ "signature": [ "TimeseriesVisData" ], - "path": "src/plugins/vis_type_timeseries/common/vis_data_utils.ts", + "path": "src/plugins/vis_types/timeseries/common/vis_data_utils.ts", "deprecated": false, "isRequired": true } @@ -58,7 +58,7 @@ ") => data is ", "TableData" ], - "path": "src/plugins/vis_type_timeseries/common/vis_data_utils.ts", + "path": "src/plugins/vis_types/timeseries/common/vis_data_utils.ts", "deprecated": false, "children": [ { @@ -71,7 +71,7 @@ "signature": [ "TimeseriesVisData" ], - "path": "src/plugins/vis_type_timeseries/common/vis_data_utils.ts", + "path": "src/plugins/vis_types/timeseries/common/vis_data_utils.ts", "deprecated": false, "isRequired": true } @@ -95,7 +95,7 @@ " | ", "TableData" ], - "path": "src/plugins/vis_type_timeseries/common/types/vis_data.ts", + "path": "src/plugins/vis_types/timeseries/common/types/vis_data.ts", "deprecated": false, "initialIsOpen": false } @@ -108,7 +108,7 @@ "tags": [], "label": "VisTypeTimeseriesSetup", "description": [], - "path": "src/plugins/vis_type_timeseries/server/plugin.ts", + "path": "src/plugins/vis_types/timeseries/server/plugin.ts", "deprecated": false, "children": [ { @@ -133,7 +133,7 @@ "TimeseriesVisData", ">" ], - "path": "src/plugins/vis_type_timeseries/server/plugin.ts", + "path": "src/plugins/vis_types/timeseries/server/plugin.ts", "deprecated": false, "children": [ { @@ -146,7 +146,7 @@ "signature": [ "DataRequestHandlerContext" ], - "path": "src/plugins/vis_type_timeseries/server/plugin.ts", + "path": "src/plugins/vis_types/timeseries/server/plugin.ts", "deprecated": false, "isRequired": true }, @@ -167,7 +167,7 @@ }, "" ], - "path": "src/plugins/vis_type_timeseries/server/plugin.ts", + "path": "src/plugins/vis_types/timeseries/server/plugin.ts", "deprecated": false, "isRequired": true }, @@ -181,7 +181,7 @@ "signature": [ "any" ], - "path": "src/plugins/vis_type_timeseries/server/plugin.ts", + "path": "src/plugins/vis_types/timeseries/server/plugin.ts", "deprecated": false, "isRequired": true } diff --git a/dev_docs/key_concepts/persistable_state.mdx b/dev_docs/key_concepts/persistable_state.mdx new file mode 100644 index 0000000000000..4368417170eed --- /dev/null +++ b/dev_docs/key_concepts/persistable_state.mdx @@ -0,0 +1,83 @@ +--- +id: kibDevDocsPersistableStateIntro +slug: /kibana-dev-docs/persistable-state-intro +title: Persistable State +summary: Persitable state is a key concept to understand when building a Kibana plugin. +date: 2021-02-02 +tags: ['kibana','dev', 'contributor', 'api docs'] +--- + + “Persistable state” is developer-defined state that supports being persisted by a plugin other than the one defining it. Persistable State needs to be serializable and the owner can/should provide utilities to migrate it, extract and inject any it may contain, as well as telemetry collection utilities. + +## Exposing state that can be persisted + +Any plugin that exposes state that another plugin might persist should implement interface on their `setup` contract. This will allow plugins persisting the state to easily access migrations and other utilities. + +Example: Data plugin allows you to generate filters. Those filters can be persisted by applications in their saved +objects or in the URL. In order to allow apps to migrate the filters in case the structure changes in the future, the Data plugin implements `PersistableStateService` on . + +note: There is currently no obvious way for a plugin to know which state is safe to persist. The developer must manually look for a matching `PersistableStateService`, or ad-hoc provided migration utilities (as is the case with Rule Type Parameters). +In the future, we hope to make it easier for producers of state to understand when they need to write a migration with changes, and also make it easier for consumers of such state, to understand whether it is safe to persist. + +## Exposing state that can be persisted but is not owned by plugin exposing it (registry) + +Any plugin that owns collection of items (registry) whose state/configuration can be persisted should implement `PersistableStateService` +interface on their `setup` contract and each item in the collection should implement interface. + +Example: Embeddable plugin owns the registry of embeddable factories to which other plugins can register new embeddable factories. Dashboard plugin +stores a bunch of embeddable panels input in its saved object and URL. Embeddable plugin setup contract implements `PersistableStateService` +interface and each `EmbeddableFactory` needs to implement `PersistableStateDefinition` interface. + +Embeddable plugin exposes this interfaces: +``` +// EmbeddableInput implements Serializable + +export interface EmbeddableRegistryDefinition extends PersistableStateDefinition { + id: string; + ... +} + +export interface EmbeddableSetup extends PersistableStateService; +``` + +Note: if your plugin doesn't expose the state (it is the only one storing state), the plugin doesn't need to implement the `PersistableStateService` interface. +If the state your plugin is storing can be provided by other plugins (your plugin owns a registry) items in that registry still need to implement `PersistableStateDefinition` interface. + +## Storing persistable state as part of saved object + +Any plugin that stores any persistable state as part of their saved object should make sure that its saved object migration +and reference extraction and injection methods correctly use the matching `PersistableStateService` implementation for the state they are storing. + +Take a look at [example saved object](https://github.com/elastic/kibana/blob/master/examples/embeddable_examples/server/searchable_list_saved_object.ts#L32) which stores an embeddable state. Note how the `migrations`, `extractReferences` and `injectReferences` are defined. + +## Storing persistable state as part of URL + +When storing persistable state as part of URL you must make sure your URL is versioned. When loading the state `migrateToLatest` method +of `PersistableStateService` should be called, which will migrate the state from its original version to latest. + +note: Currently there is no recommended way on how to store version in url and its up to every application to decide on how to implement that. + +## Available state operations + +### Extraction/Injection of References + +In order to support import and export, and space-sharing capabilities, Saved Objects need to explicitly list any references they contain to other Saved Objects. +To support persisting your state in saved objects owned by another plugin, the and methods of Persistable State interface should be implemented. + + + +[See example embeddable providing extract/inject functions](https://github.com/elastic/kibana/blob/master/examples/embeddable_examples/public/migrations/migrations_embeddable_factory.ts) + +### Migrations and Backward compatibility + +As your plugin evolves, you may need to change your state in a breaking way. If that happens, you should write a migration to upgrade the state that existed prior to the change. + +. + +[See an example saved object storing embeddable state implementing saved object migration function](https://github.com/elastic/kibana/blob/master/examples/embeddable_examples/server/searchable_list_saved_object.ts) + +[See example embeddable providing migration functions](https://github.com/elastic/kibana/blob/master/examples/embeddable_examples/public/migrations/migrations_embeddable_factory.ts) + +## Telemetry + +You might want to collect statistics about how your state is used. If that is the case you should implement the telemetry method of Persistable State interface. diff --git a/docs/api/machine-learning.asciidoc b/docs/api/machine-learning.asciidoc new file mode 100644 index 0000000000000..265896e6340df --- /dev/null +++ b/docs/api/machine-learning.asciidoc @@ -0,0 +1,11 @@ +[[machine-learning-api]] +== {ml-cap} APIs + +//Manage {kib} saved objects, including dashboards, visualizations, and more. + +The following {ml} API is available: + +* <> +//to retrieve a single {kib} saved object by ID + +include::machine-learning/sync.asciidoc[] diff --git a/docs/api/machine-learning/sync.asciidoc b/docs/api/machine-learning/sync.asciidoc new file mode 100644 index 0000000000000..5f19bc17ab2fb --- /dev/null +++ b/docs/api/machine-learning/sync.asciidoc @@ -0,0 +1,79 @@ +[[machine-learning-api-sync]] +=== Sync {ml} saved objects API +++++ +Sync {ml} saved objects +++++ + +Synchronizes {kib} saved objects for {ml} jobs. + +[[machine-learning-api-sync-request]] +==== Request + +`GET :/api/ml/saved_objects/sync` + +`GET :/s//api/ml/saved_objects/sync` + + +[[machine-learning-api-sync-path-params]] +==== Path parameters + +`space_id`:: +(Optional, string) An identifier for the space. If `space_id` is not provided in +the URL the default space is used. + +[[machine-learning-api-sync-query-params]] +==== Query parameters + +`simulate`:: +(Optional, boolean) When `true`, simulates the synchronization by only returning +the list actions that _would_ be performed. + +[[machine-learning-api-sync-response-body]] +==== Response body + +`datafeedsAdded`:: +(array) If a saved object for an {anomaly-job} is missing a {dfeed} identifier, +it is added. This list contains the {dfeed} identifiers and indicates whether +the synchronization was successful. + +`datafeedsRemoved`:: +(array) If saved objects exist for {dfeeds} that no longer exist, they are +deleted. This list contains the {dfeed} identifiers and indicates whether the +synchronization was successful. + +`savedObjectsCreated`:: +(array) If saved objects are missing for {ml} jobs, they are created. This +list contains the job identifiers and indicates whether the synchronization was +successful. + +`savedObjectsDeleted`:: +(array) If saved objects exist for jobs that no longer exist, they are deleted. +This list contains the job identifiers and indicates whether the synchronization +was successful. + +[[machine-learning-api-sync-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[machine-learning-api-sync-example]] +==== Example + +Retrieve the list of {ml} saved objects that require synchronization: + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/ml/saved_objects/sync?simulate=true +-------------------------------------------------- +// KIBANA + +If there are two jobs and a {dfeed} that need to be synchronized, for example, +the API returns the following: + +[source,sh] +-------------------------------------------------- +{{"savedObjectsCreated":{"myjob1":{"success":true},"myjob2":{"success":true}},"savedObjectsDeleted":{},"datafeedsAdded":{},"datafeedsRemoved":{"myfeed3":{"success":true}}} +-------------------------------------------------- + +To perform the synchronization, re-run the API and omit the `simulate` parameter. \ No newline at end of file diff --git a/docs/apm/dependencies.asciidoc b/docs/apm/dependencies.asciidoc new file mode 100644 index 0000000000000..b3afdc4880df5 --- /dev/null +++ b/docs/apm/dependencies.asciidoc @@ -0,0 +1,32 @@ +[role="xpack"] +[[dependencies]] +=== Dependencies + +APM agents collect details about external calls made from instrumented services. +Sometimes, these external calls resolve into a downstream service that's instrumented -- in these cases, +you can utilize <> to drill down into problematic downstream services. +Other times, though, it's not possible to instrument a downstream dependency -- +like with a database or third-party service. +**Dependencies** gives you a window into these uninstrumented, downstream dependencies. + +[role="screenshot"] +image::apm/images/dependencies.png[Dependencies view in the APM app in Kibana] + +Many application issues are caused by slow or unresponsive downstream dependencies. +And because a single, slow dependency can significantly impact the end-user experience, +it's important to be able to quickly identify these problems and determine the root cause. + +Select a dependency to see detailed latency, throughput, and failed transaction rate metrics. + +[role="screenshot"] +image::apm/images/dependencies-drilldown.png[Dependencies drilldown view in the APM app in Kibana] + +When viewing a dependency, consider your pattern of usage with that dependency. +If your usage pattern _hasn't_ increased or decreased, +but the experience has been negatively effected -- either with an increase in latency or errors, +there's likely a problem with the dependency that needs to be addressed. + +If your usage pattern _has_ changed, the dependency view can quickly show you whether +that pattern change exists in all upstream services, or just a subset of your services. +You might then start digging into traces coming from +impacted services to determine why that pattern change has occurred. diff --git a/docs/apm/errors.asciidoc b/docs/apm/errors.asciidoc index c468d7f0235b2..d8fc75bf50340 100644 --- a/docs/apm/errors.asciidoc +++ b/docs/apm/errors.asciidoc @@ -4,19 +4,21 @@ TIP: {apm-overview-ref-v}/errors.html[Errors] are groups of exceptions with a similar exception or log message. -The *Errors* overview provides a high-level view of the error message and culprit, -the number of occurrences, and the most recent occurrence. -Just like the transaction overview, you'll notice we group together like errors. -This makes it very easy to quickly see which errors are affecting your services, +The *Errors* overview provides a high-level view of the exceptions that APM agents catch, +or that users manually report with APM agent APIs. +Like errors are grouped together to make it easy to quickly see which errors are affecting your services, and to take actions to rectify them. +A service returning a 5xx code from a request handler, controller, etc., will not create +an exception that an APM agent can catch, and will therefore not show up in this view. + [role="screenshot"] -image::apm/images/apm-errors-overview.png[Example view of the errors overview in the APM app in Kibana] +image::apm/images/apm-errors-overview.png[APM Errors overview] Selecting an error group ID or error message brings you to the *Error group*. [role="screenshot"] -image::apm/images/apm-error-group.png[Example view of the error group page in the APM app in Kibana] +image::apm/images/apm-error-group.png[APM Error group] Here, you'll see the error message, culprit, and the number of occurrences over time. diff --git a/docs/apm/getting-started.asciidoc b/docs/apm/getting-started.asciidoc index e448c0beb8b99..6b205d0274262 100644 --- a/docs/apm/getting-started.asciidoc +++ b/docs/apm/getting-started.asciidoc @@ -29,6 +29,7 @@ start with: * <> * <> +* <> * <> Notice something awry? Select a service or trace and dive deeper with: @@ -46,6 +47,8 @@ include::services.asciidoc[] include::traces.asciidoc[] +include::dependencies.asciidoc[] + include::service-maps.asciidoc[] include::service-overview.asciidoc[] diff --git a/docs/apm/images/all-instances.png b/docs/apm/images/all-instances.png index e77c8af2c46f6..70028b5a9b58b 100644 Binary files a/docs/apm/images/all-instances.png and b/docs/apm/images/all-instances.png differ diff --git a/docs/apm/images/apm-distributed-tracing.png b/docs/apm/images/apm-distributed-tracing.png index 0dbffa591d43a..4d1b8cde20e95 100644 Binary files a/docs/apm/images/apm-distributed-tracing.png and b/docs/apm/images/apm-distributed-tracing.png differ diff --git a/docs/apm/images/apm-geo-ui.png b/docs/apm/images/apm-geo-ui.png index 5bbe713c908a4..69c1390a27989 100644 Binary files a/docs/apm/images/apm-geo-ui.png and b/docs/apm/images/apm-geo-ui.png differ diff --git a/docs/apm/images/apm-logs-tab.png b/docs/apm/images/apm-logs-tab.png index 891d2b7a1dd69..c79be8b5eb0b7 100644 Binary files a/docs/apm/images/apm-logs-tab.png and b/docs/apm/images/apm-logs-tab.png differ diff --git a/docs/apm/images/apm-services-overview.png b/docs/apm/images/apm-services-overview.png index 7aeb5f1ac379f..271c0347aa53e 100644 Binary files a/docs/apm/images/apm-services-overview.png and b/docs/apm/images/apm-services-overview.png differ diff --git a/docs/apm/images/apm-span-detail.png b/docs/apm/images/apm-span-detail.png index c9f55575b2232..d0b6a4de3d3df 100644 Binary files a/docs/apm/images/apm-span-detail.png and b/docs/apm/images/apm-span-detail.png differ diff --git a/docs/apm/images/apm-transaction-duration-dist.png b/docs/apm/images/apm-transaction-duration-dist.png index 91ae6c3a59ad2..9c7ab5dd67dc0 100644 Binary files a/docs/apm/images/apm-transaction-duration-dist.png and b/docs/apm/images/apm-transaction-duration-dist.png differ diff --git a/docs/apm/images/apm-transaction-sample.png b/docs/apm/images/apm-transaction-sample.png index 54eea902f0311..a9490fc20d853 100644 Binary files a/docs/apm/images/apm-transaction-sample.png and b/docs/apm/images/apm-transaction-sample.png differ diff --git a/docs/apm/images/apm-transactions-overview.png b/docs/apm/images/apm-transactions-overview.png index 66cf739a861b7..34cd0219b895d 100644 Binary files a/docs/apm/images/apm-transactions-overview.png and b/docs/apm/images/apm-transactions-overview.png differ diff --git a/docs/apm/images/apm-transactions-table.png b/docs/apm/images/apm-transactions-table.png index b573adfb0c450..8a3415bc9a9f1 100644 Binary files a/docs/apm/images/apm-transactions-table.png and b/docs/apm/images/apm-transactions-table.png differ diff --git a/docs/apm/images/dependencies-drilldown.png b/docs/apm/images/dependencies-drilldown.png new file mode 100644 index 0000000000000..4c491c1ffa254 Binary files /dev/null and b/docs/apm/images/dependencies-drilldown.png differ diff --git a/docs/apm/images/dependencies.png b/docs/apm/images/dependencies.png new file mode 100644 index 0000000000000..260025d31654b Binary files /dev/null and b/docs/apm/images/dependencies.png differ diff --git a/docs/apm/images/error-rate.png b/docs/apm/images/error-rate.png index 036c7a08302bd..845fa2af07de1 100644 Binary files a/docs/apm/images/error-rate.png and b/docs/apm/images/error-rate.png differ diff --git a/docs/apm/images/spans-dependencies.png b/docs/apm/images/spans-dependencies.png index d6e26a5061a6e..558099dd450c1 100644 Binary files a/docs/apm/images/spans-dependencies.png and b/docs/apm/images/spans-dependencies.png differ diff --git a/docs/apm/index.asciidoc b/docs/apm/index.asciidoc index f4d35a2d554ba..385d9921ae2b0 100644 --- a/docs/apm/index.asciidoc +++ b/docs/apm/index.asciidoc @@ -4,8 +4,7 @@ [partintro] -- -The APM app in {kib} is provided with the basic license. -It allows you to monitor your software services and applications in real-time; +The APM app in {kib} allows you to monitor your software services and applications in real-time; visualize detailed performance information on your services, identify and analyze errors, and monitor host-level and agent-specific metrics like JVM and Go runtime metrics. diff --git a/docs/apm/service-overview.asciidoc b/docs/apm/service-overview.asciidoc index f1096a4e43bbc..05537cef58c98 100644 --- a/docs/apm/service-overview.asciidoc +++ b/docs/apm/service-overview.asciidoc @@ -69,34 +69,43 @@ image::apm/images/traffic-transactions.png[Traffic and transactions] [discrete] [[service-error-rates]] -=== Error rate and errors +=== Failed transaction rate and errors -The *Error rate* chart displays the average error rates relating to the service, within a specific time range. -An HTTP response code greater than 400 does not necessarily indicate a failed transaction. -<>. +The failed transaction rate represents the percentage of failed transactions from the perspective of the selected service. +It's useful for visualizing unexpected increases, decreases, or irregular patterns in a service's transactions. ++ +[TIP] +==== +HTTP **transactions** from the HTTP server perspective do not consider a `4xx` status code (client error) as a failure +because the failure was caused by the caller, not the HTTP server. Thus, `event.outcome=success` and there will be no increase in failed transaction rate. + +HTTP **spans** from the client perspective however, are considered failures if the HTTP status code is ≥ 400. +These spans will set `event.outcome=failure` and increase the failed transaction rate. + +If there is no HTTP status, both transactions and spans are considered successful unless an error is reported. +==== The *Errors* table provides a high-level view of each error message when it first and last occurred, along with the total number of occurrences. This makes it very easy to quickly see which errors affect your services and take actions to rectify them. To do so, click *View errors*. [role="screenshot"] -image::apm/images/error-rate.png[Error rate and errors] +image::apm/images/error-rate.png[failed transaction rate and errors] [discrete] [[service-span-duration]] === Span types average duration and dependencies -The *Average duration by span type* chart visualizes each span type's average duration and helps you determine +The *Time spent by span type* chart visualizes each span type's average duration and helps you determine which spans could be slowing down transactions. The "app" label displayed under the chart indicates that something was happening within the application. This could signal that the agent does not have auto-instrumentation for whatever was happening during that time or that the time was spent in the application code and not in database or external requests. The *Dependencies* table displays a list of downstream services or external connections relevant -to the service at the selected time range. The table displays latency, traffic, error rate, and the impact of +to the service at the selected time range. The table displays latency, throughput, failed transaction rate, and the impact of each dependency. By default, dependencies are sorted by _Impact_ to show the most used and the slowest dependency. -If there is a particular dependency you are interested in, click *View service map* to view the related -<>. +If there is a particular dependency you are interested in, click *<>* to learn more about it. NOTE: Displaying dependencies for services instrumented with the Real User Monitoring (RUM) agent requires an agent version ≥ v5.6.3. @@ -106,11 +115,11 @@ image::apm/images/spans-dependencies.png[Span type duration and dependencies] [discrete] [[service-instances]] -=== All instances +=== Instances -The *All instances* table displays a list of all the available service instances within the selected time range. -Depending on how the service runs, the instance could be a host or a container. The table displays latency, traffic, -errors, CPU usage, and memory usage for each instance. By default, instances are sorted by _Throughput_. +The *Instances* table displays a list of all the available service instances within the selected time range. +Depending on how the service runs, the instance could be a host or a container. The table displays latency, throughput, +failed transaction, CPU usage, and memory usage for each instance. By default, instances are sorted by _Throughput_. [role="screenshot"] image::apm/images/all-instances.png[All instances] diff --git a/docs/apm/set-up.asciidoc b/docs/apm/set-up.asciidoc index b2e78bd08bc93..3cbe45ec913b7 100644 --- a/docs/apm/set-up.asciidoc +++ b/docs/apm/set-up.asciidoc @@ -8,7 +8,7 @@ APM is available via the navigation sidebar in {Kib}. If you have not already installed and configured Elastic APM, -the *Setup Instructions* in Kibana will get you started. +the *Add data* page will get you started. [role="screenshot"] image::apm/images/apm-setup.png[Installation instructions on the APM page in Kibana] @@ -17,10 +17,9 @@ image::apm/images/apm-setup.png[Installation instructions on the APM page in Kib [[apm-configure-index-pattern]] === Load the index pattern -Index patterns tell Kibana which Elasticsearch indices you want to explore. +Index patterns tell {kib} which {es} indices you want to explore. An APM index pattern is necessary for certain features in the APM app, like the query bar. -To set up the correct index pattern, -simply click *Load Kibana objects* at the bottom of the Setup Instructions. +To set up the correct index pattern, on the *Add data* page, click *Load Kibana objects*. [role="screenshot"] image::apm/images/apm-index-pattern.png[Setup index pattern for APM in Kibana] diff --git a/docs/apm/transactions.asciidoc b/docs/apm/transactions.asciidoc index 76006d375d075..c0850e4e9d507 100644 --- a/docs/apm/transactions.asciidoc +++ b/docs/apm/transactions.asciidoc @@ -8,7 +8,7 @@ APM agents automatically collect performance metrics on HTTP requests, database [role="screenshot"] image::apm/images/apm-transactions-overview.png[Example view of transactions table in the APM app in Kibana] -The *Latency*, *transactions per minute*, *Error rate*, and *Average duration by span type* +The *Latency*, *transactions per minute*, *Failed transaction rate*, and *Average duration by span type* charts display information on all transactions associated with the selected service: *Latency*:: @@ -23,17 +23,17 @@ Useful for determining if more responses than usual are being served with a part Like in the latency graph, you can zoom in on anomalies to further investigate them. [[transaction-error-rate]] -*Error rate*:: -The error rate represents the percentage of failed transactions from the perspective of the selected service. +*Failed transaction rate*:: +The failed transaction rate represents the percentage of failed transactions from the perspective of the selected service. It's useful for visualizing unexpected increases, decreases, or irregular patterns in a service's transactions. + [TIP] ==== HTTP **transactions** from the HTTP server perspective do not consider a `4xx` status code (client error) as a failure -because the failure was caused by the caller, not the HTTP server. Thus, there will be no increase in error rate. +because the failure was caused by the caller, not the HTTP server. Thus, `event.outcome=success` and there will be no increase in failed transaction rate. HTTP **spans** from the client perspective however, are considered failures if the HTTP status code is ≥ 400. -These spans will increase the error rate. +These spans will set `event.outcome=failure` and increase the failed transaction rate. If there is no HTTP status, both transactions and spans are considered successful unless an error is reported. ==== @@ -97,7 +97,7 @@ This page is visually similar to the transaction overview, but it shows data fro the selected transaction group. [role="screenshot"] -image::apm/images/apm-transaction-response-dist.png[Example view of response time distribution] +image::apm/images/apm-transactions-overview.png[Example view of response time distribution] [[transaction-duration-distribution]] ==== Latency distribution @@ -110,10 +110,10 @@ It's the requests on the right, the ones taking longer than average, that we pro [role="screenshot"] image::apm/images/apm-transaction-duration-dist.png[Example view of latency distribution graph] -Select a latency duration _bucket_ to display up to ten trace samples. +Click and drag to select a latency duration _bucket_ to display up to 500 trace samples. [[transaction-trace-sample]] -==== Trace sample +==== Trace samples Trace samples are based on the _bucket_ selection in the *Latency distribution* chart; update the samples by selecting a new _bucket_. @@ -167,4 +167,11 @@ and solve problems. [role="screenshot"] image::apm/images/apm-logs-tab.png[APM logs tab] -// To do: link to log correlation +[[transaction-latency-correlations]] +==== Correlations + +Correlations surface attributes of your data that are potentially correlated with high-latency or erroneous transactions. +To learn more, see <>. + +[role="screenshot"] +image::apm/images/correlations-hover.png[APM lattency correlations] diff --git a/docs/dev-tools/console/console.asciidoc b/docs/dev-tools/console/console.asciidoc index e1cd156e6a9e4..f29ddb1a600db 100644 --- a/docs/dev-tools/console/console.asciidoc +++ b/docs/dev-tools/console/console.asciidoc @@ -134,6 +134,7 @@ shortcuts, click *Help*. [[console-settings]] === Disable Console +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] If you don’t want to use *Console*, you can disable it by setting `console.enabled` to `false` in your `kibana.yml` configuration file. Changing this setting causes the server to regenerate assets on the next startup, diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 850b80c20e09f..edc1821f3b223 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -44,6 +44,10 @@ as uiSettings within the code. |Console provides the user with tools for storing and executing requests against Elasticsearch. +|{kib-repo}blob/{branch}/src/plugins/custom_integrations/README.md[customIntegrations] +|Register add-data cards + + |<> |- Registers the dashboard application. - Adds a dashboard embeddable that can be used in other applications. @@ -297,7 +301,7 @@ The plugin exposes the static DefaultEditorController class to consume. |Contains the timelion visualization and the timelion backend. -|{kib-repo}blob/{branch}/src/plugins/vis_type_timeseries[visTypeTimeseries] +|{kib-repo}blob/{branch}/src/plugins/vis_types/timeseries[visTypeTimeseries] |WARNING: Missing README. diff --git a/docs/development/core/server/kibana-plugin-core-server.deprecationsservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.deprecationsservicesetup.md index 7b2cbdecd146a..2bc7f6cba594d 100644 --- a/docs/development/core/server/kibana-plugin-core-server.deprecationsservicesetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.deprecationsservicesetup.md @@ -27,6 +27,7 @@ async function getDeprecations({ esClient, savedObjectsClient }: GetDeprecations const deprecations: DeprecationsDetails[] = []; const count = await getFooCount(savedObjectsClient); if (count > 0) { + // Example of a manual correctiveAction deprecations.push({ title: i18n.translate('xpack.foo.deprecations.title', { defaultMessage: `Foo's are deprecated` diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.md index 8c42884eb0b31..2c3dd9f3f8434 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.md @@ -25,4 +25,5 @@ export interface SavedObjectsTypeManagementDefinition | [isExportable](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.isexportable.md) | SavedObjectsExportablePredicate<Attributes> | Optional hook to specify whether an object should be exportable.If specified, isExportable will be called during export for each of this type's objects in the export, and the ones not matching the predicate will be excluded from the export.When implementing both isExportable and onExport, it is mandatory that isExportable returns the same value for an object before and after going though the export transform. E.g isExportable(objectBeforeTransform) === isExportable(objectAfterTransform) | | [onExport](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.onexport.md) | SavedObjectsExportTransform<Attributes> | An optional export transform function that can be used transform the objects of the registered type during the export process.It can be used to either mutate the exported objects, or add additional objects (of any type) to the export list.See [the transform type documentation](./kibana-plugin-core-server.savedobjectsexporttransform.md) for more info and examples.When implementing both isExportable and onExport, it is mandatory that isExportable returns the same value for an object before and after going though the export transform. E.g isExportable(objectBeforeTransform) === isExportable(objectAfterTransform) | | [onImport](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.onimport.md) | SavedObjectsImportHook<Attributes> | An optional [import hook](./kibana-plugin-core-server.savedobjectsimporthook.md) to use when importing given type.Import hooks are executed during the savedObjects import process and allow to interact with the imported objects. See the [hook documentation](./kibana-plugin-core-server.savedobjectsimporthook.md) for more info. | +| [visibleInManagement](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.visibleinmanagement.md) | boolean | When set to false, the type will not be listed or searchable in the SO management section. Main usage of setting this property to false for a type is when objects from the type should be included in the export via references or export hooks, but should not directly appear in the SOM. Defaults to true. | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.visibleinmanagement.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.visibleinmanagement.md new file mode 100644 index 0000000000000..33ddc8e8c8307 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectstypemanagementdefinition.visibleinmanagement.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsTypeManagementDefinition](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.md) > [visibleInManagement](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.visibleinmanagement.md) + +## SavedObjectsTypeManagementDefinition.visibleInManagement property + +When set to false, the type will not be listed or searchable in the SO management section. Main usage of setting this property to false for a type is when objects from the type should be included in the export via references or export hooks, but should not directly appear in the SOM. Defaults to `true`. + +Signature: + +```typescript +visibleInManagement?: boolean; +``` + +## Remarks + +`importableAndExportable` must be `true` to specify this property. + diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 872fcbbf83385..6fd83e8af3d15 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -142,6 +142,9 @@ The default placeholder value to use in Fields that exist outside of `_source`. Kibana merges these fields into the document when displaying it. +[[metrics:allowStringIndices]]`metrics:allowStringIndices`:: +Enables you to use {es} indices in *TSVB* visualizations. + [[metrics-maxbuckets]]`metrics:max_buckets`:: Affects the *TSVB* histogram density. Must be set higher than `histogram:maxBars`. diff --git a/docs/osquery/images/enter-query.png b/docs/osquery/images/enter-query.png new file mode 100644 index 0000000000000..154d2dcad4857 Binary files /dev/null and b/docs/osquery/images/enter-query.png differ diff --git a/docs/osquery/images/live-queries-history.png b/docs/osquery/images/live-queries-history.png new file mode 100644 index 0000000000000..6f49917a685d6 Binary files /dev/null and b/docs/osquery/images/live-queries-history.png differ diff --git a/docs/osquery/images/live-query-check-results.png b/docs/osquery/images/live-query-check-results.png new file mode 100644 index 0000000000000..df292309e0853 Binary files /dev/null and b/docs/osquery/images/live-query-check-results.png differ diff --git a/docs/osquery/images/live-query-history.png b/docs/osquery/images/live-query-history.png new file mode 100644 index 0000000000000..97d9ccb1bda88 Binary files /dev/null and b/docs/osquery/images/live-query-history.png differ diff --git a/docs/osquery/images/play-icon.png b/docs/osquery/images/play-icon.png new file mode 100644 index 0000000000000..724d17b5a381d Binary files /dev/null and b/docs/osquery/images/play-icon.png differ diff --git a/docs/osquery/images/schedule-query.png b/docs/osquery/images/schedule-query.png new file mode 100644 index 0000000000000..51d83f2540aca Binary files /dev/null and b/docs/osquery/images/schedule-query.png differ diff --git a/docs/osquery/images/scheduled-query-groupds.png b/docs/osquery/images/scheduled-query-groupds.png new file mode 100644 index 0000000000000..bb7fd8ae87563 Binary files /dev/null and b/docs/osquery/images/scheduled-query-groupds.png differ diff --git a/docs/osquery/images/table-icon.png b/docs/osquery/images/table-icon.png new file mode 100644 index 0000000000000..5c4e9e78d9f09 Binary files /dev/null and b/docs/osquery/images/table-icon.png differ diff --git a/docs/osquery/osquery.asciidoc b/docs/osquery/osquery.asciidoc new file mode 100644 index 0000000000000..1e4e6604a7c70 --- /dev/null +++ b/docs/osquery/osquery.asciidoc @@ -0,0 +1,419 @@ +[chapter] +[role="xpack"] +[[osquery]] += Osquery + +https://osquery.io[Osquery] is an open source tool that lets you query operating systems, like a database, providing you with visibility into your infrastructure and operating systems. +Using basic SQL commands, you can ask questions about devices, such as servers, +Docker containers, and computers running Linux, macOS, or Windows. +The https://osquery.io/schema[extensive schema] helps with a variety of use cases, +including vulnerability detection, compliance monitoring, incident investigations, and more. + +With Osquery, you can: + + * Run live queries for one or more agents + * Schedule queries to capture changes to OS state over time + * View a history of past queries and their results + * Save queries and build a library of queries for specific use cases + +Osquery results are stored in {es}, so that you can +search, analyze, and visualize Osquery data in {kib}. + +Osquery is powered by the *Osquery Manager* integration. +For information on how to set up *Osquery Manager*, refer to <>. + +[float] +== Required privileges + +To use *Osquery Manager*, you must be assigned to a role with the following privileges: + +* `Read` privileges for the `logs-osquery_manager.result*` index. +* {kib} privileges for **Osquery Manager**. The `All` privilege +enables you to run, schedule, and save queries. `Read` enables you to +view live and scheduled query results, but you cannot run live queries or edit. + +[float] +[[osquery-run-query]] +== Run live queries + +To inspect a host or test queries you want to schedule, run a query against one or more agents or policies, +and view the results. + +. Open the main menu, and then click *Osquery*. + +. In the *Live queries* view, click **New live query**. + +. Select one or more agents or groups to query. Start typing in the search field, +and you'll get suggestions for agents by name, ID, platform, and policy. + +. Enter a query or select a query from your saved queries. ++ +[role="screenshot"] +image::images/enter-query.png[Select saved query dropdown name showing query name and description] + +. Click **Submit**. + +. Review the results in a table, or navigate to *Discover* to dive deeper into the response, +or to the drag-and-drop *Lens* editor to create visualizations. +. To view more information about the request, such as failures, open the *Status* tab. +. To optionally save the query for future use, click *Save for later* and define the ID, +description, and other +<>. + +To view a history of the past queries you have run, open the *Live queries history*. + +* To replay a query, click image:images/play-icon.png[Right-pointing triangle]. + +* To view the query <> and <>, +click image:images/table-icon.png[Table icon]. ++ +[role="screenshot"] +image::images/live-query-check-results.png[Results of OSquery] + + +[float] +[[osquery-schedule-query]] +== Schedule queries + +Group and schedule queries to run on a specified interval, in seconds. +For example, you might create a group that checks +for IT compliance-type issues, and +another group that monitors for evidence of malware. + +. Open the **Scheduled query groups** tab. + +. Click a group name to view the details. ++ +Details include the last time each query ran, how many results were returned, and the number of agents the query ran against. +If there are errors, expand the row to view the details. ++ +[role="screenshot"] +image::images/scheduled-query-groupds.png[Shows last results last time it ran, how many results returned, number of agents it ran against, if it is actually running and if there are errors] + +. To make changes, click *Edit*. + +.. To add a query to the group, click *Add query*, and then enter the query ID and interval. +Optionally, set the minimum Osquery version and platform, +or <>. + +.. To upload queries from a .conf query pack, drag the pack to the drop zone under the query table. To explore the community packs that Osquery publishes, click *Example packs*. + +. Click *Save query*. The queries run when the policy receives the update. + +. View scheduled history results in < or the drag-and-drop <> editor. + + +[float] +[[osquery-map-fields]] +== Map Osquery fields to ECS fields + +When you schedule queries, you can optionally map query results to fields in +the {ecs-ref}/ecs-reference.html[Elastic Common Schema] (ECS), +which standardizes your Osquery data for use across detections, machine learning, +and any other areas that rely on ECS-compliant data. +The query results include the original `osquery.` +and the mapped ECS field. For example, if you update a query to map `osquery.name` to `user.name`, the query results include both fields. + +. Edit a scheduled query group, and then click the edit icon for the query that you want to map. + +. In **ECS mapping**, select the Osquery result fields you want to map to ECS fields. ++ +The fields available in the **Osquery.results** column are based on the SQL query entered, +and only include fields that the query returns. + +When mapping fields: + +. To add a new row for additional fields to map, click the plus icon. + +. To remove any mapped rows, click the trash icon. + +. To save changes to the query, click *Save*. + +. To save changes to the group, click *Save query*. + + +[float] +[[osquery-manage-query]] +== Edit saved queries + +Add or edit saved queries to the *Saved queries* tab. + +. Go to the saved queries, then click **Add saved query** or the edit icon. +. Provide the following fields: + +* The unique identifier. + +* A brief description. + +* The SQL query. + +* The defaults for the scheduled query group, which is included when you add the query to a scheduled query group. + +** The frequency to run the query. + +** The minimum https://github.com/osquery/osquery/releases)[version of Osquery] required to run the query. + +** The operating system required to run the query. For information about supported platforms per table, click *OSquery schema* in the *Edit query* flyout. + +. Click **Save query**. + +[float] +[[osquery-status]] +== Osquery status + +A query can have the following status: + +[cols="2*<"] +|=== +| Successful | The query successfully completed. +| Failed | The query encountered a problem, such as an issue with the query or the agent was disconnected, and might have failed. +| Not yet responded | The query has not been sent to the agent. +| Expired | The action request timed out. The agent may be offline. +|=== + +NOTE: If an agent is offline, the request status remains **pending** as {kib} retries the request. +By default, a query request times out after five minutes. The time out applies to the time it takes +to deliver the action request to an agent to run a query. If the action completes after the timeout period, +the results are still returned. + + +[float] +[[osquery-results]] +== Osquery results + +For the fields that can be returned in Osquery results, +refer to https://docs.elastic.co/en/integrations/osquery_manager#exported-fields[exported fields]. +Scheduled Osquery +results can also include ECS fields, if the query has a defined ECS mapping. + +Osquery responses include the following information: + +* Everything prefaced with `osquery.` is part of the query response. These fields are not mapped to ECS. + +* By default, the `host.*` and `agent.*` fields are mapped to ECS. + +* The `action_data.query` has the query that was sent. + +* All query results are https://osquery.readthedocs.io/en/stable/deployment/logging/#snapshot-logs[snapshot logs] +that represent a point in time with a set of results, with no differentials. +https://osquery.readthedocs.io/en/stable/deployment/logging/#differential-logs[Differential logs] are unsupported. + +* Osquery data is stored in the `logs-osquery_manager.result-default` datastream, and the result row data is under the `osquery` property in the document. + +The following example shows a successful Osquery result: + + +```ts +{ + "_index": ".ds-logs-osquery_manager.result-default-2021.04.12-2021.04.12-000001", + "_id": "R3ZwxngBKwN-X8eyQbxy", + "_version": 1, + "_score": null, + "fields": { + "osquery.seconds": [ + "7" + ], + "action_data.id": [ + "72d3ec71-7635-461e-a15d-f728819ae27f" + ], + "osquery.seconds.number": [ + 7 + ], + "osquery.hours.number": [ + 6 + ], + "host.hostname": [ + "MacBook-Pro.local" + ], + "type": [ + "MacBook-Pro.local" + ], + "host.mac": [ + "ad:de:48:00:12:22", + "a6:83:e7:cb:91:ee" + ], + "osquery.total_seconds.number": [ + 1060627 + ], + "host.os.build": [ + "20D91" + ], + "host.ip": [ + "192.168.31.171", + "fe80::b5b1:39ff:faa1:3b39" + ], + "agent.type": [ + "osquerybeat" + ], + "action_data.query": [ + "select * from uptime;" + ], + "osquery.minutes": [ + "37" + ], + "action_id": [ + "5099c02d-bd6d-4b88-af90-d80dcdc945df" + ], + "host.os.version": [ + "10.16" + ], + "host.os.kernel": [ + "20.3.0" + ], + "host.os.name": [ + "Mac OS X" + ], + "agent.name": [ + "MacBook-Pro.local" + ], + "host.name": [ + "MacBook-Pro.local" + ], + "osquery.total_seconds": [ + "1060627" + ], + "host.id": [ + "155D977D-8EA8-5BDE-94A2-D78A7B545198" + ], + "osquery.hours": [ + "6" + ], + "osquery.days": [ + "12" + ], + "host.os.type": [ + "macos" + ], + "osquery.days.number": [ + 12 + ], + "host.architecture": [ + "x86_64" + ], + "@timestamp": [ + "2021-04-12T14:15:45.060Z" + ], + "agent.id": [ + "196a0086-a612-48b1-930a-300565b3efaf" + ], + "host.os.platform": [ + "darwin" + ], + "ecs.version": [ + "1.8.0" + ], + "agent.ephemeral_id": [ + "5cb88e34-50fe-4c13-b81c-d2b7187505ea" + ], + "agent.version": [ + "7.13.0" + ], + "host.os.family": [ + "darwin" + ], + "osquery.minutes.number": [ + 37 + ] + } +} +``` + +The following is an example of an **error response** for an undefined action query: + +```ts +{ + "_index": ".ds-.fleet-actions-results-2021.04.10-000001", + "_id": "qm7mvHgBKwN-X8eyYB1x", + "_version": 1, + "_score": null, + "fields": { + "completed_at": [ + "2021-04-10T17:48:32.268Z" + ], + "error.keyword": [ + "action undefined" + ], + "@timestamp": [ + "2021-04-10T17:48:32.000Z" + ], + "action_data.query": [ + "select * from uptime;" + ], + "action_data.id": [ + "2c95bb2c-8ab6-4e8c-ac01-a1abb693ea00" + ], + "agent_id": [ + "c21b4c9c-6f36-49f0-8b60-08490fc619ce" + ], + "action_id": [ + "53454d3b-c8cd-4a50-b5b4-f85da17b4be2" + ], + "started_at": [ + "2021-04-10T17:48:32.267Z" + ], + "error": [ + "action undefined" + ] + } +} +``` +[float] +[[manage-osquery-integration]] +== Manage the integration + +[float] +== System requirements + +* {fleet-guide}/fleet-overview.html[Fleet] is enabled on your cluster, and +one or more {fleet-guide}/elastic-agent-installation-configuration.html[Elastic Agents] is enrolled. +* The https://docs.elastic.co/en/integrations/osquery_manager[*Osquery Manager*] integration +has been added and configured +for an agent policy through Fleet. +This integration supports x64 architecture on Windows, MacOS, and Linux platforms, +and ARM64 architecture on Linux. + +NOTE: The original {filebeat-ref}/filebeat-module-osquery.html[Filebeat Osquery module] +and the https://docs.elastic.co/en/integrations/osquery[Osquery Log Collection] +integration collect logs from self-managed Osquery deployments. +The *Osquery Manager* integration manages Osquery deployments +and supports running and scheduling queries from {kib}. + +[float] +== Customize Osquery sub-feature privileges + +Depending on your https://www.elastic.co/subscriptions[subscription level], +you can further customize the sub-feature privileges +for *Osquery Manager*. These include options to grant specific access for running live queries, +running saved queries, saving queries, and scheduling queries. For example, +you can create roles for users who can only run live or saved queries, but who cannot save or schedule queries. +This is useful for teams who need in-depth and detailed control. + +[float] +== Upgrade Osquery versions + +The https://github.com/osquery/osquery/releases[Osquery version] available on an Elastic Agent +is associated to the version of Osquery Beat on the Agent. +To get the latest version of Osquery Beat, +https://www.elastic.co/guide/en/fleet/master/upgrade-elastic-agent.html[upgrade your Elastic Agent]. + +[float] +== Debug issues +If you encounter issues with *Osquery Manager*, find the relevant logs for the {elastic-agent} +and Osquerybeat in the installed agent directory, then adjust the agent path for your setup. + +The relevant logs look similar to the following example paths: + +```ts +`/data/elastic-agent-054e22/logs/elastic-agent-json.log-*` +`/data/elastic-agent-054e22/logs/default/osquerybeat-json.log` +``` + +To get more details in the logs, change the agent logging level to debug: + +. Open the main menu, and then select **Fleet**. + +. Select the agent that you want to debug. + +. On the **Logs** tab, change the **Agent logging level** to **debug**, and then click **Apply changes**. ++ +`agent.logging.level` is updated in `fleet.yml`, and the logging level is changed to `debug`. diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index 050d14e4992d6..91e6b379a0620 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -32,6 +32,7 @@ Be sure to back up the encryption key value somewhere safe, as your alerting rul ==== Action settings `xpack.actions.enabled`:: +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] Feature toggle that enables Actions in {kib}. If `false`, all features dependent on Actions are disabled, including the *Observability* and *Security* apps. Default: `true`. diff --git a/docs/settings/apm-settings.asciidoc b/docs/settings/apm-settings.asciidoc index 67de6f8d24960..d812576878f2b 100644 --- a/docs/settings/apm-settings.asciidoc +++ b/docs/settings/apm-settings.asciidoc @@ -41,7 +41,8 @@ Changing these settings may disable features of the APM App. [cols="2*<"] |=== | `xpack.apm.enabled` - | Set to `false` to disable the APM app. Defaults to `true`. + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] + Set to `false` to disable the APM app. Defaults to `true`. | `xpack.apm.maxServiceEnvironments` | Maximum number of unique service environments recognized by the UI. Defaults to `100`. diff --git a/docs/settings/dev-settings.asciidoc b/docs/settings/dev-settings.asciidoc index b7edf36851d91..bcf4420cdadca 100644 --- a/docs/settings/dev-settings.asciidoc +++ b/docs/settings/dev-settings.asciidoc @@ -13,6 +13,7 @@ They are enabled by default. ==== Grok Debugger settings `xpack.grokdebugger.enabled` {ess-icon}:: +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] Set to `true` to enable the <>. Defaults to `true`. @@ -21,6 +22,7 @@ Set to `true` to enable the <>. Defaults to `t ==== {searchprofiler} settings `xpack.searchprofiler.enabled`:: +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] Set to `true` to enable the <>. Defaults to `true`. [float] @@ -28,4 +30,5 @@ Set to `true` to enable the <>. Defaults to `tr ==== Painless Lab settings `xpack.painless_lab.enabled`:: +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] When set to `true`, enables the <>. Defaults to `true`. diff --git a/docs/settings/fleet-settings.asciidoc b/docs/settings/fleet-settings.asciidoc index 3ae1c9df616b0..bf5c84324b0b9 100644 --- a/docs/settings/fleet-settings.asciidoc +++ b/docs/settings/fleet-settings.asciidoc @@ -21,7 +21,8 @@ See the {fleet-guide}/index.html[{fleet}] docs for more information. [cols="2*<"] |=== | `xpack.fleet.enabled` {ess-icon} - | Set to `true` (default) to enable {fleet}. + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] + Set to `true` (default) to enable {fleet}. | `xpack.fleet.agents.enabled` {ess-icon} | Set to `true` (default) to enable {fleet}. |=== @@ -86,6 +87,8 @@ Optional properties are: be changed by updating the {kib} config. `is_default`:: If `true`, this policy is the default agent policy. `is_default_fleet_server`:: If `true`, this policy is the default {fleet-server} agent policy. + `data_output_id`:: ID of the output to send data (Need to be identical to `monitoring_output_id`) + `monitoring_output_id`:: ID of the output to send monitoring data. (Need to be identical to `data_output_id`) `package_policies`:: List of integration policies to add to this policy. `name`::: (required) Name of the integration policy. `package`::: (required) Integration that this policy configures @@ -96,6 +99,20 @@ Optional properties are: integration. Follows the same schema as integration inputs, with the exception that any object in `vars` can be passed `frozen: true` in order to prevent that specific `var` from being edited by the user. + +| `xpack.fleet.outputs` + | List of ouputs that are configured when the {fleet} app starts. +Required properties are: + + `id`:: Unique ID for this output. The ID should be a string. + `name`:: Output name. + `type`:: Type of Output. Currently we only support "elasticsearch". + `hosts`:: Array that contains the list of host for that output. + `config`:: Extra config for that output. + +Optional properties are: + + `is_default`:: If `true`, this output is the default output. |=== Example configuration: diff --git a/docs/settings/general-infra-logs-ui-settings.asciidoc b/docs/settings/general-infra-logs-ui-settings.asciidoc index 2a9d4df1ff43c..282239dcf166c 100644 --- a/docs/settings/general-infra-logs-ui-settings.asciidoc +++ b/docs/settings/general-infra-logs-ui-settings.asciidoc @@ -1,7 +1,8 @@ [cols="2*<"] |=== | `xpack.infra.enabled` - | Set to `false` to disable the Logs and Metrics app plugin {kib}. Defaults to `true`. + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] + Set to `false` to disable the Logs and Metrics app plugin {kib}. Defaults to `true`. | `xpack.infra.sources.default.logAlias` | Index pattern for matching indices that contain log data. Defaults to `filebeat-*,kibana_sample_data_logs*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. diff --git a/docs/settings/graph-settings.asciidoc b/docs/settings/graph-settings.asciidoc index 093edb0d08547..793a8aae73158 100644 --- a/docs/settings/graph-settings.asciidoc +++ b/docs/settings/graph-settings.asciidoc @@ -8,4 +8,5 @@ You do not need to configure any settings to use the {graph-features}. `xpack.graph.enabled` {ess-icon}:: +deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] Set to `false` to disable the {graph-features}. diff --git a/docs/settings/ml-settings.asciidoc b/docs/settings/ml-settings.asciidoc index 92d0c0b491ce7..59fa236e08275 100644 --- a/docs/settings/ml-settings.asciidoc +++ b/docs/settings/ml-settings.asciidoc @@ -14,7 +14,8 @@ enabled by default. [cols="2*<"] |=== | `xpack.ml.enabled` {ess-icon} - | Set to `true` (default) to enable {kib} {ml-features}. + + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] + Set to `true` (default) to enable {kib} {ml-features}. + + If set to `false` in `kibana.yml`, the {ml} icon is hidden in this {kib} instance. If `xpack.ml.enabled` is set to `true` in `elasticsearch.yml`, however, diff --git a/docs/settings/monitoring-settings.asciidoc b/docs/settings/monitoring-settings.asciidoc index 31148f0abf4e1..03c11007c64c4 100644 --- a/docs/settings/monitoring-settings.asciidoc +++ b/docs/settings/monitoring-settings.asciidoc @@ -32,7 +32,8 @@ For more information, see [cols="2*<"] |=== | `monitoring.enabled` - | Set to `true` (default) to enable the {monitor-features} in {kib}. Unlike the + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] + Set to `true` (default) to enable the {monitor-features} in {kib}. Unlike the <> setting, when this setting is `false`, the monitoring back-end does not run and {kib} stats are not sent to the monitoring cluster. diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index 455ee76deefe3..906af1dfbb28e 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -15,7 +15,8 @@ You do not need to configure any additional settings to use the [cols="2*<"] |=== | `xpack.security.enabled` - | By default, {kib} automatically detects whether to enable the + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] + By default, {kib} automatically detects whether to enable the {security-features} based on the license and whether {es} {security-features} are enabled. + + diff --git a/docs/settings/spaces-settings.asciidoc b/docs/settings/spaces-settings.asciidoc index 3b643f76f0c09..8504464da1dfb 100644 --- a/docs/settings/spaces-settings.asciidoc +++ b/docs/settings/spaces-settings.asciidoc @@ -15,8 +15,9 @@ roles when Security is enabled. [cols="2*<"] |=== | `xpack.spaces.enabled` - | Set to `true` (default) to enable Spaces in {kib}. - This setting is deprecated. Starting in 8.0, it will not be possible to disable this plugin. + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] + Set to `true` (default) to enable Spaces in {kib}. + This setting is deprecated. Starting in 8.0, it will not be possible to disable this plugin. | `xpack.spaces.maxSpaces` | The maximum amount of Spaces that can be used with this instance of {kib}. Some operations diff --git a/docs/settings/url-drilldown-settings.asciidoc b/docs/settings/url-drilldown-settings.asciidoc index 8be3a21bfbffc..ca414d4f650e9 100644 --- a/docs/settings/url-drilldown-settings.asciidoc +++ b/docs/settings/url-drilldown-settings.asciidoc @@ -9,7 +9,8 @@ Configure the URL drilldown settings in your `kibana.yml` configuration file. [cols="2*<"] |=== | [[url-drilldown-enabled]] `url_drilldown.enabled` - | When `true`, enables URL drilldowns on your {kib} instance. + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] + When `true`, enables URL drilldowns on your {kib} instance. | [[external-URL-policy]] `externalUrl.policy` | Configures the external URL policies. URL drilldowns respect the global *External URL* service, which you can use to deny or allow external URLs. diff --git a/docs/setup/docker.asciidoc b/docs/setup/docker.asciidoc index cc14e79c54f15..01fc6e2e76f92 100644 --- a/docs/setup/docker.asciidoc +++ b/docs/setup/docker.asciidoc @@ -125,7 +125,7 @@ Some example translations are shown here: **Environment Variable**:: **Kibana Setting** `SERVER_NAME`:: `server.name` `SERVER_BASEPATH`:: `server.basePath` -`MONITORING_ENABLED`:: `monitoring.enabled` +`ELASTICSEARCH_HOSTS`:: `elasticsearch.hosts` In general, any setting listed in <> can be configured with this technique. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 78b776c85c937..c098fb697de04 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -21,7 +21,8 @@ configuration using `${MY_ENV_VAR}` syntax. |=== | `console.enabled:` - | Toggling this causes the server to regenerate assets on the next startup, + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] +Toggling this causes the server to regenerate assets on the next startup, which may cause a delay before pages start being served. Set to `false` to disable Console. *Default: `true`* @@ -706,12 +707,13 @@ sources and images. When false, Vega can only get data from {es}. *Default: `fal | Enables you to view the underlying documents in a data series from a dashboard panel. *Default: `false`* | `xpack.license_management.enabled` - | Set this value to false to -disable the License Management UI. *Default: `true`* + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] +Set this value to false to disable the License Management UI. +*Default: `true`* | `xpack.rollup.enabled:` - | Set this value to false to disable the -Rollup UI. *Default: true* + | deprecated:[7.16.0,"In 8.0 and later, this setting will no longer be supported."] +Set this value to false to disable the Rollup UI. *Default: true* | `i18n.locale` {ess-icon} | Set this value to change the {kib} interface language. diff --git a/docs/user/api.asciidoc b/docs/user/api.asciidoc index 00aa3c545df69..12e200bb0ba27 100644 --- a/docs/user/api.asciidoc +++ b/docs/user/api.asciidoc @@ -96,6 +96,7 @@ include::{kib-repo-dir}/api/alerting.asciidoc[] include::{kib-repo-dir}/api/actions-and-connectors.asciidoc[] include::{kib-repo-dir}/api/dashboard-api.asciidoc[] include::{kib-repo-dir}/api/logstash-configuration-management.asciidoc[] +include::{kib-repo-dir}/api/machine-learning.asciidoc[] include::{kib-repo-dir}/api/url-shortening.asciidoc[] include::{kib-repo-dir}/api/task-manager/health.asciidoc[] include::{kib-repo-dir}/api/upgrade-assistant.asciidoc[] diff --git a/docs/user/dashboard/images/tsvb_index_pattern_selection_mode.png b/docs/user/dashboard/images/tsvb_index_pattern_selection_mode.png index ef72f291850e4..4a790650ae060 100644 Binary files a/docs/user/dashboard/images/tsvb_index_pattern_selection_mode.png and b/docs/user/dashboard/images/tsvb_index_pattern_selection_mode.png differ diff --git a/docs/user/dashboard/lens.asciidoc b/docs/user/dashboard/lens.asciidoc index 0f130f15c8a77..c3e0a5523a78d 100644 --- a/docs/user/dashboard/lens.asciidoc +++ b/docs/user/dashboard/lens.asciidoc @@ -441,4 +441,20 @@ Pagination in a data table is unsupported. To use pagination in data tables, cre [%collapsible] ==== Specifying the color for a single data point, such as a single bar or line, is unsupported. -==== \ No newline at end of file +==== + +[discrete] +[[is-it-possible-to-inspect-the-elasticsearch-queries-in-Lens]] +.*How do I inspect {es} queries in visualizations?* +[%collapsible] +==== +You can inspect the requests sent by the visualization to {es} using the Inspector. It can be accessed within the editor or in the dashboard. +==== + +[discrete] +[[how-to-isolate-a-single-series-in-a-chart]] +.*How do I isolate a single series in a chart?* +[%collapsible] +==== +For area, line, and bar charts, press Shift, then click the series in the legend. All other series are automatically unselected. +==== diff --git a/docs/user/dashboard/tsvb.asciidoc b/docs/user/dashboard/tsvb.asciidoc index 5eb818b0ea3e4..80138990c4f6e 100644 --- a/docs/user/dashboard/tsvb.asciidoc +++ b/docs/user/dashboard/tsvb.asciidoc @@ -53,8 +53,8 @@ When you use only {data-sources}, you are able to: * Improve performance -IMPORTANT: Creating *TSVB* visualizations with an {es} index string is deprecated and will be removed in a future release. -It is the default one for new visualizations but it can also be switched for the old implementations: +IMPORTANT: Creating *TSVB* visualizations with an {es} index string is deprecated. To use an {es} index string, contact your administrator, or go to <> and set `metrics:allowStringIndices` to `true`. Creating *TSVB* visualizations with an {es} index string will be removed in a future release. +Creating visualizations with only {data-sources} is the default one for new visualizations but it can also be switched for the old implementations: . Click *Panel options*, then open the *Index pattern selection mode* options next to the *Index pattern* dropdown. diff --git a/docs/user/dashboard/vega-reference.asciidoc b/docs/user/dashboard/vega-reference.asciidoc index 0881afd1003da..1277797417c9e 100644 --- a/docs/user/dashboard/vega-reference.asciidoc +++ b/docs/user/dashboard/vega-reference.asciidoc @@ -102,6 +102,8 @@ Tokens include the following: * `"%dashboard_context-filter_clause%"`: String replaced by an object containing filters * `"%dashboard_context-must_not_clause%"`: String replaced by an object containing filters +NOTE: Vega supports the `interval` parameter, which is unsupported {es} 8.0.0 and later. To use intervals, use `fixed_interval` or `calendar_interval` instead. + For example, the following query counts the number of documents in a specific index: [source,yaml] diff --git a/docs/user/index.asciidoc b/docs/user/index.asciidoc index 29dd5e49a668b..75d0da1c597b6 100644 --- a/docs/user/index.asciidoc +++ b/docs/user/index.asciidoc @@ -34,12 +34,14 @@ include::{kib-repo-dir}/siem/index.asciidoc[] include::dev-tools.asciidoc[] +include::{kib-repo-dir}/fleet/fleet.asciidoc[] + +include::{kib-repo-dir}/osquery/osquery.asciidoc[] + include::monitoring/index.asciidoc[] include::management.asciidoc[] -include::{kib-repo-dir}/fleet/fleet.asciidoc[] - include::api.asciidoc[] include::plugins.asciidoc[] diff --git a/docs/user/plugins.asciidoc b/docs/user/plugins.asciidoc index 0ef5d1a237510..c604526d6c933 100644 --- a/docs/user/plugins.asciidoc +++ b/docs/user/plugins.asciidoc @@ -149,6 +149,8 @@ NOTE: Removing a plugin will result in an "optimize" run which will delay the ne [[disable-plugin]] == Disable plugins +deprecated:[7.16.0,"In 8.0 and later, this setting will only be supported for a subset of plugins that have opted in to the behavior."] + Use the following command to disable a plugin: [source,shell] @@ -158,7 +160,7 @@ Use the following command to disable a plugin: NOTE: Disabling or enabling a plugin will result in an "optimize" run which will delay the start of {kib}. -<1> You can find a plugin's plugin ID as the value of the `name` property in the plugin's `package.json` file. +<1> You can find a plugin's plugin ID as the value of the `name` property in the plugin's `kibana.json` file. [float] [[configure-plugin-manager]] diff --git a/examples/embeddable_examples/kibana.json b/examples/embeddable_examples/kibana.json index d725a5c94a9c8..103857804b5d4 100644 --- a/examples/embeddable_examples/kibana.json +++ b/examples/embeddable_examples/kibana.json @@ -9,7 +9,7 @@ "githubTeam": "kibana-app-services" }, "description": "Example app that shows how to register custom embeddables", - "requiredPlugins": ["embeddable", "uiActions", "savedObjects", "dashboard"], + "requiredPlugins": ["embeddable", "uiActions", "savedObjects", "dashboard", "kibanaUtils"], "optionalPlugins": [], "extraPublicDirs": ["public/todo", "public/hello_world", "public/todo/todo_ref_embeddable"], "requiredBundles": ["kibanaReact"] diff --git a/examples/embeddable_examples/public/migrations/migrations_embeddable_factory.ts b/examples/embeddable_examples/public/migrations/migrations_embeddable_factory.ts index c1ceaaca3e466..61e6bfa56ec47 100644 --- a/examples/embeddable_examples/public/migrations/migrations_embeddable_factory.ts +++ b/examples/embeddable_examples/public/migrations/migrations_embeddable_factory.ts @@ -7,6 +7,7 @@ */ import { i18n } from '@kbn/i18n'; +import { EmbeddableStateWithType } from '../../../../src/plugins/embeddable/common'; import { IContainer, EmbeddableInput, @@ -35,6 +36,16 @@ export class SimpleEmbeddableFactoryDefinition '7.3.0': migration730, }; + public extract(state: EmbeddableStateWithType) { + // this embeddable does not store references to other saved objects + return { state, references: [] }; + } + + public inject(state: EmbeddableStateWithType) { + // this embeddable does not store references to other saved objects + return state; + } + /** * In our simple example, we let everyone have permissions to edit this. Most * embeddables should check the UI Capabilities service to be sure of diff --git a/examples/embeddable_examples/server/merge_migration_function_maps.ts b/examples/embeddable_examples/server/merge_migration_function_maps.ts new file mode 100644 index 0000000000000..01a46949e6bbf --- /dev/null +++ b/examples/embeddable_examples/server/merge_migration_function_maps.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { mergeWith } from 'lodash'; +import type { SerializableRecord } from '@kbn/utility-types'; +import { MigrateFunctionsObject, MigrateFunction } from '../../../src/plugins/kibana_utils/common'; + +export const mergeMigrationFunctionMaps = ( + obj1: MigrateFunctionsObject, + obj2: MigrateFunctionsObject +) => { + const customizer = (objValue: MigrateFunction, srcValue: MigrateFunction) => { + if (!srcValue || !objValue) { + return srcValue || objValue; + } + return (state: SerializableRecord) => objValue(srcValue(state)); + }; + + return mergeWith({ ...obj1 }, obj2, customizer); +}; diff --git a/examples/embeddable_examples/server/searchable_list_saved_object.ts b/examples/embeddable_examples/server/searchable_list_saved_object.ts index ac4656c7c2b77..a3b12a05323f0 100644 --- a/examples/embeddable_examples/server/searchable_list_saved_object.ts +++ b/examples/embeddable_examples/server/searchable_list_saved_object.ts @@ -9,9 +9,12 @@ import { mapValues } from 'lodash'; import { SavedObjectsType, SavedObjectUnsanitizedDoc } from 'kibana/server'; import { EmbeddableSetup } from '../../../src/plugins/embeddable/server'; +// NOTE: this should rather be imported from 'plugins/kibana_utils/server' but examples at the moment don't +// allow static imports from plugins so this code was duplicated +import { mergeMigrationFunctionMaps } from './merge_migration_function_maps'; export const searchableListSavedObject = (embeddable: EmbeddableSetup) => { - return { + const searchableListSO: SavedObjectsType = { name: 'searchableList', hidden: false, namespaceType: 'single', @@ -30,14 +33,22 @@ export const searchableListSavedObject = (embeddable: EmbeddableSetup) => { }, }, migrations: () => { - // we assume all the migration will be done by embeddables service and that saved object holds no extra state besides that of searchable list embeddable input\ - // if saved object would hold additional information we would need to merge the response from embeddables.getAllMigrations with our custom migrations. - return mapValues(embeddable.getAllMigrations(), (migrate) => { + // there are no migrations defined for the saved object at the moment, possibly they would be added in the future + const searchableListSavedObjectMigrations = {}; + + // we don't know if embeddables have any migrations defined so we need to fetch them and map the received functions so we pass + // them the correct input and that we correctly map the response + const embeddableMigrations = mapValues(embeddable.getAllMigrations(), (migrate) => { return (state: SavedObjectUnsanitizedDoc) => ({ ...state, attributes: migrate(state.attributes), }); }); + + // we merge our and embeddable migrations and return + return mergeMigrationFunctionMaps(searchableListSavedObjectMigrations, embeddableMigrations); }, - } as SavedObjectsType; + }; + + return searchableListSO; }; diff --git a/examples/partial_results_example/README.md b/examples/partial_results_example/README.md new file mode 100755 index 0000000000000..21496861ba464 --- /dev/null +++ b/examples/partial_results_example/README.md @@ -0,0 +1,9 @@ +## Partial Results Example + +The partial results is a feature of the expressions plugin allowing to emit intermediate execution results over time. + +This example plugin demonstrates: + +1. An expression function emitting a datatable with intermediate results (`getEvents`). +2. An expression function emitting an infinite number of results (`countEvent`). +3. A combination of those two functions using the `mapColumn` function that continuously updates the resulting table. diff --git a/examples/partial_results_example/kibana.json b/examples/partial_results_example/kibana.json new file mode 100644 index 0000000000000..1fe46e55d4039 --- /dev/null +++ b/examples/partial_results_example/kibana.json @@ -0,0 +1,12 @@ +{ + "id": "paertialResultsExample", + "version": "0.1.0", + "kibanaVersion": "kibana", + "ui": true, + "owner": { + "name": "App Services", + "githubTeam": "kibana-app-services" + }, + "description": "A plugin demonstrating partial results in the expressions plugin", + "requiredPlugins": ["developerExamples", "expressions"] +} diff --git a/examples/partial_results_example/public/app/app.tsx b/examples/partial_results_example/public/app/app.tsx new file mode 100644 index 0000000000000..5420ab0f4ceed --- /dev/null +++ b/examples/partial_results_example/public/app/app.tsx @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { useContext, useEffect, useState } from 'react'; +import { pluck } from 'rxjs/operators'; +import { + EuiBasicTable, + EuiCallOut, + EuiCodeBlock, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiPageContentBody, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import type { Datatable } from 'src/plugins/expressions'; +import { ExpressionsContext } from './expressions_context'; + +const expression = `getEvents + | mapColumn name="Count" expression={ + countEvent {pluck "event"} + } +`; + +export function App() { + const expressions = useContext(ExpressionsContext); + const [datatable, setDatatable] = useState(); + + useEffect(() => { + const subscription = expressions + ?.execute(expression, null) + .getData() + .pipe(pluck('result')) + .subscribe((value) => setDatatable(value as Datatable)); + + return () => subscription?.unsubscribe(); + }, [expressions]); + + return ( + + + + + +

Partial Results Demo

+
+
+
+ + + +

+ This example listens for the window events and adds them to the table along with a + trigger counter. +

+
+ + {expression} + + {datatable ? ( + ({ + field, + name, + 'data-test-subj': `example-column-${field.toLowerCase()}`, + }))} + items={datatable.rows ?? []} + /> + ) : ( + +

Click or press any key.

+
+ )} +
+
+
+
+ ); +} diff --git a/examples/partial_results_example/public/app/expressions_context.ts b/examples/partial_results_example/public/app/expressions_context.ts new file mode 100644 index 0000000000000..a14c12e0f3ac1 --- /dev/null +++ b/examples/partial_results_example/public/app/expressions_context.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createContext } from 'react'; +import type { ExpressionsServiceStart } from 'src/plugins/expressions'; + +export const ExpressionsContext = createContext(undefined); diff --git a/src/core/server/elasticsearch/deprecations/index.ts b/examples/partial_results_example/public/app/index.ts similarity index 81% rename from src/core/server/elasticsearch/deprecations/index.ts rename to examples/partial_results_example/public/app/index.ts index 4f67c0103b0a1..bde228479b13b 100644 --- a/src/core/server/elasticsearch/deprecations/index.ts +++ b/examples/partial_results_example/public/app/index.ts @@ -6,4 +6,5 @@ * Side Public License, v 1. */ -export { getElasticsearchDeprecationsProvider } from './deprecation_provider'; +export * from './app'; +export * from './expressions_context'; diff --git a/examples/partial_results_example/public/functions/count_event.ts b/examples/partial_results_example/public/functions/count_event.ts new file mode 100644 index 0000000000000..86090fe4f4d60 --- /dev/null +++ b/examples/partial_results_example/public/functions/count_event.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Observable, fromEvent } from 'rxjs'; +import { scan, startWith } from 'rxjs/operators'; +import type { ExpressionFunctionDefinition } from 'src/plugins/expressions'; + +export interface CountEventArguments { + event: string; +} + +export const countEvent: ExpressionFunctionDefinition< + 'countEvent', + null, + CountEventArguments, + Observable +> = { + name: 'countEvent', + type: 'number', + help: 'Subscribes for an event and counts a number of triggers.', + args: { + event: { + aliases: ['_'], + types: ['string'], + help: 'The event name.', + required: true, + }, + }, + fn(input, { event }) { + return fromEvent(window, event).pipe( + scan((count) => count + 1, 1), + startWith(1) + ); + }, +}; diff --git a/examples/partial_results_example/public/functions/get_events.ts b/examples/partial_results_example/public/functions/get_events.ts new file mode 100644 index 0000000000000..d911e12f11f96 --- /dev/null +++ b/examples/partial_results_example/public/functions/get_events.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Observable, fromEvent, merge } from 'rxjs'; +import { distinct, map, pluck, scan, take } from 'rxjs/operators'; +import type { Datatable, ExpressionFunctionDefinition } from 'src/plugins/expressions'; + +const EVENTS: Array = [ + 'mousedown', + 'mouseup', + 'click', + 'keydown', + 'keyup', + 'keypress', +]; + +export const getEvents: ExpressionFunctionDefinition< + 'getEvents', + null, + {}, + Observable +> = { + name: 'getEvents', + type: 'datatable', + help: 'Listens for the window events and returns a table with the triggered ones.', + args: {}, + fn() { + return merge(...EVENTS.map((event) => fromEvent(window, event))).pipe( + pluck('type'), + distinct(), + take(EVENTS.length), + scan((events, event) => [...events, event], [] as string[]), + map((events) => ({ + type: 'datatable', + columns: [ + { + id: 'event', + meta: { type: 'string' }, + name: 'Event', + }, + ], + rows: Array.from(events).map((event) => ({ event })), + })) + ); + }, +}; diff --git a/src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.test.mocks.ts b/examples/partial_results_example/public/functions/index.ts similarity index 67% rename from src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.test.mocks.ts rename to examples/partial_results_example/public/functions/index.ts index 3c78d2e4ab9f7..a53014ac494e4 100644 --- a/src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.test.mocks.ts +++ b/examples/partial_results_example/public/functions/index.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -export const isInlineScriptingDisabledMock = jest.fn(); -jest.doMock('./is_scripting_disabled', () => ({ - isInlineScriptingDisabled: isInlineScriptingDisabledMock, -})); +export * from './count_event'; +export * from './get_events'; +export * from './pluck'; diff --git a/examples/partial_results_example/public/functions/pluck.ts b/examples/partial_results_example/public/functions/pluck.ts new file mode 100644 index 0000000000000..a5a1fbc007ffa --- /dev/null +++ b/examples/partial_results_example/public/functions/pluck.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { Datatable, ExpressionFunctionDefinition } from 'src/plugins/expressions'; + +export interface PluckArguments { + key: string; +} + +export const pluck: ExpressionFunctionDefinition<'pluck', Datatable, PluckArguments, unknown> = { + name: 'pluck', + inputTypes: ['datatable'], + help: 'Takes a cell from the first table row.', + args: { + key: { + aliases: ['_'], + types: ['string'], + help: 'The column id.', + required: true, + }, + }, + fn({ rows }, { key }) { + const [{ [key]: value }] = rows; + + return value; + }, +}; diff --git a/examples/partial_results_example/public/index.ts b/examples/partial_results_example/public/index.ts new file mode 100755 index 0000000000000..241dbc5e97b45 --- /dev/null +++ b/examples/partial_results_example/public/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { PartialResultsExamplePlugin } from './plugin'; + +export function plugin() { + return new PartialResultsExamplePlugin(); +} diff --git a/examples/partial_results_example/public/plugin.tsx b/examples/partial_results_example/public/plugin.tsx new file mode 100755 index 0000000000000..aa209a87918e7 --- /dev/null +++ b/examples/partial_results_example/public/plugin.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React from 'react'; +import ReactDOM from 'react-dom'; +import type { ExpressionsService, ExpressionsServiceSetup } from 'src/plugins/expressions'; +import { AppMountParameters, AppNavLinkStatus, CoreSetup, Plugin } from '../../../src/core/public'; +import type { DeveloperExamplesSetup } from '../../developer_examples/public'; +import { App, ExpressionsContext } from './app'; +import { countEvent, getEvents, pluck } from './functions'; + +interface SetupDeps { + developerExamples: DeveloperExamplesSetup; + expressions: ExpressionsServiceSetup; +} + +export class PartialResultsExamplePlugin implements Plugin { + private expressions?: ExpressionsService; + + setup({ application }: CoreSetup, { expressions, developerExamples }: SetupDeps) { + this.expressions = expressions.fork(); + this.expressions.registerFunction(countEvent); + this.expressions.registerFunction(getEvents); + this.expressions.registerFunction(pluck); + + application.register({ + id: 'partialResultsExample', + title: 'Partial Results Example', + navLinkStatus: AppNavLinkStatus.hidden, + mount: async ({ element }: AppMountParameters) => { + ReactDOM.render( + + + , + element + ); + return () => ReactDOM.unmountComponentAtNode(element); + }, + }); + + developerExamples.register({ + appId: 'partialResultsExample', + title: 'Partial Results Example', + description: 'Learn how to use partial results in the expressions plugin.', + }); + } + + start() { + return {}; + } + + stop() {} +} diff --git a/examples/partial_results_example/tsconfig.json b/examples/partial_results_example/tsconfig.json new file mode 100644 index 0000000000000..911cd4a36ed46 --- /dev/null +++ b/examples/partial_results_example/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./target", + "skipLibCheck": true + }, + "include": [ + "index.ts", + "public/**/*.ts", + "public/**/*.tsx", + "../../typings/**/*" + ], + "exclude": [], + "references": [ + { "path": "../../src/core/tsconfig.json" }, + { "path": "../developer_examples/tsconfig.json" }, + { "path": "../../src/plugins/expressions/tsconfig.json" }, + ] +} diff --git a/package.json b/package.json index f3af0ba80cfc6..d0c2810df8195 100644 --- a/package.json +++ b/package.json @@ -110,14 +110,14 @@ "@elastic/search-ui-app-search-connector": "^1.6.0", "@emotion/react": "^11.4.0", "@hapi/accept": "^5.0.2", - "@hapi/boom": "^9.1.1", + "@hapi/boom": "^9.1.4", "@hapi/cookie": "^11.0.2", "@hapi/good-squeeze": "6.0.0", "@hapi/h2o2": "^9.1.0", - "@hapi/hapi": "^20.0.3", - "@hapi/hoek": "^9.1.1", - "@hapi/inert": "^6.0.3", - "@hapi/podium": "^4.1.1", + "@hapi/hapi": "^20.2.0", + "@hapi/hoek": "^9.2.0", + "@hapi/inert": "^6.0.4", + "@hapi/podium": "^4.1.3", "@hapi/wreck": "^17.1.0", "@kbn/ace": "link:bazel-bin/packages/kbn-ace", "@kbn/alerts": "link:bazel-bin/packages/kbn-alerts", @@ -528,11 +528,10 @@ "@types/glob": "^7.1.2", "@types/gulp": "^4.0.6", "@types/gulp-zip": "^4.0.1", - "@types/hapi__cookie": "^10.1.1", - "@types/hapi__h2o2": "^8.3.2", - "@types/hapi__hapi": "^20.0.2", - "@types/hapi__inert": "^5.2.2", - "@types/hapi__podium": "^3.4.1", + "@types/hapi__cookie": "^10.1.3", + "@types/hapi__h2o2": "^8.3.3", + "@types/hapi__hapi": "^20.0.9", + "@types/hapi__inert": "^5.2.3", "@types/has-ansi": "^3.0.0", "@types/he": "^1.1.1", "@types/history": "^4.7.3", @@ -573,7 +572,7 @@ "@types/nock": "^10.0.3", "@types/node": "14.14.44", "@types/node-fetch": "^2.5.7", - "@types/node-forge": "^0.10.4", + "@types/node-forge": "^0.10.5", "@types/nodemailer": "^6.4.0", "@types/normalize-path": "^3.0.0", "@types/object-hash": "^1.3.0", @@ -664,7 +663,7 @@ "callsites": "^3.1.0", "chai": "3.5.0", "chance": "1.0.18", - "chromedriver": "^92.0.1", + "chromedriver": "^93.0.1", "clean-webpack-plugin": "^3.0.0", "cmd-shim": "^2.1.0", "compression-webpack-plugin": "^4.0.0", @@ -810,7 +809,7 @@ "tar-fs": "^2.1.0", "tempy": "^0.3.0", "terser": "^5.7.1", - "terser-webpack-plugin": "^2.1.2", + "terser-webpack-plugin": "^4.2.3", "tough-cookie": "^4.0.0", "ts-loader": "^7.0.5", "ts-morph": "^9.1.0", diff --git a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts index 6d12d5d05f07c..b198e6139d5d7 100644 --- a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts @@ -131,7 +131,7 @@ export class BasePathProxyServer { agent: this.httpsAgent, passThrough: true, xforward: true, - mapUri: async (request) => { + mapUri: async (request: Request) => { return { // Passing in this header to merge it is a workaround until this is fixed: // https://github.com/hapijs/h2o2/issues/124 diff --git a/packages/kbn-config/src/config_service.test.ts b/packages/kbn-config/src/config_service.test.ts index aa520e7189e54..754de1c0a99f5 100644 --- a/packages/kbn-config/src/config_service.test.ts +++ b/packages/kbn-config/src/config_service.test.ts @@ -364,6 +364,37 @@ test('read "enabled" even if its schema is not present', async () => { expect(isEnabled).toBe(true); }); +test('logs deprecation if schema is not present and "enabled" is used', async () => { + const initialConfig = { + foo: { + enabled: true, + }, + }; + + const rawConfigProvider = rawConfigServiceMock.create({ rawConfig: initialConfig }); + const configService = new ConfigService(rawConfigProvider, defaultEnv, logger); + + await configService.isEnabledAtPath('foo'); + expect(configService.getHandledDeprecatedConfigs()).toMatchInlineSnapshot(` + Array [ + Array [ + "foo", + Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Remove \\"foo.enabled\\" from the Kibana config file, CLI flag, or environment variable (in Docker only) before upgrading to 8.0.0.", + ], + }, + "message": "Configuring \\"foo.enabled\\" is deprecated and will be removed in 8.0.0.", + "title": "Setting \\"foo.enabled\\" is deprecated", + }, + ], + ], + ] + `); +}); + test('allows plugins to specify "enabled" flag via validation schema', async () => { const initialConfig = {}; diff --git a/packages/kbn-config/src/config_service.ts b/packages/kbn-config/src/config_service.ts index 514992891ad1b..5883ce8ab513c 100644 --- a/packages/kbn-config/src/config_service.ts +++ b/packages/kbn-config/src/config_service.ts @@ -177,6 +177,23 @@ export class ConfigService { // if plugin hasn't got a config schema, we try to read "enabled" directly const isEnabled = validatedConfig?.enabled ?? config.get(enabledPath); + // if we implicitly added an `enabled` config to a plugin without a schema, + // we log a deprecation warning, as this will not be supported in 8.0 + if (validatedConfig?.enabled === undefined && isEnabled !== undefined) { + const deprecationPath = pathToString(enabledPath); + const deprecatedConfigDetails: DeprecatedConfigDetails = { + title: `Setting "${deprecationPath}" is deprecated`, + message: `Configuring "${deprecationPath}" is deprecated and will be removed in 8.0.0.`, + correctiveActions: { + manualSteps: [ + `Remove "${deprecationPath}" from the Kibana config file, CLI flag, or environment variable (in Docker only) before upgrading to 8.0.0.`, + ], + }, + }; + this.deprecationLog.warn(deprecatedConfigDetails.message); + this.markDeprecatedConfigAsHandled(namespace, deprecatedConfigDetails); + } + // not declared. consider that plugin is enabled by default if (isEnabled === undefined) { return true; @@ -220,9 +237,7 @@ export class ConfigService { if (!context.silent) { deprecationMessages.push(context.message); } - const handledDeprecatedConfig = this.handledDeprecatedConfigs.get(domainId) || []; - handledDeprecatedConfig.push(context); - this.handledDeprecatedConfigs.set(domainId, handledDeprecatedConfig); + this.markDeprecatedConfigAsHandled(domainId, context); }; applyDeprecations(rawConfig, deprecations, createAddDeprecation); @@ -260,6 +275,12 @@ export class ConfigService { this.log.debug(`Marking config path as handled: ${path}`); this.handledPaths.add(path); } + + private markDeprecatedConfigAsHandled(domainId: string, config: DeprecatedConfigDetails) { + const handledDeprecatedConfig = this.handledDeprecatedConfigs.get(domainId) || []; + handledDeprecatedConfig.push(config); + this.handledDeprecatedConfigs.set(domainId, handledDeprecatedConfig); + } } const createPluginEnabledPath = (configPath: string | string[]) => { diff --git a/packages/kbn-config/src/deprecation/deprecation_factory.test.ts b/packages/kbn-config/src/deprecation/deprecation_factory.test.ts index 0a605cbc1c532..dfd6b8fac681f 100644 --- a/packages/kbn-config/src/deprecation/deprecation_factory.test.ts +++ b/packages/kbn-config/src/deprecation/deprecation_factory.test.ts @@ -10,7 +10,8 @@ import { DeprecatedConfigDetails } from './types'; import { configDeprecationFactory } from './deprecation_factory'; describe('DeprecationFactory', () => { - const { rename, unused, renameFromRoot, unusedFromRoot } = configDeprecationFactory; + const { deprecate, deprecateFromRoot, rename, renameFromRoot, unused, unusedFromRoot } = + configDeprecationFactory; const addDeprecation = jest.fn(); @@ -18,6 +19,139 @@ describe('DeprecationFactory', () => { addDeprecation.mockClear(); }); + describe('deprecate', () => { + it('logs a warning when property is present', () => { + const rawConfig = { + myplugin: { + deprecated: 'deprecated', + valid: 'valid', + }, + someOtherPlugin: { + property: 'value', + }, + }; + const commands = deprecate('deprecated', '8.0.0')(rawConfig, 'myplugin', addDeprecation); + expect(commands).toBeUndefined(); + expect(addDeprecation.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Remove \\"myplugin.deprecated\\" from the Kibana config file, CLI flag, or environment variable (in Docker only) before upgrading to 8.0.0.", + ], + }, + "message": "Configuring \\"myplugin.deprecated\\" is deprecated and will be removed in 8.0.0.", + "title": "Setting \\"myplugin.deprecated\\" is deprecated", + }, + ], + ] + `); + }); + + it('handles deeply nested keys', () => { + const rawConfig = { + myplugin: { + section: { + deprecated: 'deprecated', + }, + valid: 'valid', + }, + someOtherPlugin: { + property: 'value', + }, + }; + const commands = deprecate('section.deprecated', '8.0.0')( + rawConfig, + 'myplugin', + addDeprecation + ); + expect(commands).toBeUndefined(); + expect(addDeprecation.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Remove \\"myplugin.section.deprecated\\" from the Kibana config file, CLI flag, or environment variable (in Docker only) before upgrading to 8.0.0.", + ], + }, + "message": "Configuring \\"myplugin.section.deprecated\\" is deprecated and will be removed in 8.0.0.", + "title": "Setting \\"myplugin.section.deprecated\\" is deprecated", + }, + ], + ] + `); + }); + + it('does not log if unused property is not present', () => { + const rawConfig = { + myplugin: { + valid: 'valid', + }, + someOtherPlugin: { + property: 'value', + }, + }; + const commands = deprecate('deprecated', '8.0.0')(rawConfig, 'myplugin', addDeprecation); + expect(commands).toBeUndefined(); + expect(addDeprecation).toBeCalledTimes(0); + }); + }); + + describe('deprecateFromRoot', () => { + it('logs a warning when property is present', () => { + const rawConfig = { + myplugin: { + deprecated: 'deprecated', + valid: 'valid', + }, + someOtherPlugin: { + property: 'value', + }, + }; + const commands = deprecateFromRoot('myplugin.deprecated', '8.0.0')( + rawConfig, + 'does-not-matter', + addDeprecation + ); + expect(commands).toBeUndefined(); + expect(addDeprecation.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Remove \\"myplugin.deprecated\\" from the Kibana config file, CLI flag, or environment variable (in Docker only) before upgrading to 8.0.0.", + ], + }, + "message": "Configuring \\"myplugin.deprecated\\" is deprecated and will be removed in 8.0.0.", + "title": "Setting \\"myplugin.deprecated\\" is deprecated", + }, + ], + ] + `); + }); + + it('does not log if unused property is not present', () => { + const rawConfig = { + myplugin: { + valid: 'valid', + }, + someOtherPlugin: { + property: 'value', + }, + }; + const commands = deprecateFromRoot('myplugin.deprecated', '8.0.0')( + rawConfig, + 'does-not-matter', + addDeprecation + ); + expect(commands).toBeUndefined(); + expect(addDeprecation).toBeCalledTimes(0); + }); + }); + describe('rename', () => { it('moves the property to rename and logs a warning if old property exist and new one does not', () => { const rawConfig = { @@ -132,7 +266,7 @@ describe('DeprecationFactory', () => { "Remove \\"myplugin.deprecated\\" from the config.", ], }, - "message": "Setting \\"$myplugin.deprecated\\" has been replaced by \\"$myplugin.renamed\\". However, both keys are present. Ignoring \\"$myplugin.deprecated\\"", + "message": "Setting \\"myplugin.deprecated\\" has been replaced by \\"myplugin.renamed\\". However, both keys are present. Ignoring \\"myplugin.deprecated\\"", "title": "Setting \\"myplugin.deprecated\\" is deprecated", }, ], @@ -269,7 +403,7 @@ describe('DeprecationFactory', () => { "Remove \\"myplugin.deprecated\\" from the config.", ], }, - "message": "Setting \\"$myplugin.deprecated\\" has been replaced by \\"$myplugin.renamed\\". However, both keys are present. Ignoring \\"$myplugin.deprecated\\"", + "message": "Setting \\"myplugin.deprecated\\" has been replaced by \\"myplugin.renamed\\". However, both keys are present. Ignoring \\"myplugin.deprecated\\"", "title": "Setting \\"myplugin.deprecated\\" is deprecated", }, ], diff --git a/packages/kbn-config/src/deprecation/deprecation_factory.ts b/packages/kbn-config/src/deprecation/deprecation_factory.ts index 119b9b11237dc..1d61733715bd9 100644 --- a/packages/kbn-config/src/deprecation/deprecation_factory.ts +++ b/packages/kbn-config/src/deprecation/deprecation_factory.ts @@ -24,6 +24,37 @@ const getDeprecationTitle = (deprecationPath: string) => { }); }; +const _deprecate = ( + config: Record, + rootPath: string, + addDeprecation: AddConfigDeprecation, + deprecatedKey: string, + removeBy: string, + details?: Partial +): void => { + const fullPath = getPath(rootPath, deprecatedKey); + if (get(config, fullPath) === undefined) { + return; + } + addDeprecation({ + title: getDeprecationTitle(fullPath), + message: i18n.translate('kbnConfig.deprecations.deprecatedSettingMessage', { + defaultMessage: 'Configuring "{fullPath}" is deprecated and will be removed in {removeBy}.', + values: { fullPath, removeBy }, + }), + correctiveActions: { + manualSteps: [ + i18n.translate('kbnConfig.deprecations.deprecatedSetting.manualStepOneMessage', { + defaultMessage: + 'Remove "{fullPath}" from the Kibana config file, CLI flag, or environment variable (in Docker only) before upgrading to {removeBy}.', + values: { fullPath, removeBy }, + }), + ], + }, + ...details, + }); +}; + const _rename = ( config: Record, rootPath: string, @@ -67,7 +98,7 @@ const _rename = ( title: getDeprecationTitle(fullOldPath), message: i18n.translate('kbnConfig.deprecations.conflictSettingMessage', { defaultMessage: - 'Setting "${fullOldPath}" has been replaced by "${fullNewPath}". However, both keys are present. Ignoring "${fullOldPath}"', + 'Setting "{fullOldPath}" has been replaced by "{fullNewPath}". However, both keys are present. Ignoring "{fullOldPath}"', values: { fullOldPath, fullNewPath }, }), correctiveActions: { @@ -125,6 +156,24 @@ const _unused = ( }; }; +const deprecate = + ( + unusedKey: string, + removeBy: string, + details?: Partial + ): ConfigDeprecation => + (config, rootPath, addDeprecation) => + _deprecate(config, rootPath, addDeprecation, unusedKey, removeBy, details); + +const deprecateFromRoot = + ( + unusedKey: string, + removeBy: string, + details?: Partial + ): ConfigDeprecation => + (config, rootPath, addDeprecation) => + _deprecate(config, '', addDeprecation, unusedKey, removeBy, details); + const rename = (oldKey: string, newKey: string, details?: Partial): ConfigDeprecation => (config, rootPath, addDeprecation) => @@ -154,6 +203,8 @@ const getPath = (rootPath: string, subPath: string) => * @internal */ export const configDeprecationFactory: ConfigDeprecationFactory = { + deprecate, + deprecateFromRoot, rename, renameFromRoot, unused, diff --git a/packages/kbn-config/src/deprecation/types.ts b/packages/kbn-config/src/deprecation/types.ts index 0e1f36121e50e..47a31b9e6725a 100644 --- a/packages/kbn-config/src/deprecation/types.ts +++ b/packages/kbn-config/src/deprecation/types.ts @@ -91,6 +91,7 @@ export interface ConfigDeprecationCommand { * @example * ```typescript * const provider: ConfigDeprecationProvider = ({ rename, unused }) => [ + * deprecate('deprecatedKey', '8.0.0'), * rename('oldKey', 'newKey'), * unused('deprecatedKey'), * (config, path) => ({ unset: [{ key: 'path.to.key' }] }) @@ -119,6 +120,43 @@ export type ConfigDeprecationProvider = (factory: ConfigDeprecationFactory) => C */ export interface ConfigDeprecationFactory { + /** + * Deprecate a configuration property from inside a plugin's configuration path. + * Will log a deprecation warning if the deprecatedKey was found. + * + * @example + * Log a deprecation warning indicating 'myplugin.deprecatedKey' should be removed by `8.0.0` + * ```typescript + * const provider: ConfigDeprecationProvider = ({ deprecate }) => [ + * deprecate('deprecatedKey', '8.0.0'), + * ] + * ``` + */ + deprecate( + deprecatedKey: string, + removeBy: string, + details?: Partial + ): ConfigDeprecation; + /** + * Deprecate a configuration property from the root configuration. + * Will log a deprecation warning if the deprecatedKey was found. + * + * This should be only used when deprecating properties from different configuration's path. + * To deprecate properties from inside a plugin's configuration, use 'deprecate' instead. + * + * @example + * Log a deprecation warning indicating 'myplugin.deprecatedKey' should be removed by `8.0.0` + * ```typescript + * const provider: ConfigDeprecationProvider = ({ deprecate }) => [ + * deprecateFromRoot('deprecatedKey', '8.0.0'), + * ] + * ``` + */ + deprecateFromRoot( + deprecatedKey: string, + removeBy: string, + details?: Partial + ): ConfigDeprecation; /** * Rename a configuration property from inside a plugin's configuration path. * Will log a deprecation warning if the oldKey was found and deprecation applied. diff --git a/packages/kbn-legacy-logging/BUILD.bazel b/packages/kbn-legacy-logging/BUILD.bazel index 1148cf1d38b65..c4927fe076e15 100644 --- a/packages/kbn-legacy-logging/BUILD.bazel +++ b/packages/kbn-legacy-logging/BUILD.bazel @@ -29,6 +29,7 @@ RUNTIME_DEPS = [ "//packages/kbn-utils", "@npm//@elastic/numeral", "@npm//@hapi/hapi", + "@npm//@hapi/podium", "@npm//chokidar", "@npm//lodash", "@npm//moment-timezone", @@ -41,12 +42,12 @@ TYPES_DEPS = [ "//packages/kbn-config-schema", "//packages/kbn-utils", "@npm//@elastic/numeral", + "@npm//@hapi/podium", "@npm//chokidar", "@npm//query-string", "@npm//rxjs", "@npm//tslib", "@npm//@types/hapi__hapi", - "@npm//@types/hapi__podium", "@npm//@types/jest", "@npm//@types/lodash", "@npm//@types/moment-timezone", diff --git a/packages/kbn-legacy-logging/src/legacy_logging_server.ts b/packages/kbn-legacy-logging/src/legacy_logging_server.ts index c02eb2803515a..f6c42dd1b161f 100644 --- a/packages/kbn-legacy-logging/src/legacy_logging_server.ts +++ b/packages/kbn-legacy-logging/src/legacy_logging_server.ts @@ -112,7 +112,6 @@ export class LegacyLoggingServer { tags: [getLegacyLogLevel(level), ...context.split('.'), ...tags], timestamp: timestamp.getTime(), }) - // @ts-expect-error @hapi/podium emit is actually an async function .catch((err) => { // eslint-disable-next-line no-console console.error('An unexpected error occurred while writing to the log:', err.stack); diff --git a/packages/kbn-legacy-logging/src/setup_logging.ts b/packages/kbn-legacy-logging/src/setup_logging.ts index 800ed2e523274..a045469e81251 100644 --- a/packages/kbn-legacy-logging/src/setup_logging.ts +++ b/packages/kbn-legacy-logging/src/setup_logging.ts @@ -23,7 +23,7 @@ export async function setupLogging( // thrown every time we start the server. // In order to keep using the legacy logger until we remove it I'm just adding // a new hard limit here. - process.stdout.setMaxListeners(40); + process.stdout.setMaxListeners(60); return await server.register({ plugin: good, diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 69cfffe1f08f0..3b6cc7f249931 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -73,7 +73,7 @@ pageLoadAssetSize: transform: 41007 triggersActionsUi: 100000 uiActions: 97717 - uiActionsEnhanced: 313011 + uiActionsEnhanced: 32000 upgradeAssistant: 81241 uptime: 40825 urlDrilldown: 70674 @@ -115,3 +115,4 @@ pageLoadAssetSize: expressionTagcloud: 27505 expressions: 239290 securitySolution: 231753 + customIntegrations: 28810 diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 6c00ef08b8600..9a0863237fab1 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -276,6 +276,7 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: parallel: false, terserOptions: { compress: true, + keep_classnames: true, mangle: !['kibanaLegacy', 'monitoring'].includes(bundle.id), }, }), diff --git a/packages/kbn-storybook/templates/index.ejs b/packages/kbn-storybook/templates/index.ejs index 1fca20b1ff8e8..3473f73ca131f 100644 --- a/packages/kbn-storybook/templates/index.ejs +++ b/packages/kbn-storybook/templates/index.ejs @@ -16,12 +16,11 @@ - - + - + diff --git a/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts b/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts index d4bf625ee2d3b..0129614fe658d 100644 --- a/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts +++ b/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts @@ -37,17 +37,24 @@ export function runFailedTestsReporterCli() { } if (updateGithub) { - let branch: string | undefined = ''; + let branch: string = ''; let isPr = false; if (process.env.BUILDKITE === 'true') { - branch = process.env.BUILDKITE_BRANCH; + branch = process.env.BUILDKITE_BRANCH || ''; isPr = process.env.BUILDKITE_PULL_REQUEST === 'true'; + updateGithub = process.env.REPORT_FAILED_TESTS_TO_GITHUB === 'true'; } else { // JOB_NAME is formatted as `elastic+kibana+7.x` in some places and `elastic+kibana+7.x/JOB=kibana-intake,node=immutable` in others const jobNameSplit = (process.env.JOB_NAME || '').split(/\+|\//); - branch = jobNameSplit.length >= 3 ? jobNameSplit[2] : process.env.GIT_BRANCH; + branch = jobNameSplit.length >= 3 ? jobNameSplit[2] : process.env.GIT_BRANCH || ''; isPr = !!process.env.ghprbPullId; + + const isMasterOrVersion = branch === 'master' || branch.match(/^\d+\.(x|\d+)$/); + if (!isMasterOrVersion || isPr) { + log.info('Failure issues only created on master/version branch jobs'); + updateGithub = false; + } } if (!branch) { @@ -55,12 +62,6 @@ export function runFailedTestsReporterCli() { 'Unable to determine originating branch from job name or other environment variables' ); } - - const isMasterOrVersion = branch === 'master' || branch.match(/^\d+\.(x|\d+)$/); - if (!isMasterOrVersion || isPr) { - log.info('Failure issues only created on master/version branch jobs'); - updateGithub = false; - } } const githubApi = new GithubApi({ diff --git a/packages/kbn-typed-react-router-config/src/create_router.test.tsx b/packages/kbn-typed-react-router-config/src/create_router.test.tsx index 61ba8eb157ee3..9837d45ddd869 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.test.tsx +++ b/packages/kbn-typed-react-router-config/src/create_router.test.tsx @@ -33,6 +33,28 @@ describe('createRouter', () => { }, }, children: [ + { + path: '/services/{serviceName}/errors', + element: <>, + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + }), + children: [ + { + path: '/services/{serviceName}/errors/{groupId}', + element: <>, + params: t.type({ + path: t.type({ groupId: t.string }), + }), + }, + { + path: '/services/{serviceName}/errors', + element: <>, + }, + ], + }, { path: '/services', element: <>, @@ -43,7 +65,7 @@ describe('createRouter', () => { }), }, { - path: '/services', + path: '/services/{serviceName}', element: <>, children: [ { @@ -252,6 +274,28 @@ describe('createRouter', () => { }, }); }); + + it('matches deep routes', () => { + history.push('/services/opbeans-java/errors/foo?rangeFrom=now-15m&rangeTo=now'); + + const matchedRoutes = router.matchRoutes( + '/services/{serviceName}/errors/{groupId}', + history.location + ); + + expect(matchedRoutes.length).toEqual(4); + + expect(matchedRoutes[matchedRoutes.length - 1].match).toEqual({ + isExact: true, + params: { + path: { + groupId: 'foo', + }, + }, + path: '/services/:serviceName/errors/:groupId', + url: '/services/opbeans-java/errors/foo', + }); + }); }); describe('link', () => { diff --git a/packages/kbn-typed-react-router-config/src/create_router.ts b/packages/kbn-typed-react-router-config/src/create_router.ts index 7f2ac818fc9b9..13f09e7546de5 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.ts +++ b/packages/kbn-typed-react-router-config/src/create_router.ts @@ -26,7 +26,7 @@ const deepExactRt: typeof deepExactRtTyped = deepExactRtNonTyped; const mergeRt: typeof mergeRtTyped = mergeRtNonTyped; function toReactRouterPath(path: string) { - return path.replace(/(?:{([^\/]+)})/, ':$1'); + return path.replace(/(?:{([^\/]+)})/g, ':$1'); } export function createRouter(routes: TRoutes): Router { diff --git a/src/core/public/application/application_service.test.ts b/src/core/public/application/application_service.test.ts index de9e4d4496f3b..f348936d26795 100644 --- a/src/core/public/application/application_service.test.ts +++ b/src/core/public/application/application_service.test.ts @@ -804,6 +804,21 @@ describe('#start()', () => { `); }); + it("when openInNewTab is true it doesn't update currentApp$ after mounting", async () => { + service.setup(setupDeps); + + const { currentAppId$, navigateToApp } = await service.start(startDeps); + const stop$ = new Subject(); + const promise = currentAppId$.pipe(bufferCount(4), takeUntil(stop$)).toPromise(); + + await navigateToApp('delta', { openInNewTab: true }); + stop$.next(); + + const appIds = await promise; + + expect(appIds).toBeUndefined(); + }); + it('updates httpLoadingCount$ while mounting', async () => { // Use a memory history so that mounting the component will work const { createMemoryHistory } = jest.requireActual('history'); diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx index 2e804bf2f5413..3ba0d78cf15fd 100644 --- a/src/core/public/application/application_service.tsx +++ b/src/core/public/application/application_service.tsx @@ -250,16 +250,15 @@ export class ApplicationService { if (path === undefined) { path = applications$.value.get(appId)?.defaultPath; } - if (!navigatingToSameApp) { - this.appInternalStates.delete(this.currentAppId$.value!); - } if (openInNewTab) { this.openInNewTab!(getAppUrl(availableMounters, appId, path)); } else { + if (!navigatingToSameApp) { + this.appInternalStates.delete(this.currentAppId$.value!); + } this.navigate!(getAppUrl(availableMounters, appId, path), state, replace); + this.currentAppId$.next(appId); } - - this.currentAppId$.next(appId); } }; diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 72fa6c5553f77..0fe1347d299f9 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -159,6 +159,17 @@ export class DocLinksService { docsBase: `${ELASTICSEARCH_DOCS}`, asyncSearch: `${ELASTICSEARCH_DOCS}async-search-intro.html`, dataStreams: `${ELASTICSEARCH_DOCS}data-streams.html`, + deprecationLogging: `${ELASTICSEARCH_DOCS}logging.html#deprecation-logging`, + ilm: `${ELASTICSEARCH_DOCS}index-lifecycle-management.html`, + ilmForceMerge: `${ELASTICSEARCH_DOCS}ilm-forcemerge.html`, + ilmFreeze: `${ELASTICSEARCH_DOCS}ilm-freeze.html`, + ilmPhaseTransitions: `${ELASTICSEARCH_DOCS}ilm-index-lifecycle.html#ilm-phase-transitions`, + ilmReadOnly: `${ELASTICSEARCH_DOCS}ilm-readonly.html`, + ilmRollover: `${ELASTICSEARCH_DOCS}ilm-rollover.html`, + ilmSearchableSnapshot: `${ELASTICSEARCH_DOCS}ilm-searchable-snapshot.html`, + ilmSetPriority: `${ELASTICSEARCH_DOCS}ilm-set-priority.html`, + ilmShrink: `${ELASTICSEARCH_DOCS}ilm-shrink.html`, + ilmWaitForSnapshot: `${ELASTICSEARCH_DOCS}ilm-wait-for-snapshot.html`, indexModules: `${ELASTICSEARCH_DOCS}index-modules.html`, indexSettings: `${ELASTICSEARCH_DOCS}index-modules.html#index-modules-settings`, indexTemplates: `${ELASTICSEARCH_DOCS}index-templates.html`, @@ -199,16 +210,17 @@ export class DocLinksService { mappingStore: `${ELASTICSEARCH_DOCS}mapping-store.html`, mappingTermVector: `${ELASTICSEARCH_DOCS}term-vector.html`, mappingTypesRemoval: `${ELASTICSEARCH_DOCS}removal-of-types.html`, + migrateIndexAllocationFilters: `${ELASTICSEARCH_DOCS}migrate-index-allocation-filters.html`, nodeRoles: `${ELASTICSEARCH_DOCS}modules-node.html#node-roles`, - remoteClusters: `${ELASTICSEARCH_DOCS}modules-remote-clusters.html`, - remoteClustersProxy: `${ELASTICSEARCH_DOCS}modules-remote-clusters.html#proxy-mode`, - remoteClusersProxySettings: `${ELASTICSEARCH_DOCS}modules-remote-clusters.html#remote-cluster-proxy-settings`, + releaseHighlights: `${ELASTICSEARCH_DOCS}release-highlights.html`, + remoteClusters: `${ELASTICSEARCH_DOCS}remote-clusters.html`, + remoteClustersProxy: `${ELASTICSEARCH_DOCS}remote-clusters.html#proxy-mode`, + remoteClusersProxySettings: `${ELASTICSEARCH_DOCS}remote-clusters-settings.html#remote-cluster-proxy-settings`, scriptParameters: `${ELASTICSEARCH_DOCS}modules-scripting-using.html#prefer-params`, + setupUpgrade: `${ELASTICSEARCH_DOCS}setup-upgrade.html`, + shardAllocationSettings: `${ELASTICSEARCH_DOCS}modules-cluster.html#cluster-shard-allocation-settings`, transportSettings: `${ELASTICSEARCH_DOCS}modules-network.html#common-network-settings`, typesRemoval: `${ELASTICSEARCH_DOCS}removal-of-types.html`, - deprecationLogging: `${ELASTICSEARCH_DOCS}logging.html#deprecation-logging`, - setupUpgrade: `${ELASTICSEARCH_DOCS}setup-upgrade.html`, - releaseHighlights: `${ELASTICSEARCH_DOCS}release-highlights.html`, }, siem: { guide: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/index.html`, @@ -241,6 +253,7 @@ export class DocLinksService { kibanaSearchSettings: `${KIBANA_DOCS}advanced-options.html#kibana-search-settings`, visualizationSettings: `${KIBANA_DOCS}advanced-options.html#kibana-visualization-settings`, timelionSettings: `${KIBANA_DOCS}advanced-options.html#kibana-timelion-settings`, + savedObjectsApiList: `${KIBANA_DOCS}saved-objects-api.html#saved-objects-api`, }, ml: { guide: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/index.html`, @@ -333,7 +346,7 @@ export class DocLinksService { elasticsearchSettings: `${ELASTICSEARCH_DOCS}security-settings.html`, elasticsearchEnableSecurity: `${ELASTICSEARCH_DOCS}configuring-stack-security.html`, indicesPrivileges: `${ELASTICSEARCH_DOCS}security-privileges.html#privileges-list-indices`, - kibanaTLS: `${KIBANA_DOCS}configuring-tls.html`, + kibanaTLS: `${ELASTICSEARCH_DOCS}security-basic-setup.html#encrypt-internode-communication`, kibanaPrivileges: `${KIBANA_DOCS}kibana-privileges.html`, mappingRoles: `${ELASTICSEARCH_DOCS}mapping-roles.html`, mappingRolesFieldRules: `${ELASTICSEARCH_DOCS}role-mapping-resources.html#mapping-roles-rule-field`, @@ -387,7 +400,7 @@ export class DocLinksService { }, snapshotRestore: { guide: `${KIBANA_DOCS}snapshot-repositories.html`, - changeIndexSettings: `${ELASTICSEARCH_DOCS}snapshots-restore-snapshot.html#change-index-settings-during-restore`, + changeIndexSettings: `${ELASTICSEARCH_DOCS}index-modules.html`, createSnapshot: `${ELASTICSEARCH_DOCS}snapshots-take-snapshot.html`, getSnapshot: `${ELASTICSEARCH_DOCS}get-snapshot-api.html`, registerSharedFileSystem: `${ELASTICSEARCH_DOCS}snapshots-register-repository.html#snapshots-filesystem-repository`, @@ -395,6 +408,7 @@ export class DocLinksService { registerUrl: `${ELASTICSEARCH_DOCS}snapshots-register-repository.html#snapshots-read-only-repository`, restoreSnapshot: `${ELASTICSEARCH_DOCS}snapshots-restore-snapshot.html`, restoreSnapshotApi: `${ELASTICSEARCH_DOCS}restore-snapshot-api.html#restore-snapshot-api-request-body`, + searchableSnapshotSharedCache: `${ELASTICSEARCH_DOCS}searchable-snapshots.html#searchable-snapshots-shared-cache`, }, ingest: { append: `${ELASTICSEARCH_DOCS}append-processor.html`, @@ -412,6 +426,7 @@ export class DocLinksService { fail: `${ELASTICSEARCH_DOCS}fail-processor.html`, foreach: `${ELASTICSEARCH_DOCS}foreach-processor.html`, geoIp: `${ELASTICSEARCH_DOCS}geoip-processor.html`, + geoMatch: `${ELASTICSEARCH_DOCS}geo-match-enrich-policy-type.html`, grok: `${ELASTICSEARCH_DOCS}grok-processor.html`, gsub: `${ELASTICSEARCH_DOCS}gsub-processor.html`, htmlString: `${ELASTICSEARCH_DOCS}htmlstrip-processor.html`, diff --git a/src/core/server/elasticsearch/deprecations/deprecation_provider.ts b/src/core/server/elasticsearch/deprecations/deprecation_provider.ts deleted file mode 100644 index d085af0d96008..0000000000000 --- a/src/core/server/elasticsearch/deprecations/deprecation_provider.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { RegisterDeprecationsConfig } from '../../deprecations'; -import { getScriptingDisabledDeprecations } from './scripting_disabled_deprecation'; - -export const getElasticsearchDeprecationsProvider = (): RegisterDeprecationsConfig => { - return { - getDeprecations: async (context) => { - return [...(await getScriptingDisabledDeprecations({ esClient: context.esClient }))]; - }, - }; -}; diff --git a/src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.test.ts b/src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.test.ts deleted file mode 100644 index 1be73310be691..0000000000000 --- a/src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { isInlineScriptingDisabledMock } from './scripting_disabled_deprecation.test.mocks'; -import { elasticsearchServiceMock } from '../../elasticsearch/elasticsearch_service.mock'; -import { getScriptingDisabledDeprecations } from './scripting_disabled_deprecation'; - -describe('getScriptingDisabledDeprecations', () => { - let esClient: ReturnType; - - beforeEach(() => { - esClient = elasticsearchServiceMock.createScopedClusterClient(); - }); - - afterEach(() => { - isInlineScriptingDisabledMock.mockReset(); - }); - - it('calls `isInlineScriptingDisabled` with the correct arguments', async () => { - await getScriptingDisabledDeprecations({ - esClient, - }); - - expect(isInlineScriptingDisabledMock).toHaveBeenCalledTimes(1); - expect(isInlineScriptingDisabledMock).toHaveBeenCalledWith({ - client: esClient.asInternalUser, - }); - }); - - it('returns no deprecations if scripting is not disabled', async () => { - isInlineScriptingDisabledMock.mockResolvedValue(false); - - const deprecations = await getScriptingDisabledDeprecations({ - esClient, - }); - - expect(deprecations).toHaveLength(0); - }); - - it('returns a deprecation if scripting is disabled', async () => { - isInlineScriptingDisabledMock.mockResolvedValue(true); - - const deprecations = await getScriptingDisabledDeprecations({ - esClient, - }); - - expect(deprecations).toHaveLength(1); - expect(deprecations[0]).toEqual({ - title: expect.any(String), - message: expect.any(String), - level: 'critical', - requireRestart: false, - correctiveActions: { - manualSteps: expect.any(Array), - }, - }); - }); -}); diff --git a/src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.ts b/src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.ts deleted file mode 100644 index d1e64b8faeeab..0000000000000 --- a/src/core/server/elasticsearch/deprecations/scripting_disabled_deprecation.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; -import type { DeprecationsDetails } from '../../deprecations'; -import { IScopedClusterClient } from '../../elasticsearch'; -import { isInlineScriptingDisabled } from './is_scripting_disabled'; - -interface GetScriptingDisabledDeprecations { - esClient: IScopedClusterClient; -} - -export const getScriptingDisabledDeprecations = async ({ - esClient, -}: GetScriptingDisabledDeprecations): Promise => { - const deprecations: DeprecationsDetails[] = []; - if (await isInlineScriptingDisabled({ client: esClient.asInternalUser })) { - deprecations.push({ - title: i18n.translate('core.elasticsearch.deprecations.scriptingDisabled.title', { - defaultMessage: 'Inline scripting is disabled on elasticsearch', - }), - message: i18n.translate('core.elasticsearch.deprecations.scriptingDisabled.message', { - defaultMessage: - 'Starting in 8.0, Kibana will require inline scripting to be enabled,' + - 'and will fail to start otherwise.', - }), - level: 'critical', - requireRestart: false, - correctiveActions: { - manualSteps: [ - i18n.translate('core.elasticsearch.deprecations.scriptingDisabled.manualSteps.1', { - defaultMessage: 'Set `script.allowed_types=inline` in your elasticsearch config ', - }), - ], - }, - }); - } - return deprecations; -}; diff --git a/src/core/server/elasticsearch/elasticsearch_service.test.mocks.ts b/src/core/server/elasticsearch/elasticsearch_service.test.mocks.ts index b1a60019a801f..0ac23c1b37cf6 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.test.mocks.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.test.mocks.ts @@ -8,3 +8,8 @@ export const MockClusterClient = jest.fn(); jest.mock('./client/cluster_client', () => ({ ClusterClient: MockClusterClient })); + +export const isScriptingEnabledMock = jest.fn(); +jest.doMock('./is_scripting_enabled', () => ({ + isInlineScriptingEnabled: isScriptingEnabledMock, +})); diff --git a/src/core/server/elasticsearch/elasticsearch_service.test.ts b/src/core/server/elasticsearch/elasticsearch_service.test.ts index d10fec01697a8..3b75d19b80a10 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.test.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.test.ts @@ -16,8 +16,9 @@ jest.mock('./version_check/ensure_es_version', () => ({ pollEsNodesVersion: jest.fn(), })); +import { MockClusterClient, isScriptingEnabledMock } from './elasticsearch_service.test.mocks'; + import type { NodesVersionCompatibility } from './version_check/ensure_es_version'; -import { MockClusterClient } from './elasticsearch_service.test.mocks'; import { BehaviorSubject } from 'rxjs'; import { first } from 'rxjs/operators'; import { REPO_ROOT } from '@kbn/dev-utils'; @@ -30,7 +31,6 @@ import { executionContextServiceMock } from '../execution_context/execution_cont import { configSchema, ElasticsearchConfig } from './elasticsearch_config'; import { ElasticsearchService, SetupDeps } from './elasticsearch_service'; import { elasticsearchClientMock } from './client/mocks'; -import { deprecationsServiceMock } from '../deprecations/deprecations_service.mock'; import { duration } from 'moment'; import { isValidConnection as isValidConnectionMock } from './is_valid_connection'; import { pollEsNodesVersion as pollEsNodesVersionMocked } from './version_check/ensure_es_version'; @@ -50,15 +50,11 @@ let coreContext: CoreContext; let mockClusterClientInstance: ReturnType; let mockConfig$: BehaviorSubject; let setupDeps: SetupDeps; -let deprecationsSetup: ReturnType; beforeEach(() => { - deprecationsSetup = deprecationsServiceMock.createInternalSetupContract(); - setupDeps = { http: httpServiceMock.createInternalSetupContract(), executionContext: executionContextServiceMock.createInternalSetupContract(), - deprecations: deprecationsSetup, }; env = Env.createDefault(REPO_ROOT, getEnvOptions()); @@ -78,15 +74,20 @@ beforeEach(() => { coreContext = { coreId: Symbol(), env, logger, configService: configService as any }; elasticsearchService = new ElasticsearchService(coreContext); - MockClusterClient.mockClear(); mockClusterClientInstance = elasticsearchClientMock.createCustomClusterClient(); MockClusterClient.mockImplementation(() => mockClusterClientInstance); + isScriptingEnabledMock.mockResolvedValue(true); + // @ts-expect-error TS does not get that `pollEsNodesVersion` is mocked pollEsNodesVersionMocked.mockImplementation(pollEsNodesVersionActual); }); -afterEach(() => jest.clearAllMocks()); +afterEach(() => { + jest.clearAllMocks(); + MockClusterClient.mockClear(); + isScriptingEnabledMock.mockReset(); +}); describe('#preboot', () => { describe('#config', () => { @@ -181,22 +182,6 @@ describe('#setup', () => { ); }); - it('registers its deprecation provider', async () => { - const registry = deprecationsServiceMock.createSetupContract(); - - deprecationsSetup.getRegistry.mockReturnValue(registry); - - await elasticsearchService.setup(setupDeps); - - expect(deprecationsSetup.getRegistry).toHaveBeenCalledTimes(1); - expect(deprecationsSetup.getRegistry).toHaveBeenCalledWith('elasticsearch'); - - expect(registry.registerDeprecations).toHaveBeenCalledTimes(1); - expect(registry.registerDeprecations).toHaveBeenCalledWith({ - getDeprecations: expect.any(Function), - }); - }); - it('esNodeVersionCompatibility$ only starts polling when subscribed to', async (done) => { const mockedClient = mockClusterClientInstance.asInternalUser; mockedClient.nodes.info.mockImplementation(() => @@ -302,6 +287,39 @@ describe('#start', () => { }); }); + describe('isInlineScriptingEnabled', () => { + it('does not throw error when scripting is enabled', async () => { + isScriptingEnabledMock.mockResolvedValue(true); + + await elasticsearchService.setup(setupDeps); + expect(isScriptingEnabledMock).not.toHaveBeenCalled(); + + await expect(elasticsearchService.start()).resolves.toBeDefined(); + expect(isScriptingEnabledMock).toHaveBeenCalledTimes(1); + }); + + it('throws an error if scripting is disabled', async () => { + isScriptingEnabledMock.mockResolvedValue(false); + + await elasticsearchService.setup(setupDeps); + + await expect(elasticsearchService.start()).rejects.toThrowError( + 'Inline scripting is disabled' + ); + }); + + it('does not throw error when `skipStartupConnectionCheck` is true', async () => { + isScriptingEnabledMock.mockResolvedValue(false); + mockConfig$.next({ + ...(await mockConfig$.pipe(first()).toPromise()), + skipStartupConnectionCheck: true, + }); + + await elasticsearchService.setup(setupDeps); + await expect(elasticsearchService.start()).resolves.toBeDefined(); + }); + }); + describe('#createClient', () => { it('allows to specify config properties', async () => { await elasticsearchService.setup(setupDeps); diff --git a/src/core/server/elasticsearch/elasticsearch_service.ts b/src/core/server/elasticsearch/elasticsearch_service.ts index 09c96696b7985..014fa38646275 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.ts @@ -18,7 +18,6 @@ import { ClusterClient, ElasticsearchClientConfig } from './client'; import { ElasticsearchConfig, ElasticsearchConfigType } from './elasticsearch_config'; import type { InternalHttpServiceSetup, GetAuthHeaders } from '../http'; import type { InternalExecutionContextSetup, IExecutionContext } from '../execution_context'; -import type { InternalDeprecationsServiceSetup } from '../deprecations'; import { InternalElasticsearchServicePreboot, InternalElasticsearchServiceSetup, @@ -28,11 +27,10 @@ import type { NodesVersionCompatibility } from './version_check/ensure_es_versio import { pollEsNodesVersion } from './version_check/ensure_es_version'; import { calculateStatus$ } from './status'; import { isValidConnection } from './is_valid_connection'; -import { getElasticsearchDeprecationsProvider } from './deprecations'; +import { isInlineScriptingEnabled } from './is_scripting_enabled'; export interface SetupDeps { http: InternalHttpServiceSetup; - deprecations: InternalDeprecationsServiceSetup; executionContext: InternalExecutionContextSetup; } @@ -82,10 +80,6 @@ export class ElasticsearchService this.executionContextClient = deps.executionContext; this.client = this.createClusterClient('data', config); - deps.deprecations - .getRegistry('elasticsearch') - .registerDeprecations(getElasticsearchDeprecationsProvider()); - const esNodesCompatibility$ = pollEsNodesVersion({ internalClient: this.client.asInternalUser, log: this.log, @@ -122,6 +116,18 @@ export class ElasticsearchService if (!config.skipStartupConnectionCheck) { // Ensure that the connection is established and the product is valid before moving on await isValidConnection(this.esNodesCompatibility$); + + // Ensure inline scripting is enabled on the ES cluster + const scriptingEnabled = await isInlineScriptingEnabled({ + client: this.client.asInternalUser, + }); + if (!scriptingEnabled) { + throw new Error( + 'Inline scripting is disabled on the Elasticsearch cluster, and is mandatory for Kibana to function. ' + + 'Please enabled inline scripting, then restart Kibana. ' + + 'Refer to https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting-security.html for more info.' + ); + } } return { diff --git a/src/core/server/elasticsearch/integration_tests/is_scripting_disabled.test.ts b/src/core/server/elasticsearch/integration_tests/is_scripting_enabled.test.ts similarity index 63% rename from src/core/server/elasticsearch/integration_tests/is_scripting_disabled.test.ts rename to src/core/server/elasticsearch/integration_tests/is_scripting_enabled.test.ts index 0d235ff2429e4..501193a833f27 100644 --- a/src/core/server/elasticsearch/integration_tests/is_scripting_disabled.test.ts +++ b/src/core/server/elasticsearch/integration_tests/is_scripting_enabled.test.ts @@ -11,9 +11,9 @@ import { TestElasticsearchUtils, TestKibanaUtils, } from '../../../test_helpers/kbn_server'; -import { isInlineScriptingDisabled } from '../deprecations/is_scripting_disabled'; +import { isInlineScriptingEnabled } from '../is_scripting_enabled'; -describe('isInlineScriptingDisabled', () => { +describe('isInlineScriptingEnabled', () => { let esServer: TestElasticsearchUtils; let kibanaServer: TestKibanaUtils; @@ -33,6 +33,13 @@ describe('isInlineScriptingDisabled', () => { es: { esArgs, }, + kbn: { + elasticsearch: { + // required for the server to start without throwing + // as inline scripting is disabled in some tests + skipStartupConnectionCheck: true, + }, + }, }, }); @@ -40,43 +47,43 @@ describe('isInlineScriptingDisabled', () => { kibanaServer = await startKibana(); }; - it('returns false when `script.allowed_types` is unset', async () => { + it('returns true when `script.allowed_types` is unset', async () => { await startServers({ esArgs: [] }); - const disabled = await isInlineScriptingDisabled({ + const enabled = await isInlineScriptingEnabled({ client: kibanaServer.coreStart.elasticsearch.client.asInternalUser, }); - expect(disabled).toEqual(false); + expect(enabled).toEqual(true); }); - it('returns false when `script.allowed_types` is `inline`', async () => { + it('returns true when `script.allowed_types` is `inline`', async () => { await startServers({ esArgs: ['script.allowed_types=inline'] }); - const disabled = await isInlineScriptingDisabled({ + const enabled = await isInlineScriptingEnabled({ client: kibanaServer.coreStart.elasticsearch.client.asInternalUser, }); - expect(disabled).toEqual(false); + expect(enabled).toEqual(true); }); - it('returns true when `script.allowed_types` is `stored`', async () => { + it('returns false when `script.allowed_types` is `stored`', async () => { await startServers({ esArgs: ['script.allowed_types=stored'] }); - const disabled = await isInlineScriptingDisabled({ + const enabled = await isInlineScriptingEnabled({ client: kibanaServer.coreStart.elasticsearch.client.asInternalUser, }); - expect(disabled).toEqual(true); + expect(enabled).toEqual(false); }); - it('returns true when `script.allowed_types` is `none', async () => { + it('returns false when `script.allowed_types` is `none', async () => { await startServers({ esArgs: ['script.allowed_types=none'] }); - const disabled = await isInlineScriptingDisabled({ + const enabled = await isInlineScriptingEnabled({ client: kibanaServer.coreStart.elasticsearch.client.asInternalUser, }); - expect(disabled).toEqual(true); + expect(enabled).toEqual(false); }); }); diff --git a/src/core/server/elasticsearch/deprecations/is_scripting_disabled.test.ts b/src/core/server/elasticsearch/is_scripting_enabled.test.ts similarity index 66% rename from src/core/server/elasticsearch/deprecations/is_scripting_disabled.test.ts rename to src/core/server/elasticsearch/is_scripting_enabled.test.ts index 90c5f022bd41c..6dfb4b13edb9f 100644 --- a/src/core/server/elasticsearch/deprecations/is_scripting_disabled.test.ts +++ b/src/core/server/elasticsearch/is_scripting_enabled.test.ts @@ -7,10 +7,10 @@ */ import { estypes } from '@elastic/elasticsearch'; -import { elasticsearchServiceMock } from '../../elasticsearch/elasticsearch_service.mock'; -import { isInlineScriptingDisabled } from './is_scripting_disabled'; +import { elasticsearchServiceMock } from './elasticsearch_service.mock'; +import { isInlineScriptingEnabled } from './is_scripting_enabled'; -describe('isInlineScriptingDisabled', () => { +describe('isInlineScriptingEnabled', () => { let client: ReturnType; beforeEach(() => { @@ -23,17 +23,17 @@ describe('isInlineScriptingDisabled', () => { ); }; - it('returns `false` if all settings are empty', async () => { + it('returns `true` if all settings are empty', async () => { mockSettingsValue({ transient: {}, persistent: {}, defaults: {}, }); - expect(await isInlineScriptingDisabled({ client })).toEqual(false); + expect(await isInlineScriptingEnabled({ client })).toEqual(true); }); - it('returns `false` if `defaults.script.allowed_types` is `inline`', async () => { + it('returns `true` if `defaults.script.allowed_types` is `inline`', async () => { mockSettingsValue({ transient: {}, persistent: {}, @@ -42,10 +42,10 @@ describe('isInlineScriptingDisabled', () => { }, }); - expect(await isInlineScriptingDisabled({ client })).toEqual(false); + expect(await isInlineScriptingEnabled({ client })).toEqual(true); }); - it('returns `true` if `defaults.script.allowed_types` is `none`', async () => { + it('returns `false` if `defaults.script.allowed_types` is `none`', async () => { mockSettingsValue({ transient: {}, persistent: {}, @@ -54,10 +54,10 @@ describe('isInlineScriptingDisabled', () => { }, }); - expect(await isInlineScriptingDisabled({ client })).toEqual(true); + expect(await isInlineScriptingEnabled({ client })).toEqual(false); }); - it('returns `true` if `defaults.script.allowed_types` is `stored`', async () => { + it('returns `false` if `defaults.script.allowed_types` is `stored`', async () => { mockSettingsValue({ transient: {}, persistent: {}, @@ -66,7 +66,7 @@ describe('isInlineScriptingDisabled', () => { }, }); - expect(await isInlineScriptingDisabled({ client })).toEqual(true); + expect(await isInlineScriptingEnabled({ client })).toEqual(false); }); it('respect the persistent->defaults priority', async () => { @@ -80,7 +80,7 @@ describe('isInlineScriptingDisabled', () => { }, }); - expect(await isInlineScriptingDisabled({ client })).toEqual(false); + expect(await isInlineScriptingEnabled({ client })).toEqual(true); }); it('respect the transient->persistent priority', async () => { @@ -94,6 +94,6 @@ describe('isInlineScriptingDisabled', () => { defaults: {}, }); - expect(await isInlineScriptingDisabled({ client })).toEqual(true); + expect(await isInlineScriptingEnabled({ client })).toEqual(false); }); }); diff --git a/src/core/server/elasticsearch/deprecations/is_scripting_disabled.ts b/src/core/server/elasticsearch/is_scripting_enabled.ts similarity index 80% rename from src/core/server/elasticsearch/deprecations/is_scripting_disabled.ts rename to src/core/server/elasticsearch/is_scripting_enabled.ts index 9f140c71da8a0..31276a8c72aef 100644 --- a/src/core/server/elasticsearch/deprecations/is_scripting_disabled.ts +++ b/src/core/server/elasticsearch/is_scripting_enabled.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ -import { ElasticsearchClient } from '../../elasticsearch'; +import { ElasticsearchClient } from './client'; const scriptAllowedTypesKey = 'script.allowed_types'; -export const isInlineScriptingDisabled = async ({ +export const isInlineScriptingEnabled = async ({ client, }: { client: ElasticsearchClient; @@ -28,7 +28,5 @@ export const isInlineScriptingDisabled = async ({ []; // when unspecified, the setting as a default `[]` value that means that both scriptings are allowed. - const scriptAllowed = scriptAllowedTypes.length === 0 || scriptAllowedTypes.includes('inline'); - - return !scriptAllowed; + return scriptAllowedTypes.length === 0 || scriptAllowedTypes.includes('inline'); }; diff --git a/src/core/server/http/router/socket.test.ts b/src/core/server/http/router/socket.test.ts index 60c91786767a6..389c08825d51b 100644 --- a/src/core/server/http/router/socket.test.ts +++ b/src/core/server/http/router/socket.test.ts @@ -92,7 +92,7 @@ describe('KibanaSocket', () => { }); const socket = new KibanaSocket(tlsSocket); - expect(socket.renegotiate({})).resolves.toBe(result); + await expect(socket.renegotiate({})).rejects.toBe(result); expect(spy).toBeCalledTimes(1); }); diff --git a/src/core/server/saved_objects/migrations/core/migration_context.test.ts b/src/core/server/saved_objects/migrations/core/migration_context.test.ts index 240b41266abb6..27aae5968ba88 100644 --- a/src/core/server/saved_objects/migrations/core/migration_context.test.ts +++ b/src/core/server/saved_objects/migrations/core/migration_context.test.ts @@ -74,4 +74,18 @@ describe('disableUnknownTypeMappingFields', () => { }, }); }); + + it('does not fail if the source mapping does not have `properties` defined', () => { + const missingPropertiesMappings = { + ...sourceMappings, + properties: undefined, + }; + const result = disableUnknownTypeMappingFields( + activeMappings, + // @ts-expect-error `properties` should not be undefined + missingPropertiesMappings + ); + + expect(Object.keys(result.properties)).toEqual(['known_type']); + }); }); diff --git a/src/core/server/saved_objects/migrations/core/migration_context.ts b/src/core/server/saved_objects/migrations/core/migration_context.ts index d7f7aff45a470..96c47bcf38d0a 100644 --- a/src/core/server/saved_objects/migrations/core/migration_context.ts +++ b/src/core/server/saved_objects/migrations/core/migration_context.ts @@ -154,7 +154,7 @@ export function disableUnknownTypeMappingFields( ): IndexMapping { const targetTypes = Object.keys(activeMappings.properties); - const disabledTypesProperties = Object.keys(sourceMappings.properties) + const disabledTypesProperties = Object.keys(sourceMappings.properties ?? {}) .filter((sourceType) => { const isObjectType = 'properties' in sourceMappings.properties[sourceType]; // Only Object/Nested datatypes can be excluded from the field count by diff --git a/src/core/server/saved_objects/migrationsv2/README.md b/src/core/server/saved_objects/migrationsv2/README.md index 5121e66052f40..a6b8e01a3dc6c 100644 --- a/src/core/server/saved_objects/migrationsv2/README.md +++ b/src/core/server/saved_objects/migrationsv2/README.md @@ -36,7 +36,7 @@ - [REINDEX_SOURCE_TO_TEMP_READ](#reindex_source_to_temp_read) - [Next action](#next-action-11) - [New control state](#new-control-state-11) - - [REINDEX_SOURCE_TO_TEMP_INDEX](#reindex_source_to_temp_index) + - [REINDEX_SOURCE_TO_TEMP_TRANSFORM](#REINDEX_SOURCE_TO_TEMP_TRANSFORM) - [Next action](#next-action-12) - [New control state](#new-control-state-12) - [REINDEX_SOURCE_TO_TEMP_INDEX_BULK](#reindex_source_to_temp_index_bulk) @@ -284,11 +284,11 @@ Read the next batch of outdated documents from the source index by using search ### New control state 1. If the batch contained > 0 documents - → `REINDEX_SOURCE_TO_TEMP_INDEX` + → `REINDEX_SOURCE_TO_TEMP_TRANSFORM` 2. If there are no more documents returned → `REINDEX_SOURCE_TO_TEMP_CLOSE_PIT` -## REINDEX_SOURCE_TO_TEMP_INDEX +## REINDEX_SOURCE_TO_TEMP_TRANSFORM ### Next action `transformRawDocs` @@ -357,7 +357,7 @@ documents. If another instance has a disabled plugin it will reindex that plugin's documents without transforming them. Because this instance doesn't know which plugins were disabled by the instance that performed the -`REINDEX_SOURCE_TO_TEMP_INDEX` step, we need to search for outdated documents +`REINDEX_SOURCE_TO_TEMP_TRANSFORM` step, we need to search for outdated documents and transform them to ensure that everything is up to date. ### New control state diff --git a/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts b/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts index 936746ddc6930..32d12e13434aa 100644 --- a/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts +++ b/src/core/server/saved_objects/migrationsv2/actions/integration_tests/actions.test.ts @@ -802,7 +802,9 @@ describe('migration actions', () => { } `); }); - it('resolves left wait_for_task_completion_timeout when the task does not finish within the timeout', async () => { + + // FLAKY https://github.com/elastic/kibana/issues/113012 + it.skip('resolves left wait_for_task_completion_timeout when the task does not finish within the timeout', async () => { const res = (await reindex({ client, sourceIndex: 'existing_index_with_docs', diff --git a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.ts b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.ts index d4ad724911277..3a5e592a8b9bf 100644 --- a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.ts +++ b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.ts @@ -13,7 +13,7 @@ import type { ElasticsearchClient } from '../../elasticsearch'; import { getErrorMessage, getRequestDebugMeta } from '../../elasticsearch'; import { Model, Next, stateActionMachine } from './state_action_machine'; import { cleanup } from './migrations_state_machine_cleanup'; -import { ReindexSourceToTempIndex, ReindexSourceToTempIndexBulk, State } from './types'; +import { ReindexSourceToTempTransform, ReindexSourceToTempIndexBulk, State } from './types'; import { SavedObjectsRawDoc } from '../serialization'; interface StateTransitionLogMeta extends LogMeta { @@ -115,7 +115,9 @@ export async function migrationStateActionMachine({ const redactedNewState = { ...newState, ...{ - outdatedDocuments: ((newState as ReindexSourceToTempIndex).outdatedDocuments ?? []).map( + outdatedDocuments: ( + (newState as ReindexSourceToTempTransform).outdatedDocuments ?? [] + ).map( (doc) => ({ _id: doc._id, diff --git a/src/core/server/saved_objects/migrationsv2/model/model.test.ts b/src/core/server/saved_objects/migrationsv2/model/model.test.ts index 033a18b488841..3e48a7147bffd 100644 --- a/src/core/server/saved_objects/migrationsv2/model/model.test.ts +++ b/src/core/server/saved_objects/migrationsv2/model/model.test.ts @@ -20,7 +20,7 @@ import type { ReindexSourceToTempOpenPit, ReindexSourceToTempRead, ReindexSourceToTempClosePit, - ReindexSourceToTempIndex, + ReindexSourceToTempTransform, RefreshTarget, UpdateTargetMappingsState, UpdateTargetMappingsWaitForTaskState, @@ -962,7 +962,7 @@ describe('migrations v2 model', () => { progress: createInitialProgress(), }; - it('REINDEX_SOURCE_TO_TEMP_READ -> REINDEX_SOURCE_TO_TEMP_INDEX if the index has outdated documents to reindex', () => { + it('REINDEX_SOURCE_TO_TEMP_READ -> REINDEX_SOURCE_TO_TEMP_TRANSFORM if the index has outdated documents to reindex', () => { const outdatedDocuments = [{ _id: '1', _source: { type: 'vis' } }]; const lastHitSortValue = [123456]; const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_READ'> = Either.right({ @@ -970,8 +970,8 @@ describe('migrations v2 model', () => { lastHitSortValue, totalHits: 1, }); - const newState = model(state, res) as ReindexSourceToTempIndex; - expect(newState.controlState).toBe('REINDEX_SOURCE_TO_TEMP_INDEX'); + const newState = model(state, res) as ReindexSourceToTempTransform; + expect(newState.controlState).toBe('REINDEX_SOURCE_TO_TEMP_TRANSFORM'); expect(newState.outdatedDocuments).toBe(outdatedDocuments); expect(newState.lastHitSortValue).toBe(lastHitSortValue); expect(newState.progress.processed).toBe(undefined); @@ -1032,16 +1032,16 @@ describe('migrations v2 model', () => { it('REINDEX_SOURCE_TO_TEMP_CLOSE_PIT -> SET_TEMP_WRITE_BLOCK if action succeeded', () => { const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_CLOSE_PIT'> = Either.right({}); - const newState = model(state, res) as ReindexSourceToTempIndex; + const newState = model(state, res) as ReindexSourceToTempTransform; expect(newState.controlState).toBe('SET_TEMP_WRITE_BLOCK'); expect(newState.sourceIndex).toEqual(state.sourceIndex); }); }); - describe('REINDEX_SOURCE_TO_TEMP_INDEX', () => { - const state: ReindexSourceToTempIndex = { + describe('REINDEX_SOURCE_TO_TEMP_TRANSFORM', () => { + const state: ReindexSourceToTempTransform = { ...baseState, - controlState: 'REINDEX_SOURCE_TO_TEMP_INDEX', + controlState: 'REINDEX_SOURCE_TO_TEMP_TRANSFORM', outdatedDocuments: [], versionIndexReadyActions: Option.none, sourceIndex: Option.some('.kibana') as Option.Some, @@ -1059,8 +1059,8 @@ describe('migrations v2 model', () => { }, ] as SavedObjectsRawDoc[]; - it('REINDEX_SOURCE_TO_TEMP_INDEX -> REINDEX_SOURCE_TO_TEMP_INDEX_BULK if action succeeded', () => { - const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX'> = Either.right({ + it('REINDEX_SOURCE_TO_TEMP_TRANSFORM -> REINDEX_SOURCE_TO_TEMP_INDEX_BULK if action succeeded', () => { + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_TRANSFORM'> = Either.right({ processedDocs, }); const newState = model(state, res) as ReindexSourceToTempIndexBulk; @@ -1071,7 +1071,7 @@ describe('migrations v2 model', () => { }); it('increments the progress.processed counter', () => { - const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX'> = Either.right({ + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_TRANSFORM'> = Either.right({ processedDocs, }); @@ -1089,8 +1089,8 @@ describe('migrations v2 model', () => { expect(newState.progress.processed).toBe(2); }); - it('REINDEX_SOURCE_TO_TEMP_INDEX -> REINDEX_SOURCE_TO_TEMP_READ if action succeeded but we have carried through previous failures', () => { - const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX'> = Either.right({ + it('REINDEX_SOURCE_TO_TEMP_TRANSFORM -> REINDEX_SOURCE_TO_TEMP_READ if action succeeded but we have carried through previous failures', () => { + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_TRANSFORM'> = Either.right({ processedDocs, }); const testState = { @@ -1098,15 +1098,15 @@ describe('migrations v2 model', () => { corruptDocumentIds: ['a:b'], transformErrors: [], }; - const newState = model(testState, res) as ReindexSourceToTempIndex; + const newState = model(testState, res) as ReindexSourceToTempTransform; expect(newState.controlState).toEqual('REINDEX_SOURCE_TO_TEMP_READ'); expect(newState.corruptDocumentIds.length).toEqual(1); expect(newState.transformErrors.length).toEqual(0); expect(newState.progress.processed).toBe(0); }); - it('REINDEX_SOURCE_TO_TEMP_INDEX -> REINDEX_SOURCE_TO_TEMP_READ when response is left documents_transform_failed', () => { - const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX'> = Either.left({ + it('REINDEX_SOURCE_TO_TEMP_TRANSFORM -> REINDEX_SOURCE_TO_TEMP_READ when response is left documents_transform_failed', () => { + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_TRANSFORM'> = Either.left({ type: 'documents_transform_failed', corruptDocumentIds: ['a:b'], transformErrors: [], diff --git a/src/core/server/saved_objects/migrationsv2/model/model.ts b/src/core/server/saved_objects/migrationsv2/model/model.ts index 8aa3d7b83b295..5d8862e48df1a 100644 --- a/src/core/server/saved_objects/migrationsv2/model/model.ts +++ b/src/core/server/saved_objects/migrationsv2/model/model.ts @@ -446,7 +446,7 @@ export const model = (currentState: State, resW: ResponseType): if (res.right.outdatedDocuments.length > 0) { return { ...stateP, - controlState: 'REINDEX_SOURCE_TO_TEMP_INDEX', + controlState: 'REINDEX_SOURCE_TO_TEMP_TRANSFORM', outdatedDocuments: res.right.outdatedDocuments, lastHitSortValue: res.right.lastHitSortValue, progress, @@ -489,11 +489,11 @@ export const model = (currentState: State, resW: ResponseType): } else { throwBadResponse(stateP, res); } - } else if (stateP.controlState === 'REINDEX_SOURCE_TO_TEMP_INDEX') { + } else if (stateP.controlState === 'REINDEX_SOURCE_TO_TEMP_TRANSFORM') { // We follow a similar control flow as for // outdated document search -> outdated document transform -> transform documents bulk index // collecting issues along the way rather than failing - // REINDEX_SOURCE_TO_TEMP_INDEX handles the document transforms + // REINDEX_SOURCE_TO_TEMP_TRANSFORM handles the document transforms const res = resW as ExcludeRetryableEsError>; // Increment the processed documents, no matter what the results are. diff --git a/src/core/server/saved_objects/migrationsv2/next.ts b/src/core/server/saved_objects/migrationsv2/next.ts index 3f3714552725b..433c0998f7567 100644 --- a/src/core/server/saved_objects/migrationsv2/next.ts +++ b/src/core/server/saved_objects/migrationsv2/next.ts @@ -12,7 +12,7 @@ import type { ReindexSourceToTempOpenPit, ReindexSourceToTempRead, ReindexSourceToTempClosePit, - ReindexSourceToTempIndex, + ReindexSourceToTempTransform, MarkVersionIndexReady, InitState, LegacyCreateReindexTargetState, @@ -105,7 +105,7 @@ export const nextActionMap = (client: ElasticsearchClient, transformRawDocs: Tra }), REINDEX_SOURCE_TO_TEMP_CLOSE_PIT: (state: ReindexSourceToTempClosePit) => Actions.closePit({ client, pitId: state.sourceIndexPitId }), - REINDEX_SOURCE_TO_TEMP_INDEX: (state: ReindexSourceToTempIndex) => + REINDEX_SOURCE_TO_TEMP_TRANSFORM: (state: ReindexSourceToTempTransform) => Actions.transformDocs({ transformRawDocs, outdatedDocuments: state.outdatedDocuments }), REINDEX_SOURCE_TO_TEMP_INDEX_BULK: (state: ReindexSourceToTempIndexBulk) => Actions.bulkOverwriteTransformedDocuments({ diff --git a/src/core/server/saved_objects/migrationsv2/types.ts b/src/core/server/saved_objects/migrationsv2/types.ts index 49ce12c53aa1a..4f6419930c6cc 100644 --- a/src/core/server/saved_objects/migrationsv2/types.ts +++ b/src/core/server/saved_objects/migrationsv2/types.ts @@ -233,8 +233,8 @@ export interface ReindexSourceToTempClosePit extends PostInitState { readonly sourceIndexPitId: string; } -export interface ReindexSourceToTempIndex extends PostInitState { - readonly controlState: 'REINDEX_SOURCE_TO_TEMP_INDEX'; +export interface ReindexSourceToTempTransform extends PostInitState { + readonly controlState: 'REINDEX_SOURCE_TO_TEMP_TRANSFORM'; readonly outdatedDocuments: SavedObjectsRawDoc[]; readonly sourceIndexPitId: string; readonly lastHitSortValue: number[] | undefined; @@ -434,7 +434,7 @@ export type State = Readonly< | ReindexSourceToTempOpenPit | ReindexSourceToTempRead | ReindexSourceToTempClosePit - | ReindexSourceToTempIndex + | ReindexSourceToTempTransform | ReindexSourceToTempIndexBulk | SetTempWriteBlock | CloneTempToSource diff --git a/src/core/server/saved_objects/saved_objects_type_registry.test.ts b/src/core/server/saved_objects/saved_objects_type_registry.test.ts index 872b61706c526..c86a1a54f14a8 100644 --- a/src/core/server/saved_objects/saved_objects_type_registry.test.ts +++ b/src/core/server/saved_objects/saved_objects_type_registry.test.ts @@ -47,6 +47,59 @@ describe('SavedObjectTypeRegistry', () => { }).toThrowErrorMatchingInlineSnapshot(`"Type 'typeA' is already registered"`); }); + it('throws when `management.visibleInManagement` is specified but `management.importableAndExportable` is undefined or false', () => { + expect(() => { + registry.registerType( + createType({ + name: 'typeA', + management: { + visibleInManagement: true, + }, + }) + ); + }).toThrowErrorMatchingInlineSnapshot( + `"Type typeA: 'management.importableAndExportable' must be 'true' when specifying 'management.visibleInManagement'"` + ); + + expect(() => { + registry.registerType( + createType({ + name: 'typeA', + management: { + visibleInManagement: false, + }, + }) + ); + }).toThrowErrorMatchingInlineSnapshot( + `"Type typeA: 'management.importableAndExportable' must be 'true' when specifying 'management.visibleInManagement'"` + ); + + expect(() => { + registry.registerType( + createType({ + name: 'typeA', + management: { + importableAndExportable: false, + visibleInManagement: false, + }, + }) + ); + }).toThrowErrorMatchingInlineSnapshot( + `"Type typeA: 'management.importableAndExportable' must be 'true' when specifying 'management.visibleInManagement'"` + ); + expect(() => { + registry.registerType( + createType({ + name: 'typeA', + management: { + importableAndExportable: true, + visibleInManagement: false, + }, + }) + ); + }).not.toThrow(); + }); + it('throws when `management.onExport` is specified but `management.importableAndExportable` is undefined or false', () => { expect(() => { registry.registerType( diff --git a/src/core/server/saved_objects/saved_objects_type_registry.ts b/src/core/server/saved_objects/saved_objects_type_registry.ts index ba5960c59239d..444af58eee801 100644 --- a/src/core/server/saved_objects/saved_objects_type_registry.ts +++ b/src/core/server/saved_objects/saved_objects_type_registry.ts @@ -134,5 +134,10 @@ const validateType = ({ name, management }: SavedObjectsType) => { `Type ${name}: 'management.importableAndExportable' must be 'true' when specifying 'management.onExport'` ); } + if (management.visibleInManagement !== undefined && !management.importableAndExportable) { + throw new Error( + `Type ${name}: 'management.importableAndExportable' must be 'true' when specifying 'management.visibleInManagement'` + ); + } } }; diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts index 83f46c521a836..b2a6be38bb526 100644 --- a/src/core/server/saved_objects/types.ts +++ b/src/core/server/saved_objects/types.ts @@ -356,6 +356,15 @@ export interface SavedObjectsTypeManagementDefinition { * Is the type importable or exportable. Defaults to `false`. */ importableAndExportable?: boolean; + /** + * When set to false, the type will not be listed or searchable in the SO management section. + * Main usage of setting this property to false for a type is when objects from the type should + * be included in the export via references or export hooks, but should not directly appear in the SOM. + * Defaults to `true`. + * + * @remarks `importableAndExportable` must be `true` to specify this property. + */ + visibleInManagement?: boolean; /** * The default search field to use for this type. Defaults to `id`. */ diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index ba7973fa1ce06..3c7aa8b992688 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -2751,6 +2751,7 @@ export interface SavedObjectsTypeManagementDefinition { isExportable?: SavedObjectsExportablePredicate; onExport?: SavedObjectsExportTransform; onImport?: SavedObjectsImportHook; + visibleInManagement?: boolean; } // @public diff --git a/src/core/server/server.ts b/src/core/server/server.ts index cd133def69a67..867446484a230 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -218,7 +218,6 @@ export class Server { const elasticsearchServiceSetup = await this.elasticsearch.setup({ http: httpSetup, executionContext: executionContextSetup, - deprecations: deprecationsSetup, }); const metricsSetup = await this.metrics.setup({ http: httpSetup }); diff --git a/src/dev/build/tasks/os_packages/docker_generator/run.ts b/src/dev/build/tasks/os_packages/docker_generator/run.ts index c5a4ff64d2188..21f223a09f60d 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/run.ts +++ b/src/dev/build/tasks/os_packages/docker_generator/run.ts @@ -47,7 +47,7 @@ export async function runDockerGenerator( // General docker var config const license = 'Elastic License'; - const imageTag = 'docker.elastic.co/kibana/kibana'; + const imageTag = `docker.elastic.co/kibana${flags.cloud ? '-ci' : ''}/kibana`; const version = config.getBuildVersion(); const artifactArchitecture = flags.architecture === 'aarch64' ? 'aarch64' : 'x86_64'; const artifactPrefix = `kibana-${version}-linux`; diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 9395c5fdf8834..a61a2618d6428 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -24,6 +24,7 @@ export const storybookAliases = { expression_reveal_image: 'src/plugins/expression_reveal_image/.storybook', expression_shape: 'src/plugins/expression_shape/.storybook', expression_tagcloud: 'src/plugins/chart_expressions/expression_tagcloud/.storybook', + fleet: 'x-pack/plugins/fleet/storybook', infra: 'x-pack/plugins/infra/.storybook', security_solution: 'x-pack/plugins/security_solution/.storybook', ui_actions_enhanced: 'x-pack/plugins/ui_actions_enhanced/.storybook', diff --git a/src/plugins/apm_oss/server/index.ts b/src/plugins/apm_oss/server/index.ts index bf6baf1876074..f2f6777672e33 100644 --- a/src/plugins/apm_oss/server/index.ts +++ b/src/plugins/apm_oss/server/index.ts @@ -10,7 +10,8 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { ConfigDeprecationProvider, PluginInitializerContext } from '../../../core/server'; import { APMOSSPlugin } from './plugin'; -const deprecations: ConfigDeprecationProvider = ({ unused }) => [ +const deprecations: ConfigDeprecationProvider = ({ deprecate, unused }) => [ + deprecate('enabled', '8.0.0'), unused('fleetMode'), unused('indexPattern'), ]; diff --git a/src/plugins/console/server/index.ts b/src/plugins/console/server/index.ts index 736a7e1ae3c97..cd05652c62838 100644 --- a/src/plugins/console/server/index.ts +++ b/src/plugins/console/server/index.ts @@ -16,6 +16,6 @@ export { ConsoleSetup, ConsoleStart } from './types'; export const plugin = (ctx: PluginInitializerContext) => new ConsoleServerPlugin(ctx); export const config: PluginConfigDescriptor = { - deprecations: ({ unused }) => [unused('ssl')], + deprecations: ({ deprecate, unused, rename }) => [deprecate('enabled', '8.0.0'), unused('ssl')], schema: configSchema, }; diff --git a/src/plugins/custom_integrations/README.md b/src/plugins/custom_integrations/README.md new file mode 100755 index 0000000000000..e7af518e21ec1 --- /dev/null +++ b/src/plugins/custom_integrations/README.md @@ -0,0 +1,9 @@ +# customIntegrations + +Register add-data cards + +--- + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment. diff --git a/src/plugins/custom_integrations/common/index.ts b/src/plugins/custom_integrations/common/index.ts new file mode 100755 index 0000000000000..24ed44f3e5cfe --- /dev/null +++ b/src/plugins/custom_integrations/common/index.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const PLUGIN_ID = 'customIntegrations'; +export const PLUGIN_NAME = 'customIntegrations'; + +export interface CategoryCount { + count: number; + id: Category; +} + +export const CATEGORY_DISPLAY = { + aws: 'AWS', + azure: 'Azure', + cloud: 'Cloud', + config_management: 'Config management', + containers: 'Containers', + crm: 'CRM', + custom: 'Custom', + datastore: 'Datastore', + elastic_stack: 'Elastic Stack', + google_cloud: 'Google cloud', + kubernetes: 'Kubernetes', + languages: 'Languages', + message_queue: 'Message queue', + monitoring: 'Monitoring', + network: 'Network', + notification: 'Notification', + os_system: 'OS & System', + productivity: 'Productivity', + security: 'Security', + sample_data: 'Sample data', + support: 'Support', + ticketing: 'Ticketing', + version_control: 'Version control', + web: 'Web', + upload_file: 'Upload a file', + + updates_available: 'Updates available', +}; + +export type Category = keyof typeof CATEGORY_DISPLAY; + +export interface CustomIntegration { + id: string; + title: string; + description: string; + type: 'ui_link'; + uiInternalPath: string; + isBeta: boolean; + icons: Array<{ src: string; type: string }>; + categories: Category[]; + shipper: string; +} + +export const ROUTES_ADDABLECUSTOMINTEGRATIONS = `/api/${PLUGIN_ID}/appendCustomIntegrations`; diff --git a/src/plugins/custom_integrations/jest.config.js b/src/plugins/custom_integrations/jest.config.js new file mode 100644 index 0000000000000..15aed3f602073 --- /dev/null +++ b/src/plugins/custom_integrations/jest.config.js @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/src/plugins/custom_integrations'], + testRunner: 'jasmine2', + coverageDirectory: '/target/kibana-coverage/jest/src/plugins/custom_integrations', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/src/plugins/data/{common,public,server}/**/*.{ts,tsx}'], +}; diff --git a/src/plugins/custom_integrations/kibana.json b/src/plugins/custom_integrations/kibana.json new file mode 100755 index 0000000000000..3a78270d9ef09 --- /dev/null +++ b/src/plugins/custom_integrations/kibana.json @@ -0,0 +1,16 @@ +{ + "id": "customIntegrations", + "version": "1.0.0", + "kibanaVersion": "kibana", + "owner": { + "name": "Fleet", + "githubTeam": "fleet" + }, + "description": "Add custom data integrations so they can be displayed in the Fleet integrations app", + "ui": true, + "server": true, + "extraPublicDirs": [ + "common" + ], + "optionalPlugins": [] +} diff --git a/src/plugins/custom_integrations/public/index.ts b/src/plugins/custom_integrations/public/index.ts new file mode 100755 index 0000000000000..9e979dd6692bc --- /dev/null +++ b/src/plugins/custom_integrations/public/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CustomIntegrationsPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. +export function plugin() { + return new CustomIntegrationsPlugin(); +} +export { CustomIntegrationsSetup, CustomIntegrationsStart } from './types'; diff --git a/src/plugins/saved_objects_management/public/services/service_registry.mock.ts b/src/plugins/custom_integrations/public/mocks.ts similarity index 54% rename from src/plugins/saved_objects_management/public/services/service_registry.mock.ts rename to src/plugins/custom_integrations/public/mocks.ts index 2036f8d1130e7..e6462751368a3 100644 --- a/src/plugins/saved_objects_management/public/services/service_registry.mock.ts +++ b/src/plugins/custom_integrations/public/mocks.ts @@ -6,20 +6,16 @@ * Side Public License, v 1. */ -import { ISavedObjectsManagementServiceRegistry } from './service_registry'; +import { CustomIntegrationsSetup } from './types'; -const createRegistryMock = (): jest.Mocked => { +function createCustomIntegrationsSetup(): jest.Mocked { const mock = { - register: jest.fn(), - all: jest.fn(), - get: jest.fn(), + getAppendCustomIntegrations: jest.fn(), }; - mock.all.mockReturnValue([]); - return mock; -}; +} -export const serviceRegistryMock = { - create: createRegistryMock, +export const customIntegrationsMock = { + createSetup: createCustomIntegrationsSetup, }; diff --git a/src/plugins/custom_integrations/public/plugin.test.ts b/src/plugins/custom_integrations/public/plugin.test.ts new file mode 100644 index 0000000000000..32f25754fe8e0 --- /dev/null +++ b/src/plugins/custom_integrations/public/plugin.test.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CustomIntegrationsPlugin } from './plugin'; + +import { coreMock } from '../../../core/public/mocks'; + +describe('CustomIntegrationsPlugin', () => { + beforeEach(() => {}); + + describe('setup', () => { + let mockCoreSetup: ReturnType; + + beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); + }); + + test('wires up tutorials provider service and returns registerTutorial and addScopedTutorialContextFactory', () => { + const setup = new CustomIntegrationsPlugin().setup(mockCoreSetup); + expect(setup).toHaveProperty('getAppendCustomIntegrations'); + }); + }); +}); diff --git a/src/plugins/custom_integrations/public/plugin.ts b/src/plugins/custom_integrations/public/plugin.ts new file mode 100755 index 0000000000000..821c08ce84e31 --- /dev/null +++ b/src/plugins/custom_integrations/public/plugin.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; +import { CustomIntegrationsSetup, CustomIntegrationsStart } from './types'; +import { CustomIntegration, ROUTES_ADDABLECUSTOMINTEGRATIONS } from '../common'; + +export class CustomIntegrationsPlugin + implements Plugin +{ + public setup(core: CoreSetup): CustomIntegrationsSetup { + // Return methods that should be available to other plugins + return { + async getAppendCustomIntegrations(): Promise { + return core.http.get(ROUTES_ADDABLECUSTOMINTEGRATIONS); + }, + } as CustomIntegrationsSetup; + } + + public start(core: CoreStart): CustomIntegrationsStart { + return {}; + } + + public stop() {} +} diff --git a/src/plugins/custom_integrations/public/types.ts b/src/plugins/custom_integrations/public/types.ts new file mode 100755 index 0000000000000..911194171b4c4 --- /dev/null +++ b/src/plugins/custom_integrations/public/types.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CustomIntegration } from '../common'; + +export interface CustomIntegrationsSetup { + getAppendCustomIntegrations: () => Promise; +} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface CustomIntegrationsStart {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AppPluginStartDependencies {} diff --git a/src/plugins/custom_integrations/server/custom_integration_registry.test.ts b/src/plugins/custom_integrations/server/custom_integration_registry.test.ts new file mode 100644 index 0000000000000..2e211cfb4c93d --- /dev/null +++ b/src/plugins/custom_integrations/server/custom_integration_registry.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CustomIntegrationRegistry } from './custom_integration_registry'; +import { loggerMock, MockedLogger } from '@kbn/logging/mocks'; +import { CustomIntegration } from '../common'; + +describe('CustomIntegrationsRegistry', () => { + let mockLogger: MockedLogger; + + const integration: CustomIntegration = { + id: 'foo', + title: 'Foo', + description: 'test integration', + type: 'ui_link', + uiInternalPath: '/path/to/foo', + isBeta: false, + icons: [], + categories: ['upload_file'], + shipper: 'tests', + }; + + beforeEach(() => { + mockLogger = loggerMock.create(); + }); + + describe('register', () => { + describe('should log to console on duplicate id', () => { + test('with an error in dev', () => { + const registry = new CustomIntegrationRegistry(mockLogger, true); + registry.registerCustomIntegration(integration); + registry.registerCustomIntegration(integration); + expect(mockLogger.error.mock.calls.length).toBe(1); + }); + test('with a debug in prod', () => { + const registry = new CustomIntegrationRegistry(mockLogger, false); + registry.registerCustomIntegration(integration); + registry.registerCustomIntegration(integration); + expect(mockLogger.debug.mock.calls.length).toBe(1); + }); + }); + }); + + describe('getAppendCustomCategories', () => { + test('should return', () => { + const registry = new CustomIntegrationRegistry(mockLogger, true); + registry.registerCustomIntegration(integration); + registry.registerCustomIntegration({ ...integration, id: 'bar' }); + expect(registry.getAppendCustomIntegrations()).toEqual([ + { + categories: ['upload_file'], + description: 'test integration', + icons: [], + id: 'foo', + isBeta: false, + shipper: 'tests', + title: 'Foo', + type: 'ui_link', + uiInternalPath: '/path/to/foo', + }, + { + categories: ['upload_file'], + description: 'test integration', + icons: [], + id: 'bar', + isBeta: false, + shipper: 'tests', + title: 'Foo', + type: 'ui_link', + uiInternalPath: '/path/to/foo', + }, + ]); + }); + test('should ignore duplicate ids', () => { + const registry = new CustomIntegrationRegistry(mockLogger, true); + registry.registerCustomIntegration(integration); + registry.registerCustomIntegration(integration); + expect(registry.getAppendCustomIntegrations()).toEqual([ + { + categories: ['upload_file'], + description: 'test integration', + icons: [], + id: 'foo', + isBeta: false, + shipper: 'tests', + title: 'Foo', + type: 'ui_link', + uiInternalPath: '/path/to/foo', + }, + ]); + }); + test('should ignore integrations without category', () => { + const registry = new CustomIntegrationRegistry(mockLogger, true); + registry.registerCustomIntegration(integration); + registry.registerCustomIntegration({ ...integration, id: 'bar', categories: [] }); + + expect(registry.getAppendCustomIntegrations()).toEqual([ + { + categories: ['upload_file'], + description: 'test integration', + icons: [], + id: 'foo', + isBeta: false, + shipper: 'tests', + title: 'Foo', + type: 'ui_link', + uiInternalPath: '/path/to/foo', + }, + ]); + }); + }); +}); diff --git a/src/plugins/custom_integrations/server/custom_integration_registry.ts b/src/plugins/custom_integrations/server/custom_integration_registry.ts new file mode 100644 index 0000000000000..fa216ced5bd92 --- /dev/null +++ b/src/plugins/custom_integrations/server/custom_integration_registry.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Logger } from 'kibana/server'; +import { CustomIntegration } from '../common'; + +function isAddable(integration: CustomIntegration) { + return integration.categories.length; +} + +export class CustomIntegrationRegistry { + private readonly _integrations: CustomIntegration[]; + private readonly _logger: Logger; + private readonly _isDev: boolean; + + constructor(logger: Logger, isDev: boolean) { + this._integrations = []; + this._logger = logger; + this._isDev = isDev; + } + + registerCustomIntegration(customIntegration: CustomIntegration) { + if ( + this._integrations.some((integration: CustomIntegration) => { + return integration.id === customIntegration.id; + }) + ) { + const message = `Integration with id=${customIntegration.id} already exists.`; + if (this._isDev) { + this._logger.error(message); + } else { + this._logger.debug(message); + } + return; + } + + this._integrations.push(customIntegration); + } + + getAppendCustomIntegrations(): CustomIntegration[] { + return this._integrations.filter(isAddable); + } +} diff --git a/src/plugins/custom_integrations/server/index.ts b/src/plugins/custom_integrations/server/index.ts new file mode 100755 index 0000000000000..423a06009ac4b --- /dev/null +++ b/src/plugins/custom_integrations/server/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema } from '@kbn/config-schema'; +import { PluginInitializerContext } from '../../../core/server'; +import { CustomIntegrationsPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. + +export function plugin(initializerContext: PluginInitializerContext) { + return new CustomIntegrationsPlugin(initializerContext); +} + +export { CustomIntegrationsPluginSetup, CustomIntegrationsPluginStart } from './types'; + +export type { Category, CategoryCount, CustomIntegration } from '../common'; + +export const config = { + schema: schema.object({}), +}; diff --git a/src/plugins/custom_integrations/server/mocks.ts b/src/plugins/custom_integrations/server/mocks.ts new file mode 100644 index 0000000000000..661c7e567aef6 --- /dev/null +++ b/src/plugins/custom_integrations/server/mocks.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { MockedKeys } from '@kbn/utility-types/jest'; + +import { CustomIntegrationsPluginSetup } from '../server'; + +function createCustomIntegrationsSetup(): MockedKeys { + const mock = { + registerCustomIntegration: jest.fn(), + getAppendCustomIntegrations: jest.fn(), + }; + + return mock as MockedKeys; +} + +export const customIntegrationsMock = { + createSetup: createCustomIntegrationsSetup, +}; diff --git a/src/plugins/custom_integrations/server/plugin.test.ts b/src/plugins/custom_integrations/server/plugin.test.ts new file mode 100644 index 0000000000000..08f68a70a3c70 --- /dev/null +++ b/src/plugins/custom_integrations/server/plugin.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CustomIntegrationsPlugin } from './plugin'; + +import { coreMock } from '../../../core/server/mocks'; + +describe('CustomIntegrationsPlugin', () => { + beforeEach(() => {}); + + describe('setup', () => { + let mockCoreSetup: ReturnType; + let initContext: ReturnType; + + beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); + initContext = coreMock.createPluginInitializerContext(); + }); + + test('wires up tutorials provider service and returns registerTutorial and addScopedTutorialContextFactory', () => { + const setup = new CustomIntegrationsPlugin(initContext).setup(mockCoreSetup); + expect(setup).toHaveProperty('registerCustomIntegration'); + expect(setup).toHaveProperty('getAppendCustomIntegrations'); + }); + }); +}); diff --git a/src/plugins/custom_integrations/server/plugin.ts b/src/plugins/custom_integrations/server/plugin.ts new file mode 100755 index 0000000000000..f1ddd70b6945a --- /dev/null +++ b/src/plugins/custom_integrations/server/plugin.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from 'kibana/server'; + +import { CustomIntegrationsPluginSetup, CustomIntegrationsPluginStart } from './types'; +import { CustomIntegration } from '../common'; +import { CustomIntegrationRegistry } from './custom_integration_registry'; +import { defineRoutes } from './routes/define_routes'; + +export class CustomIntegrationsPlugin + implements Plugin +{ + private readonly logger: Logger; + private readonly customIngegrationRegistry: CustomIntegrationRegistry; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + this.customIngegrationRegistry = new CustomIntegrationRegistry( + this.logger, + initializerContext.env.mode.dev + ); + } + + public setup(core: CoreSetup) { + this.logger.debug('customIntegrations: Setup'); + + const router = core.http.createRouter(); + defineRoutes(router, this.customIngegrationRegistry); + + return { + registerCustomIntegration: (integration: Omit) => { + this.customIngegrationRegistry.registerCustomIntegration({ + type: 'ui_link', + ...integration, + }); + }, + getAppendCustomIntegrations: (): CustomIntegration[] => { + return this.customIngegrationRegistry.getAppendCustomIntegrations(); + }, + } as CustomIntegrationsPluginSetup; + } + + public start(core: CoreStart) { + this.logger.debug('customIntegrations: Started'); + return {}; + } + + public stop() {} +} diff --git a/src/plugins/custom_integrations/server/routes/define_routes.ts b/src/plugins/custom_integrations/server/routes/define_routes.ts new file mode 100644 index 0000000000000..f5e952a0c1ebd --- /dev/null +++ b/src/plugins/custom_integrations/server/routes/define_routes.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { IRouter } from 'src/core/server'; +import { CustomIntegrationRegistry } from '../custom_integration_registry'; +import { ROUTES_ADDABLECUSTOMINTEGRATIONS } from '../../common'; + +export function defineRoutes( + router: IRouter, + customIntegrationsRegistry: CustomIntegrationRegistry +) { + router.get( + { + path: ROUTES_ADDABLECUSTOMINTEGRATIONS, + validate: false, + }, + async (context, request, response) => { + const integrations = customIntegrationsRegistry.getAppendCustomIntegrations(); + return response.ok({ + body: integrations, + }); + } + ); +} diff --git a/src/plugins/custom_integrations/server/types.ts b/src/plugins/custom_integrations/server/types.ts new file mode 100755 index 0000000000000..b21bfd157a96e --- /dev/null +++ b/src/plugins/custom_integrations/server/types.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CustomIntegration } from '../common'; + +export interface CustomIntegrationsPluginSetup { + registerCustomIntegration(customIntegration: Omit): void; + getAppendCustomIntegrations(): CustomIntegration[]; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface CustomIntegrationsPluginStart {} diff --git a/src/plugins/custom_integrations/tsconfig.json b/src/plugins/custom_integrations/tsconfig.json new file mode 100644 index 0000000000000..2ce7bf9c8112c --- /dev/null +++ b/src/plugins/custom_integrations/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": ["common/**/*", "public/**/*", "server/**/*"], + "references": [ + { "path": "../../core/tsconfig.json" } + ] +} diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx index 1ac9d680915c6..c3b4075690261 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx @@ -59,9 +59,7 @@ const createDashboardAppStateServices = () => { const defaults = makeDefaultServices(); const indexPatterns = {} as IndexPatternsContract; const defaultIndexPattern = { id: 'foo', fields: [{ name: 'bar' }] } as IIndexPattern; - indexPatterns.ensureDefaultIndexPattern = jest - .fn() - .mockImplementation(() => Promise.resolve(true)); + indexPatterns.ensureDefaultDataView = jest.fn().mockImplementation(() => Promise.resolve(true)); indexPatterns.getDefault = jest .fn() .mockImplementation(() => Promise.resolve(defaultIndexPattern)); diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts index 1b24062ccd9b5..be600cb802146 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts @@ -237,27 +237,25 @@ export const useDashboardAppState = ({ .pipe(debounceTime(DashboardConstants.CHANGE_CHECK_DEBOUNCE)) .subscribe((states) => { const [lastSaved, current] = states; - const unsavedChanges = - current.viewMode === ViewMode.EDIT ? diffDashboardState(lastSaved, current) : {}; - - let savedTimeChanged = false; + const unsavedChanges = diffDashboardState(lastSaved, current); + + const savedTimeChanged = + lastSaved.timeRestore && + !areTimeRangesEqual( + { + from: savedDashboard?.timeFrom, + to: savedDashboard?.timeTo, + }, + timefilter.getTime() + ); /** - * changes to the time filter should only be considered 'unsaved changes' when + * changes to the dashboard should only be considered 'unsaved changes' when * editing the dashboard */ - if (current.viewMode === ViewMode.EDIT) { - savedTimeChanged = - lastSaved.timeRestore && - !areTimeRangesEqual( - { - from: savedDashboard?.timeFrom, - to: savedDashboard?.timeTo, - }, - timefilter.getTime() - ); - } - const hasUnsavedChanges = Object.keys(unsavedChanges).length > 0 || savedTimeChanged; + const hasUnsavedChanges = + current.viewMode === ViewMode.EDIT && + (Object.keys(unsavedChanges).length > 0 || savedTimeChanged); setDashboardAppState((s) => ({ ...s, hasUnsavedChanges })); unsavedChanges.viewMode = current.viewMode; // always push view mode into session store. diff --git a/src/plugins/dashboard/public/application/lib/dashboard_session_storage.ts b/src/plugins/dashboard/public/application/lib/dashboard_session_storage.ts index 7d0e60c0609a8..a696c8bc15b83 100644 --- a/src/plugins/dashboard/public/application/lib/dashboard_session_storage.ts +++ b/src/plugins/dashboard/public/application/lib/dashboard_session_storage.ts @@ -11,6 +11,7 @@ import { Storage } from '../../services/kibana_utils'; import { NotificationsStart } from '../../services/core'; import { panelStorageErrorStrings } from '../../dashboard_strings'; import { DashboardState } from '../../types'; +import { ViewMode } from '../../services/embeddable'; export const DASHBOARD_PANELS_UNSAVED_ID = 'unsavedDashboard'; const DASHBOARD_PANELS_SESSION_KEY = 'dashboardStateManagerPanels'; @@ -69,6 +70,7 @@ export class DashboardSessionStorage { const dashboardsWithUnsavedChanges: string[] = []; Object.keys(dashboardStatesInSpace).map((dashboardId) => { if ( + dashboardStatesInSpace[dashboardId].viewMode === ViewMode.EDIT && Object.keys(dashboardStatesInSpace[dashboardId]).some( (stateKey) => stateKey !== 'viewMode' ) diff --git a/src/plugins/dashboard/public/application/lib/load_saved_dashboard_state.ts b/src/plugins/dashboard/public/application/lib/load_saved_dashboard_state.ts index 04461a46ad0da..3913608c6beff 100644 --- a/src/plugins/dashboard/public/application/lib/load_saved_dashboard_state.ts +++ b/src/plugins/dashboard/public/application/lib/load_saved_dashboard_state.ts @@ -51,7 +51,7 @@ export const loadSavedDashboardState = async ({ notifications.toasts.addWarning(getDashboard60Warning()); return; } - await indexPatterns.ensureDefaultIndexPattern(); + await indexPatterns.ensureDefaultDataView(); let savedDashboard: DashboardSavedObject | undefined; try { savedDashboard = (await savedDashboards.get(savedDashboardId)) as DashboardSavedObject; diff --git a/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx b/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx index 6508bd9f355e1..827e5abf2bd6a 100644 --- a/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx +++ b/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx @@ -7,7 +7,7 @@ */ import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiLink, EuiButton, EuiEmptyPrompt } from '@elastic/eui'; +import { EuiLink, EuiButton, EuiEmptyPrompt, EuiBasicTableColumn } from '@elastic/eui'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { attemptLoadDashboardByTitle } from '../lib'; import { DashboardAppServices, DashboardRedirect } from '../../types'; @@ -231,7 +231,7 @@ const getTableColumns = ( sortable: true, }, ...(savedObjectsTagging ? [savedObjectsTagging.ui.getTableColumnDefinition()] : []), - ]; + ] as unknown as Array>>; }; const getNoItemsMessage = ( diff --git a/src/plugins/dashboard/public/application/listing/dashboard_no_match.tsx b/src/plugins/dashboard/public/application/listing/dashboard_no_match.tsx index 03f7b0e162229..91361836f59d4 100644 --- a/src/plugins/dashboard/public/application/listing/dashboard_no_match.tsx +++ b/src/plugins/dashboard/public/application/listing/dashboard_no_match.tsx @@ -23,9 +23,8 @@ export const DashboardNoMatch = ({ history }: { history: RouteComponentProps['hi useEffect(() => { services.restorePreviousUrl(); - const { navigated } = services.urlForwarding.navigateToLegacyKibanaUrl( - history.location.pathname + history.location.pathname + history.location.search ); if (!navigated) { diff --git a/src/plugins/dashboard/server/saved_objects/dashboard.ts b/src/plugins/dashboard/server/saved_objects/dashboard.ts index dfda251e28779..068883c429e61 100644 --- a/src/plugins/dashboard/server/saved_objects/dashboard.ts +++ b/src/plugins/dashboard/server/saved_objects/dashboard.ts @@ -27,9 +27,6 @@ export const createDashboardSavedObjectType = ({ getTitle(obj) { return obj.attributes.title; }, - getEditUrl(obj) { - return `/management/kibana/objects/savedDashboards/${encodeURIComponent(obj.id)}`; - }, getInAppUrl(obj) { return { path: `/app/dashboards#/view/${encodeURIComponent(obj.id)}`, diff --git a/src/plugins/data/common/data_views/index_pattern.stub.ts b/src/plugins/data/common/data_views/data_view.stub.ts similarity index 59% rename from src/plugins/data/common/data_views/index_pattern.stub.ts rename to src/plugins/data/common/data_views/data_view.stub.ts index 16624087f83b3..a3279434c7a0b 100644 --- a/src/plugins/data/common/data_views/index_pattern.stub.ts +++ b/src/plugins/data/common/data_views/data_view.stub.ts @@ -7,12 +7,15 @@ */ import { stubFieldSpecMap, stubLogstashFieldSpecMap } from './field.stub'; -import { createStubIndexPattern } from './data_views/index_pattern.stub'; -export { createStubIndexPattern } from './data_views/index_pattern.stub'; +import { createStubDataView } from './data_views/data_view.stub'; +export { + createStubDataView, + createStubDataView as createStubIndexPattern, +} from './data_views/data_view.stub'; import { SavedObject } from '../../../../core/types'; -import { IndexPatternAttributes } from '../types'; +import { DataViewAttributes } from '../types'; -export const stubIndexPattern = createStubIndexPattern({ +export const stubDataView = createStubDataView({ spec: { id: 'logstash-*', fields: stubFieldSpecMap, @@ -21,7 +24,9 @@ export const stubIndexPattern = createStubIndexPattern({ }, }); -export const stubIndexPatternWithoutTimeField = createStubIndexPattern({ +export const stubIndexPattern = stubDataView; + +export const stubDataViewWithoutTimeField = createStubDataView({ spec: { id: 'logstash-*', fields: stubFieldSpecMap, @@ -29,7 +34,9 @@ export const stubIndexPatternWithoutTimeField = createStubIndexPattern({ }, }); -export const stubLogstashIndexPattern = createStubIndexPattern({ +export const stubIndexPatternWithoutTimeField = stubDataViewWithoutTimeField; + +export const stubLogstashDataView = createStubDataView({ spec: { id: 'logstash-*', title: 'logstash-*', @@ -38,9 +45,11 @@ export const stubLogstashIndexPattern = createStubIndexPattern({ }, }); -export function stubbedSavedObjectIndexPattern( +export const stubLogstashIndexPattern = stubLogstashDataView; + +export function stubbedSavedObjectDataView( id: string | null = null -): SavedObject { +): SavedObject { return { id: id ?? '', type: 'index-pattern', @@ -53,3 +62,5 @@ export function stubbedSavedObjectIndexPattern( references: [], }; } + +export const stubbedSavedObjectIndexPattern = stubbedSavedObjectDataView; diff --git a/src/plugins/data/common/data_views/data_views/__snapshots__/index_pattern.test.ts.snap b/src/plugins/data/common/data_views/data_views/__snapshots__/data_view.test.ts.snap similarity index 100% rename from src/plugins/data/common/data_views/data_views/__snapshots__/index_pattern.test.ts.snap rename to src/plugins/data/common/data_views/data_views/__snapshots__/data_view.test.ts.snap diff --git a/src/plugins/data/common/data_views/data_views/__snapshots__/index_patterns.test.ts.snap b/src/plugins/data/common/data_views/data_views/__snapshots__/data_views.test.ts.snap similarity index 100% rename from src/plugins/data/common/data_views/data_views/__snapshots__/index_patterns.test.ts.snap rename to src/plugins/data/common/data_views/data_views/__snapshots__/data_views.test.ts.snap diff --git a/src/plugins/data/common/data_views/data_views/_pattern_cache.ts b/src/plugins/data/common/data_views/data_views/_pattern_cache.ts index f304d0e93d79c..19db5b21e5934 100644 --- a/src/plugins/data/common/data_views/data_views/_pattern_cache.ts +++ b/src/plugins/data/common/data_views/data_views/_pattern_cache.ts @@ -16,12 +16,12 @@ export interface DataViewCache { } export function createDataViewCache(): DataViewCache { - const vals: Record = {}; + const vals: Record> = {}; const cache: DataViewCache = { get: (id: string) => { return vals[id]; }, - set: (id: string, prom: any) => { + set: (id: string, prom: Promise) => { vals[id] = prom; return prom; }, diff --git a/src/plugins/data/common/data_views/data_views/index_pattern.stub.ts b/src/plugins/data/common/data_views/data_views/data_view.stub.ts similarity index 85% rename from src/plugins/data/common/data_views/data_views/index_pattern.stub.ts rename to src/plugins/data/common/data_views/data_views/data_view.stub.ts index 3b6660c6d93dc..5ff2d077812a8 100644 --- a/src/plugins/data/common/data_views/data_views/index_pattern.stub.ts +++ b/src/plugins/data/common/data_views/data_views/data_view.stub.ts @@ -6,18 +6,18 @@ * Side Public License, v 1. */ -import { IndexPattern } from './data_view'; +import { DataView } from './data_view'; import { DataViewSpec } from '../types'; import { FieldFormatsStartCommon } from '../../../../field_formats/common'; import { fieldFormatsMock } from '../../../../field_formats/common/mocks'; /** - * Create a custom stub index pattern. Use it in your unit tests where an {@link IndexPattern} expected. + * Create a custom stub index pattern. Use it in your unit tests where an {@link DataView} expected. * @param spec - Serialized index pattern object * @param opts - Specify index pattern options * @param deps - Optionally provide dependencies, you can provide a custom field formats implementation, by default a dummy mock is used * - * @returns - an {@link IndexPattern} instance + * @returns - an {@link DataView} instance * * * @example @@ -32,7 +32,7 @@ import { fieldFormatsMock } from '../../../../field_formats/common/mocks'; * * ``` */ -export const createStubIndexPattern = ({ +export const createStubDataView = ({ spec, opts, deps, @@ -45,12 +45,10 @@ export const createStubIndexPattern = ({ deps?: { fieldFormats?: FieldFormatsStartCommon; }; -}): IndexPattern => { - const indexPattern = new IndexPattern({ +}): DataView => + new DataView({ spec, metaFields: opts?.metaFields ?? ['_id', '_type', '_source'], shortDotsEnable: opts?.shortDotsEnable, fieldFormats: deps?.fieldFormats ?? fieldFormatsMock, }); - return indexPattern; -}; diff --git a/src/plugins/data/common/data_views/data_views/index_pattern.test.ts b/src/plugins/data/common/data_views/data_views/data_view.test.ts similarity index 99% rename from src/plugins/data/common/data_views/data_views/index_pattern.test.ts rename to src/plugins/data/common/data_views/data_views/data_view.test.ts index 5fd1d0d051acb..6aea86a7adae7 100644 --- a/src/plugins/data/common/data_views/data_views/index_pattern.test.ts +++ b/src/plugins/data/common/data_views/data_views/data_view.test.ts @@ -18,7 +18,7 @@ import { fieldFormatsMock } from '../../../../field_formats/common/mocks'; import { FieldFormat } from '../../../../field_formats/common'; import { RuntimeField } from '../types'; import { stubLogstashFields } from '../field.stub'; -import { stubbedSavedObjectIndexPattern } from '../index_pattern.stub'; +import { stubbedSavedObjectIndexPattern } from '../data_view.stub'; class MockFieldFormatter {} diff --git a/src/plugins/data/common/data_views/data_views/data_view.ts b/src/plugins/data/common/data_views/data_views/data_view.ts index e08d1e62bae06..18d301d2f9ea7 100644 --- a/src/plugins/data/common/data_views/data_views/data_view.ts +++ b/src/plugins/data/common/data_views/data_views/data_view.ts @@ -10,6 +10,7 @@ import _, { each, reject } from 'lodash'; import { castEsToKbnFieldTypeName } from '@kbn/field-types'; +import type { estypes } from '@elastic/elasticsearch'; import { FieldAttrs, FieldAttrSet, DataViewAttributes } from '../..'; import type { RuntimeField } from '../types'; import { DuplicateField } from '../../../../kibana_utils/common'; @@ -158,7 +159,7 @@ export class DataView implements IIndexPattern { }; getComputedFields() { - const scriptFields: any = {}; + const scriptFields: Record = {}; if (!this.fields) { return { storedFields: ['*'], @@ -170,23 +171,21 @@ export class DataView implements IIndexPattern { // Date value returned in "_source" could be in any number of formats // Use a docvalue for each date field to ensure standardized formats when working with date fields - // indexPattern.flattenHit will override "_source" values when the same field is also defined in "fields" - const docvalueFields = reject(this.fields.getByType('date'), 'scripted').map( - (dateField: any) => { - return { - field: dateField.name, - format: - dateField.esTypes && dateField.esTypes.indexOf('date_nanos') !== -1 - ? 'strict_date_time' - : 'date_time', - }; - } - ); + // dataView.flattenHit will override "_source" values when the same field is also defined in "fields" + const docvalueFields = reject(this.fields.getByType('date'), 'scripted').map((dateField) => { + return { + field: dateField.name, + format: + dateField.esTypes && dateField.esTypes.indexOf('date_nanos') !== -1 + ? 'strict_date_time' + : 'date_time', + }; + }); each(this.getScriptedFields(), function (field) { scriptFields[field.name] = { script: { - source: field.script, + source: field.script as string, lang: field.lang, }, }; @@ -227,7 +226,7 @@ export class DataView implements IIndexPattern { */ getSourceFiltering() { return { - excludes: (this.sourceFilters && this.sourceFilters.map((filter: any) => filter.value)) || [], + excludes: (this.sourceFilters && this.sourceFilters.map((filter) => filter.value)) || [], }; } @@ -299,8 +298,8 @@ export class DataView implements IIndexPattern { } isTimeNanosBased(): boolean { - const timeField: any = this.getTimeField(); - return timeField && timeField.esTypes && timeField.esTypes.indexOf('date_nanos') !== -1; + const timeField = this.getTimeField(); + return !!(timeField && timeField.esTypes && timeField.esTypes.indexOf('date_nanos') !== -1); } getTimeField() { diff --git a/src/plugins/data/common/data_views/data_views/index_patterns.test.ts b/src/plugins/data/common/data_views/data_views/data_views.test.ts similarity index 99% rename from src/plugins/data/common/data_views/data_views/index_patterns.test.ts rename to src/plugins/data/common/data_views/data_views/data_views.test.ts index 996700b3c9118..ef9381f16d934 100644 --- a/src/plugins/data/common/data_views/data_views/index_patterns.test.ts +++ b/src/plugins/data/common/data_views/data_views/data_views.test.ts @@ -11,7 +11,7 @@ import { DataViewsService, DataView } from '.'; import { fieldFormatsMock } from '../../../../field_formats/common/mocks'; import { UiSettingsCommon, SavedObjectsClientCommon, SavedObject } from '../types'; -import { stubbedSavedObjectIndexPattern } from '../index_pattern.stub'; +import { stubbedSavedObjectIndexPattern } from '../data_view.stub'; const createFieldsFetcher = jest.fn().mockImplementation(() => ({ getFieldsForWildcard: jest.fn().mockImplementation(() => { diff --git a/src/plugins/data/common/data_views/data_views/data_views.ts b/src/plugins/data/common/data_views/data_views/data_views.ts index 1284f00436324..f9b193d154770 100644 --- a/src/plugins/data/common/data_views/data_views/data_views.ts +++ b/src/plugins/data/common/data_views/data_views/data_views.ts @@ -77,9 +77,9 @@ export class DataViewsService { private fieldFormats: FieldFormatsStartCommon; private onNotification: OnNotification; private onError: OnError; - private indexPatternCache: ReturnType; + private dataViewCache: ReturnType; - ensureDefaultIndexPattern: EnsureDefaultDataView; + ensureDefaultDataView: EnsureDefaultDataView; constructor({ uiSettings, @@ -96,12 +96,9 @@ export class DataViewsService { this.fieldFormats = fieldFormats; this.onNotification = onNotification; this.onError = onError; - this.ensureDefaultIndexPattern = createEnsureDefaultDataView( - uiSettings, - onRedirectNoIndexPattern - ); + this.ensureDefaultDataView = createEnsureDefaultDataView(uiSettings, onRedirectNoIndexPattern); - this.indexPatternCache = createDataViewCache(); + this.dataViewCache = createDataViewCache(); } /** @@ -190,9 +187,9 @@ export class DataViewsService { clearCache = (id?: string) => { this.savedObjectsCache = null; if (id) { - this.indexPatternCache.clear(id); + this.dataViewCache.clear(id); } else { - this.indexPatternCache.clearAll(); + this.dataViewCache.clearAll(); } }; @@ -289,7 +286,7 @@ export class DataViewsService { indexPattern.fields.replaceAll(fieldsWithSavedAttrs); } catch (err) { if (err instanceof DataViewMissingIndices) { - this.onNotification({ title: (err as any).message, color: 'danger', iconType: 'alert' }); + this.onNotification({ title: err.message, color: 'danger', iconType: 'alert' }); } this.onError(err, { @@ -334,7 +331,7 @@ export class DataViewsService { return this.fieldArrayToMap(updatedFieldList, fieldAttrs); } catch (err) { if (err instanceof DataViewMissingIndices) { - this.onNotification({ title: (err as any).message, color: 'danger', iconType: 'alert' }); + this.onNotification({ title: err.message, color: 'danger', iconType: 'alert' }); return {}; } @@ -475,7 +472,7 @@ export class DataViewsService { } catch (err) { if (err instanceof DataViewMissingIndices) { this.onNotification({ - title: (err as any).message, + title: err.message, color: 'danger', iconType: 'alert', }); @@ -505,12 +502,11 @@ export class DataViewsService { get = async (id: string): Promise => { const indexPatternPromise = - this.indexPatternCache.get(id) || - this.indexPatternCache.set(id, this.getSavedObjectAndInit(id)); + this.dataViewCache.get(id) || this.dataViewCache.set(id, this.getSavedObjectAndInit(id)); // don't cache failed requests indexPatternPromise.catch(() => { - this.indexPatternCache.clear(id); + this.dataViewCache.clear(id); }); return indexPatternPromise; @@ -580,7 +576,7 @@ export class DataViewsService { )) as SavedObject; const createdIndexPattern = await this.initFromSavedObject(response); - this.indexPatternCache.set(createdIndexPattern.id!, Promise.resolve(createdIndexPattern)); + this.dataViewCache.set(createdIndexPattern.id!, Promise.resolve(createdIndexPattern)); if (this.savedObjectsCache) { this.savedObjectsCache.push(response as SavedObject); } @@ -668,7 +664,7 @@ export class DataViewsService { indexPattern.version = samePattern.version; // Clear cache - this.indexPatternCache.clear(indexPattern.id!); + this.dataViewCache.clear(indexPattern.id!); // Try the save again return this.updateSavedObject(indexPattern, saveAttempts, ignoreErrors); @@ -682,7 +678,7 @@ export class DataViewsService { * @param indexPatternId: Id of kibana Index Pattern to delete */ async delete(indexPatternId: string) { - this.indexPatternCache.clear(indexPatternId); + this.dataViewCache.clear(indexPatternId); return this.savedObjectsClient.delete(DATA_VIEW_SAVED_OBJECT_TYPE, indexPatternId); } } diff --git a/src/plugins/data/common/data_views/data_views/flatten_hit.test.ts b/src/plugins/data/common/data_views/data_views/flatten_hit.test.ts index f8e1309a38ffe..73232a65b6b72 100644 --- a/src/plugins/data/common/data_views/data_views/flatten_hit.test.ts +++ b/src/plugins/data/common/data_views/data_views/flatten_hit.test.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ -import { IndexPattern } from './data_view'; +import { DataView } from './data_view'; import { fieldFormatsMock } from '../../../../field_formats/common/mocks'; import { flattenHitWrapper } from './flatten_hit'; -import { stubbedSavedObjectIndexPattern } from '../index_pattern.stub'; +import { stubbedSavedObjectIndexPattern } from '../data_view.stub'; class MockFieldFormatter {} @@ -24,7 +24,7 @@ function create(id: string) { attributes: { timeFieldName, fields, title }, } = stubbedSavedObjectIndexPattern(id); - return new IndexPattern({ + return new DataView({ spec: { id, type, @@ -41,7 +41,7 @@ function create(id: string) { } describe('flattenHit', () => { - let indexPattern: IndexPattern; + let indexPattern: DataView; // create an indexPattern instance for each test beforeEach(() => { diff --git a/src/plugins/data/common/data_views/data_views/flatten_hit.ts b/src/plugins/data/common/data_views/data_views/flatten_hit.ts index 58a5dff66acc8..ddf484affa298 100644 --- a/src/plugins/data/common/data_views/data_views/flatten_hit.ts +++ b/src/plugins/data/common/data_views/data_views/flatten_hit.ts @@ -103,11 +103,11 @@ function decorateFlattenedWrapper(hit: Record, metaFields: Record, deep = false) { const decorateFlattened = decorateFlattenedWrapper(hit, metaFields); const cached = cache.get(hit); - const flattened = cached || flattenHit(indexPattern, hit, deep); + const flattened = cached || flattenHit(dataView, hit, deep); if (!cached) { cache.set(hit, { ...flattened }); } diff --git a/src/plugins/data/common/data_views/data_views/format_hit.ts b/src/plugins/data/common/data_views/data_views/format_hit.ts index b226013752628..39f7fef564eb0 100644 --- a/src/plugins/data/common/data_views/data_views/format_hit.ts +++ b/src/plugins/data/common/data_views/data_views/format_hit.ts @@ -15,24 +15,24 @@ const partialFormattedCache = new WeakMap(); // Takes a hit, merges it with any stored/scripted fields, and with the metaFields // returns a formatted version -export function formatHitProvider(indexPattern: DataView, defaultFormat: any) { +export function formatHitProvider(dataView: DataView, defaultFormat: any) { function convert( hit: Record, val: any, fieldName: string, type: FieldFormatsContentType = 'html' ) { - const field = indexPattern.fields.getByName(fieldName); - const format = field ? indexPattern.getFormatterForField(field) : defaultFormat; + const field = dataView.fields.getByName(fieldName); + const format = field ? dataView.getFormatterForField(field) : defaultFormat; - return format.convert(val, type, { field, hit, indexPattern }); + return format.convert(val, type, { field, hit, indexPattern: dataView }); } function formatHit(hit: Record, type: string = 'html') { if (type === 'text') { // formatHit of type text is for react components to get rid of // since it's currently just used at the discover's doc view table, caching is not necessary - const flattened = indexPattern.flattenHit(hit); + const flattened = dataView.flattenHit(hit); const result: Record = {}; for (const [key, value] of Object.entries(flattened)) { result[key] = convert(hit, value, key, type); @@ -53,7 +53,7 @@ export function formatHitProvider(indexPattern: DataView, defaultFormat: any) { const cache: Record = {}; formattedCache.set(hit, cache); - _.forOwn(indexPattern.flattenHit(hit), function (val: any, fieldName?: string) { + _.forOwn(dataView.flattenHit(hit), function (val: any, fieldName?: string) { // sync the formatted and partial cache if (!fieldName) { return; @@ -77,7 +77,7 @@ export function formatHitProvider(indexPattern: DataView, defaultFormat: any) { partialFormattedCache.set(hit, partials); } - const val = fieldName === '_source' ? hit._source : indexPattern.flattenHit(hit)[fieldName]; + const val = fieldName === '_source' ? hit._source : dataView.flattenHit(hit)[fieldName]; return convert(hit, val, fieldName); }; diff --git a/src/plugins/data/common/data_views/errors/data_view_saved_object_conflict.ts b/src/plugins/data/common/data_views/errors/data_view_saved_object_conflict.ts new file mode 100644 index 0000000000000..3fcb281655727 --- /dev/null +++ b/src/plugins/data/common/data_views/errors/data_view_saved_object_conflict.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export class DataViewSavedObjectConflictError extends Error { + constructor(savedObjectId: string) { + super(`Conflict loading DataView saved object, id: ${savedObjectId}`); + this.name = 'DataViewSavedObjectConflictError'; + } +} diff --git a/src/plugins/data/common/data_views/errors/duplicate_index_pattern.ts b/src/plugins/data/common/data_views/errors/duplicate_index_pattern.ts index d35b09e39aa76..942c104eee4e5 100644 --- a/src/plugins/data/common/data_views/errors/duplicate_index_pattern.ts +++ b/src/plugins/data/common/data_views/errors/duplicate_index_pattern.ts @@ -9,6 +9,6 @@ export class DuplicateDataViewError extends Error { constructor(message: string) { super(message); - this.name = 'DuplicateIndexPatternError'; + this.name = 'DuplicateDataViewError'; } } diff --git a/src/plugins/data/common/data_views/errors/index.ts b/src/plugins/data/common/data_views/errors/index.ts index 63bd1ac5f5848..20ff90d3fd6cf 100644 --- a/src/plugins/data/common/data_views/errors/index.ts +++ b/src/plugins/data/common/data_views/errors/index.ts @@ -7,3 +7,4 @@ */ export * from './duplicate_index_pattern'; +export * from './data_view_saved_object_conflict'; diff --git a/src/plugins/data/common/data_views/field.stub.ts b/src/plugins/data/common/data_views/field.stub.ts index 03bb0dee33db3..7ff51007bcefa 100644 --- a/src/plugins/data/common/data_views/field.stub.ts +++ b/src/plugins/data/common/data_views/field.stub.ts @@ -6,10 +6,10 @@ * Side Public License, v 1. */ -import { FieldSpec, IndexPatternField } from '.'; +import { FieldSpec, DataViewField } from '.'; -export const createIndexPatternFieldStub = ({ spec }: { spec: FieldSpec }): IndexPatternField => { - return new IndexPatternField(spec); +export const createIndexPatternFieldStub = ({ spec }: { spec: FieldSpec }): DataViewField => { + return new DataViewField(spec); }; export const stubFieldSpecMap: Record = { @@ -71,7 +71,7 @@ export const stubFieldSpecMap: Record = { }, }; -export const stubFields: IndexPatternField[] = Object.values(stubFieldSpecMap).map((spec) => +export const stubFields: DataViewField[] = Object.values(stubFieldSpecMap).map((spec) => createIndexPatternFieldStub({ spec }) ); @@ -404,6 +404,6 @@ export const stubLogstashFieldSpecMap: Record = { }, }; -export const stubLogstashFields: IndexPatternField[] = Object.values(stubLogstashFieldSpecMap).map( +export const stubLogstashFields: DataViewField[] = Object.values(stubLogstashFieldSpecMap).map( (spec) => createIndexPatternFieldStub({ spec }) ); diff --git a/src/plugins/data/common/data_views/fields/__snapshots__/index_pattern_field.test.ts.snap b/src/plugins/data/common/data_views/fields/__snapshots__/data_view_field.test.ts.snap similarity index 100% rename from src/plugins/data/common/data_views/fields/__snapshots__/index_pattern_field.test.ts.snap rename to src/plugins/data/common/data_views/fields/__snapshots__/data_view_field.test.ts.snap diff --git a/src/plugins/data/common/data_views/fields/index_pattern_field.test.ts b/src/plugins/data/common/data_views/fields/data_view_field.test.ts similarity index 98% rename from src/plugins/data/common/data_views/fields/index_pattern_field.test.ts rename to src/plugins/data/common/data_views/fields/data_view_field.test.ts index 906cb0ad1badd..9107036c15c1a 100644 --- a/src/plugins/data/common/data_views/fields/index_pattern_field.test.ts +++ b/src/plugins/data/common/data_views/fields/data_view_field.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { IndexPatternField } from './index_pattern_field'; +import { IndexPatternField } from './data_view_field'; import { IndexPattern } from '..'; import { KBN_FIELD_TYPES } from '../../../common'; import { FieldSpec, RuntimeField } from '../types'; diff --git a/src/plugins/data/common/data_views/fields/index_pattern_field.ts b/src/plugins/data/common/data_views/fields/data_view_field.ts similarity index 100% rename from src/plugins/data/common/data_views/fields/index_pattern_field.ts rename to src/plugins/data/common/data_views/fields/data_view_field.ts diff --git a/src/plugins/data/common/data_views/fields/field_list.ts b/src/plugins/data/common/data_views/fields/field_list.ts index 8dd407e16e4c0..e2c850c0c4dd0 100644 --- a/src/plugins/data/common/data_views/fields/field_list.ts +++ b/src/plugins/data/common/data_views/fields/field_list.ts @@ -8,7 +8,7 @@ import { findIndex } from 'lodash'; import { IFieldType } from './types'; -import { DataViewField } from './index_pattern_field'; +import { DataViewField } from './data_view_field'; import { FieldSpec, DataViewFieldMap } from '../types'; import { DataView } from '../data_views'; diff --git a/src/plugins/data/common/data_views/fields/index.ts b/src/plugins/data/common/data_views/fields/index.ts index 53c8ed213cda7..0ff7397c4f7b5 100644 --- a/src/plugins/data/common/data_views/fields/index.ts +++ b/src/plugins/data/common/data_views/fields/index.ts @@ -9,4 +9,4 @@ export * from './types'; export { isFilterable, isNestedField } from './utils'; export * from './field_list'; -export * from './index_pattern_field'; +export * from './data_view_field'; diff --git a/src/plugins/data/common/data_views/lib/get_title.ts b/src/plugins/data/common/data_views/lib/get_title.ts index efebbc302f22c..94185eae46893 100644 --- a/src/plugins/data/common/data_views/lib/get_title.ts +++ b/src/plugins/data/common/data_views/lib/get_title.ts @@ -6,17 +6,18 @@ * Side Public License, v 1. */ -import { SavedObjectsClientContract, SimpleSavedObject } from '../../../../../core/public'; +import { SavedObjectsClientContract } from '../../../../../core/public'; import { DATA_VIEW_SAVED_OBJECT_TYPE } from '../../constants'; +import { DataViewAttributes } from '../types'; export async function getTitle( client: SavedObjectsClientContract, indexPatternId: string -): Promise> { - const savedObject = (await client.get( +): Promise { + const savedObject = await client.get( DATA_VIEW_SAVED_OBJECT_TYPE, indexPatternId - )) as SimpleSavedObject; + ); if (savedObject.error) { throw new Error(`Unable to get index-pattern title: ${savedObject.error.message}`); diff --git a/src/plugins/data/common/data_views/lib/index.ts b/src/plugins/data/common/data_views/lib/index.ts index ae59c7d417818..0554232e64cae 100644 --- a/src/plugins/data/common/data_views/lib/index.ts +++ b/src/plugins/data/common/data_views/lib/index.ts @@ -8,7 +8,6 @@ export { DataViewMissingIndices } from './errors'; export { getTitle } from './get_title'; -export { isDefault } from './is_default'; export * from './types'; -export { validateDataView } from './validate_index_pattern'; +export { validateDataView } from './validate_data_view'; diff --git a/src/plugins/data/common/data_views/lib/validate_index_pattern.test.ts b/src/plugins/data/common/data_views/lib/validate_data_view.test.ts similarity index 94% rename from src/plugins/data/common/data_views/lib/validate_index_pattern.test.ts rename to src/plugins/data/common/data_views/lib/validate_data_view.test.ts index ed90da122484e..edf20440931e3 100644 --- a/src/plugins/data/common/data_views/lib/validate_index_pattern.test.ts +++ b/src/plugins/data/common/data_views/lib/validate_data_view.test.ts @@ -8,7 +8,7 @@ import { CONTAINS_SPACES_KEY, ILLEGAL_CHARACTERS_KEY, ILLEGAL_CHARACTERS_VISIBLE } from './types'; -import { validateDataView } from './validate_index_pattern'; +import { validateDataView } from './validate_data_view'; describe('Index Pattern Utils', () => { describe('Validation', () => { diff --git a/src/plugins/data/common/data_views/lib/validate_index_pattern.ts b/src/plugins/data/common/data_views/lib/validate_data_view.ts similarity index 92% rename from src/plugins/data/common/data_views/lib/validate_index_pattern.ts rename to src/plugins/data/common/data_views/lib/validate_data_view.ts index 454d0bc1a0c6e..f86ba28e7cde4 100644 --- a/src/plugins/data/common/data_views/lib/validate_index_pattern.ts +++ b/src/plugins/data/common/data_views/lib/validate_data_view.ts @@ -24,7 +24,7 @@ function findIllegalCharacters(indexPattern: string): string[] { } export function validateDataView(indexPattern: string) { - const errors: Record = {}; + const errors: { [ILLEGAL_CHARACTERS_KEY]?: string[]; [CONTAINS_SPACES_KEY]?: boolean } = {}; const illegalCharacters = findIllegalCharacters(indexPattern); diff --git a/src/plugins/data/common/data_views/mocks.ts b/src/plugins/data/common/data_views/mocks.ts index 6e82118f7b8b8..9585b6e60f923 100644 --- a/src/plugins/data/common/data_views/mocks.ts +++ b/src/plugins/data/common/data_views/mocks.ts @@ -7,4 +7,4 @@ */ export * from './fields/fields.mocks'; -export * from './data_views/index_pattern.stub'; +export * from './data_views/data_view.stub'; diff --git a/src/plugins/data/common/data_views/types.ts b/src/plugins/data/common/data_views/types.ts index d1e822aea4e97..85fe98fbcfeb7 100644 --- a/src/plugins/data/common/data_views/types.ts +++ b/src/plugins/data/common/data_views/types.ts @@ -89,8 +89,8 @@ export type OnNotification = (toastInputFields: ToastInputFields) => void; export type OnError = (error: Error, toastInputFields: ErrorToastOptions) => void; export interface UiSettingsCommon { - get: (key: string) => Promise; - getAll: () => Promise>; + get: (key: string) => Promise; + getAll: () => Promise>; set: (key: string, value: any) => Promise; remove: (key: string) => Promise; } diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts index 215d3ce13f55e..7ec176d7ab11a 100644 --- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts @@ -377,6 +377,86 @@ describe('Terms Agg Other bucket helper', () => { } }); + test('correctly builds query for nested terms agg with one disabled', () => { + const oneDisabledNestedTerms = { + aggs: [ + { + id: '2', + type: BUCKET_TYPES.TERMS, + enabled: false, + params: { + field: { + name: 'machine.os.raw', + indexPattern, + filterable: true, + }, + size: 2, + otherBucket: false, + missingBucket: true, + }, + }, + { + id: '1', + type: BUCKET_TYPES.TERMS, + params: { + field: { + name: 'geo.src', + indexPattern, + filterable: true, + }, + size: 2, + otherBucket: true, + missingBucket: false, + }, + }, + ], + }; + const aggConfigs = getAggConfigs(oneDisabledNestedTerms.aggs); + const agg = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[1] as IBucketAggConfig, + singleTermResponse + ); + const expectedResponse = { + 'other-filter': { + aggs: undefined, + filters: { + filters: { + '': { + bool: { + filter: [ + { + exists: { + field: 'geo.src', + }, + }, + ], + must: [], + must_not: [ + { + match_phrase: { + 'geo.src': 'ios', + }, + }, + { + match_phrase: { + 'geo.src': 'win xp', + }, + }, + ], + should: [], + }, + }, + }, + }, + }, + }; + expect(agg).toBeDefined(); + if (agg) { + expect(agg()).toEqual(expectedResponse); + } + }); + test('does not build query if sum_other_doc_count is 0 (exhaustive terms)', () => { const aggConfigs = getAggConfigs(nestedTerm.aggs); expect( diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts index 39fba23a42210..436cc5614ac80 100644 --- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts +++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts @@ -129,7 +129,9 @@ export const buildOtherBucketAgg = ( aggWithOtherBucket: IBucketAggConfig, response: any ) => { - const bucketAggs = aggConfigs.aggs.filter((agg) => agg.type.type === AggGroupNames.Buckets); + const bucketAggs = aggConfigs.aggs.filter( + (agg) => agg.type.type === AggGroupNames.Buckets && agg.enabled + ); const index = bucketAggs.findIndex((agg) => agg.id === aggWithOtherBucket.id); const aggs = aggConfigs.toDsl(); const indexPattern = aggWithOtherBucket.aggConfigs.indexPattern; diff --git a/src/plugins/data/common/search/aggs/metrics/top_hit.test.ts b/src/plugins/data/common/search/aggs/metrics/top_hit.test.ts index 04d382f1aa6d1..37ce9c4edb8d1 100644 --- a/src/plugins/data/common/search/aggs/metrics/top_hit.test.ts +++ b/src/plugins/data/common/search/aggs/metrics/top_hit.test.ts @@ -133,28 +133,28 @@ describe('Top hit metric', () => { }); it('should request the _source field', () => { - init({ field: '_source' }); - expect(aggDsl.top_hits._source).toBeTruthy(); - expect(aggDsl.top_hits.docvalue_fields).toBeUndefined(); + init({ fieldName: '_source' }); + expect(aggDsl.top_hits._source).toBe(true); + expect(aggDsl.top_hits.fields).toBeUndefined(); }); - it('requests both source and docvalues_fields for non-text aggregatable fields', () => { + it('requests fields for non-text aggregatable fields', () => { init({ fieldName: 'bytes', readFromDocValues: true }); - expect(aggDsl.top_hits._source).toBe('bytes'); - expect(aggDsl.top_hits.docvalue_fields).toEqual([{ field: 'bytes' }]); + expect(aggDsl.top_hits._source).toBe(false); + expect(aggDsl.top_hits.fields).toEqual([{ field: 'bytes' }]); }); - it('requests both source and docvalues_fields for date aggregatable fields', () => { + it('requests fields for date aggregatable fields', () => { init({ fieldName: '@timestamp', readFromDocValues: true, fieldType: KBN_FIELD_TYPES.DATE }); - expect(aggDsl.top_hits._source).toBe('@timestamp'); - expect(aggDsl.top_hits.docvalue_fields).toEqual([{ field: '@timestamp', format: 'date_time' }]); + expect(aggDsl.top_hits._source).toBe(false); + expect(aggDsl.top_hits.fields).toEqual([{ field: '@timestamp', format: 'date_time' }]); }); - it('requests just source for aggregatable text fields', () => { + it('requests fields for aggregatable text fields', () => { init({ fieldName: 'machine.os' }); - expect(aggDsl.top_hits._source).toBe('machine.os'); - expect(aggDsl.top_hits.docvalue_fields).toBeUndefined(); + expect(aggDsl.top_hits._source).toBe(false); + expect(aggDsl.top_hits.fields).toEqual([{ field: 'machine.os' }]); }); describe('try to get the value from the top hit', () => { diff --git a/src/plugins/data/common/search/aggs/metrics/top_hit.ts b/src/plugins/data/common/search/aggs/metrics/top_hit.ts index 094b5cda9a46d..a4bd99d6b210d 100644 --- a/src/plugins/data/common/search/aggs/metrics/top_hit.ts +++ b/src/plugins/data/common/search/aggs/metrics/top_hit.ts @@ -78,8 +78,8 @@ export const getTopHitMetricAgg = () => { }, }; } else { - if (field.readFromDocValues) { - output.params.docvalue_fields = [ + if (field.name !== '_source') { + output.params.fields = [ { field: field.name, // always format date fields as date_time to avoid @@ -89,7 +89,7 @@ export const getTopHitMetricAgg = () => { }, ]; } - output.params._source = field.name === '_source' ? true : field.name; + output.params._source = field.name === '_source'; } }, }, diff --git a/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.test.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.test.ts index 2e7ffd9d562c3..13d957e7c38bc 100644 --- a/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.test.ts +++ b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.test.ts @@ -22,6 +22,13 @@ describe('parseEsInterval', () => { expect(parseEsInterval('1y')).toEqual({ value: 1, unit: 'y', type: 'calendar' }); }); + it('should correctly parse an user-friendly intervals', () => { + expect(parseEsInterval('minute')).toEqual({ value: 1, unit: 'm', type: 'calendar' }); + expect(parseEsInterval('hour')).toEqual({ value: 1, unit: 'h', type: 'calendar' }); + expect(parseEsInterval('month')).toEqual({ value: 1, unit: 'M', type: 'calendar' }); + expect(parseEsInterval('year')).toEqual({ value: 1, unit: 'y', type: 'calendar' }); + }); + it('should correctly parse an interval containing unit and multiple value', () => { expect(parseEsInterval('250ms')).toEqual({ value: 250, unit: 'ms', type: 'fixed' }); expect(parseEsInterval('90s')).toEqual({ value: 90, unit: 's', type: 'fixed' }); diff --git a/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts index 0280cc0f7c8af..b723c3f45c5a6 100644 --- a/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts +++ b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts @@ -7,16 +7,37 @@ */ import dateMath, { Unit } from '@elastic/datemath'; - import { InvalidEsCalendarIntervalError } from './invalid_es_calendar_interval_error'; import { InvalidEsIntervalFormatError } from './invalid_es_interval_format_error'; const ES_INTERVAL_STRING_REGEX = new RegExp( '^([1-9][0-9]*)\\s*(' + dateMath.units.join('|') + ')$' ); - export type ParsedInterval = ReturnType; +/** ES allows to work at user-friendly intervals. + * This method matches between these intervals and the intervals accepted by parseEsInterval. + * @internal **/ +const mapToEquivalentInterval = (interval: string) => { + switch (interval) { + case 'minute': + return '1m'; + case 'hour': + return '1h'; + case 'day': + return '1d'; + case 'week': + return '1w'; + case 'month': + return '1M'; + case 'quarter': + return '1q'; + case 'year': + return '1y'; + } + return interval; +}; + /** * Extracts interval properties from an ES interval string. Disallows unrecognized interval formats * and fractional values. Converts some intervals from "calendar" to "fixed" when the number of @@ -37,7 +58,7 @@ export type ParsedInterval = ReturnType; * */ export function parseEsInterval(interval: string) { - const matches = String(interval).trim().match(ES_INTERVAL_STRING_REGEX); + const matches = String(mapToEquivalentInterval(interval)).trim().match(ES_INTERVAL_STRING_REGEX); if (!matches) { throw new InvalidEsIntervalFormatError(interval); diff --git a/src/plugins/data/common/stubs.ts b/src/plugins/data/common/stubs.ts index 36bd3357e7098..5cddcf397f442 100644 --- a/src/plugins/data/common/stubs.ts +++ b/src/plugins/data/common/stubs.ts @@ -7,5 +7,5 @@ */ export * from './data_views/field.stub'; -export * from './data_views/index_pattern.stub'; +export * from './data_views/data_view.stub'; export * from './es_query/stubs'; diff --git a/src/plugins/data/public/data_views/data_views/index_pattern.stub.ts b/src/plugins/data/public/data_views/data_views/data_view.stub.ts similarity index 87% rename from src/plugins/data/public/data_views/data_views/index_pattern.stub.ts rename to src/plugins/data/public/data_views/data_views/data_view.stub.ts index 49d31def92384..b3d8448064c65 100644 --- a/src/plugins/data/public/data_views/data_views/index_pattern.stub.ts +++ b/src/plugins/data/public/data_views/data_views/data_view.stub.ts @@ -10,15 +10,15 @@ import { CoreSetup } from 'kibana/public'; import { FieldFormatsStartCommon } from '../../../../field_formats/common'; import { getFieldFormatsRegistry } from '../../../../field_formats/public/mocks'; import * as commonStubs from '../../../common/stubs'; -import { IndexPattern, IndexPatternSpec } from '../../../common'; +import { DataView, DataViewSpec } from '../../../common'; import { coreMock } from '../../../../../core/public/mocks'; /** - * Create a custom stub index pattern. Use it in your unit tests where an {@link IndexPattern} expected. + * Create a custom stub index pattern. Use it in your unit tests where an {@link DataView} expected. * @param spec - Serialized index pattern object * @param opts - Specify index pattern options * @param deps - Optionally provide dependencies, you can provide a custom field formats implementation, by default client side registry with real formatters implementation is used * - * @returns - an {@link IndexPattern} instance + * @returns - an {@link DataView} instance * * @remark - This is a client side version, a browser-agnostic version is available in {@link commonStubs | common}. * The main difference is that client side version by default uses client side field formats service, where common version uses a dummy field formats mock. @@ -35,12 +35,12 @@ import { coreMock } from '../../../../../core/public/mocks'; * * ``` */ -export const createStubIndexPattern = ({ +export const createStubDataView = ({ spec, opts, deps, }: { - spec: IndexPatternSpec; + spec: DataViewSpec; opts?: { shortDotsEnable?: boolean; metaFields?: string[]; @@ -49,8 +49,8 @@ export const createStubIndexPattern = ({ fieldFormats?: FieldFormatsStartCommon; core?: CoreSetup; }; -}): IndexPattern => { - return commonStubs.createStubIndexPattern({ +}): DataView => { + return commonStubs.createStubDataView({ spec, opts, deps: { diff --git a/src/plugins/data/public/data_views/data_views/index_patterns_api_client.test.mock.ts b/src/plugins/data/public/data_views/data_views/data_views_api_client.test.mock.ts similarity index 100% rename from src/plugins/data/public/data_views/data_views/index_patterns_api_client.test.mock.ts rename to src/plugins/data/public/data_views/data_views/data_views_api_client.test.mock.ts diff --git a/src/plugins/data/public/data_views/data_views/index_patterns_api_client.test.ts b/src/plugins/data/public/data_views/data_views/data_views_api_client.test.ts similarity index 83% rename from src/plugins/data/public/data_views/data_views/index_patterns_api_client.test.ts rename to src/plugins/data/public/data_views/data_views/data_views_api_client.test.ts index a6742852533a0..09ee001c218b5 100644 --- a/src/plugins/data/public/data_views/data_views/index_patterns_api_client.test.ts +++ b/src/plugins/data/public/data_views/data_views/data_views_api_client.test.ts @@ -6,16 +6,16 @@ * Side Public License, v 1. */ -import { http } from './index_patterns_api_client.test.mock'; -import { IndexPatternsApiClient } from './index_patterns_api_client'; +import { http } from './data_views_api_client.test.mock'; +import { DataViewsApiClient } from './data_views_api_client'; describe('IndexPatternsApiClient', () => { let fetchSpy: jest.SpyInstance; - let indexPatternsApiClient: IndexPatternsApiClient; + let indexPatternsApiClient: DataViewsApiClient; beforeEach(() => { fetchSpy = jest.spyOn(http, 'fetch').mockImplementation(() => Promise.resolve({})); - indexPatternsApiClient = new IndexPatternsApiClient(http); + indexPatternsApiClient = new DataViewsApiClient(http); }); test('uses the right URI to fetch fields for time patterns', async function () { diff --git a/src/plugins/data/public/data_views/data_views/index_patterns_api_client.ts b/src/plugins/data/public/data_views/data_views/data_views_api_client.ts similarity index 95% rename from src/plugins/data/public/data_views/data_views/index_patterns_api_client.ts rename to src/plugins/data/public/data_views/data_views/data_views_api_client.ts index 295cd99e7e017..d11ec7cfa003d 100644 --- a/src/plugins/data/public/data_views/data_views/index_patterns_api_client.ts +++ b/src/plugins/data/public/data_views/data_views/data_views_api_client.ts @@ -10,13 +10,13 @@ import { HttpSetup } from 'src/core/public'; import { DataViewMissingIndices } from '../../../common/data_views/lib'; import { GetFieldsOptions, - IIndexPatternsApiClient, + IDataViewsApiClient, GetFieldsOptionsTimePattern, } from '../../../common/data_views/types'; const API_BASE_URL: string = `/api/index_patterns/`; -export class IndexPatternsApiClient implements IIndexPatternsApiClient { +export class DataViewsApiClient implements IDataViewsApiClient { private http: HttpSetup; constructor(http: HttpSetup) { diff --git a/src/plugins/data/public/data_views/data_views/index.ts b/src/plugins/data/public/data_views/data_views/index.ts index 4b31933442893..e0d18d47f39db 100644 --- a/src/plugins/data/public/data_views/data_views/index.ts +++ b/src/plugins/data/public/data_views/data_views/index.ts @@ -8,4 +8,4 @@ export * from '../../../common/data_views/data_views'; export * from './redirect_no_index_pattern'; -export * from './index_patterns_api_client'; +export * from './data_views_api_client'; diff --git a/src/plugins/data/public/data_views/index.ts b/src/plugins/data/public/data_views/index.ts index 02e36d893fa6f..0125b173989fb 100644 --- a/src/plugins/data/public/data_views/index.ts +++ b/src/plugins/data/public/data_views/index.ts @@ -12,7 +12,6 @@ export { ILLEGAL_CHARACTERS_VISIBLE, ILLEGAL_CHARACTERS, validateDataView, - isDefault, } from '../../common/data_views/lib'; export { flattenHitWrapper, formatHitProvider, onRedirectNoIndexPattern } from './data_views'; @@ -22,7 +21,7 @@ export { IndexPatternsService, IndexPatternsContract, IndexPattern, - IndexPatternsApiClient, + DataViewsApiClient, DataViewsService, DataViewsContract, DataView, diff --git a/src/plugins/data/public/data_views/saved_objects_client_wrapper.test.ts b/src/plugins/data/public/data_views/saved_objects_client_wrapper.test.ts new file mode 100644 index 0000000000000..221a18ac7fab7 --- /dev/null +++ b/src/plugins/data/public/data_views/saved_objects_client_wrapper.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { SavedObjectsClientPublicToCommon } from './saved_objects_client_wrapper'; +import { savedObjectsServiceMock } from 'src/core/public/mocks'; + +import { DataViewSavedObjectConflictError } from '../../common/data_views'; + +describe('SavedObjectsClientPublicToCommon', () => { + const soClient = savedObjectsServiceMock.createStartContract().client; + + test('get saved object - exactMatch', async () => { + const mockedSavedObject = { + version: 'abc', + }; + soClient.resolve = jest + .fn() + .mockResolvedValue({ outcome: 'exactMatch', saved_object: mockedSavedObject }); + const service = new SavedObjectsClientPublicToCommon(soClient); + const result = await service.get('index-pattern', '1'); + expect(result).toStrictEqual(mockedSavedObject); + }); + + test('get saved object - aliasMatch', async () => { + const mockedSavedObject = { + version: 'def', + }; + soClient.resolve = jest + .fn() + .mockResolvedValue({ outcome: 'aliasMatch', saved_object: mockedSavedObject }); + const service = new SavedObjectsClientPublicToCommon(soClient); + const result = await service.get('index-pattern', '1'); + expect(result).toStrictEqual(mockedSavedObject); + }); + + test('get saved object - conflict', async () => { + const mockedSavedObject = { + version: 'ghi', + }; + + soClient.resolve = jest + .fn() + .mockResolvedValue({ outcome: 'conflict', saved_object: mockedSavedObject }); + const service = new SavedObjectsClientPublicToCommon(soClient); + + await expect(service.get('index-pattern', '1')).rejects.toThrow( + DataViewSavedObjectConflictError + ); + }); +}); diff --git a/src/plugins/data/public/data_views/saved_objects_client_wrapper.ts b/src/plugins/data/public/data_views/saved_objects_client_wrapper.ts index f55ca3896df33..1db4e3b1ccd24 100644 --- a/src/plugins/data/public/data_views/saved_objects_client_wrapper.ts +++ b/src/plugins/data/public/data_views/saved_objects_client_wrapper.ts @@ -12,9 +12,10 @@ import { SavedObjectsClientCommon, SavedObjectsClientCommonFindArgs, SavedObject, + DataViewSavedObjectConflictError, } from '../../common/data_views'; -type SOClient = Pick; +type SOClient = Pick; const simpleSavedObjectToSavedObject = (simpleSavedObject: SimpleSavedObject): SavedObject => ({ @@ -33,8 +34,11 @@ export class SavedObjectsClientPublicToCommon implements SavedObjectsClientCommo } async get(type: string, id: string) { - const response = await this.savedObjectClient.get(type, id); - return simpleSavedObjectToSavedObject(response); + const response = await this.savedObjectClient.resolve(type, id); + if (response.outcome === 'conflict') { + throw new DataViewSavedObjectConflictError(id); + } + return simpleSavedObjectToSavedObject(response.saved_object); } async update( type: string, diff --git a/src/plugins/data/public/data_views/ui_settings_wrapper.ts b/src/plugins/data/public/data_views/ui_settings_wrapper.ts index e0998ed72b2e6..f8ae317391fa3 100644 --- a/src/plugins/data/public/data_views/ui_settings_wrapper.ts +++ b/src/plugins/data/public/data_views/ui_settings_wrapper.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { IUiSettingsClient } from 'src/core/public'; +import { IUiSettingsClient, PublicUiSettingsParams, UserProvidedValues } from 'src/core/public'; import { UiSettingsCommon } from '../../common'; export class UiSettingsPublicToCommon implements UiSettingsCommon { @@ -14,11 +14,11 @@ export class UiSettingsPublicToCommon implements UiSettingsCommon { constructor(uiSettings: IUiSettingsClient) { this.uiSettings = uiSettings; } - get(key: string) { + get(key: string): Promise { return Promise.resolve(this.uiSettings.get(key)); } - getAll() { + getAll(): Promise>> { return Promise.resolve(this.uiSettings.getAll()); } diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 6480a0a340340..e1f5b98baca9c 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -45,7 +45,6 @@ import { CONTAINS_SPACES_KEY, ILLEGAL_CHARACTERS_VISIBLE, ILLEGAL_CHARACTERS, - isDefault, validateDataView, flattenHitWrapper, } from './data_views'; @@ -58,7 +57,6 @@ export const indexPatterns = { CONTAINS_SPACES_KEY, ILLEGAL_CHARACTERS_VISIBLE, ILLEGAL_CHARACTERS, - isDefault, isFilterable, isNestedField, validate: validateDataView, diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 63f32e50f61ab..aa766f78a5ecb 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -22,9 +22,9 @@ import { SearchService } from './search/search_service'; import { QueryService } from './query'; import { createIndexPatternSelect } from './ui/index_pattern_select'; import { - IndexPatternsService, + DataViewsService, onRedirectNoIndexPattern, - IndexPatternsApiClient, + DataViewsApiClient, UiSettingsPublicToCommon, } from './data_views'; import { @@ -145,10 +145,10 @@ export class DataPublicPlugin setOverlays(overlays); setUiSettings(uiSettings); - const indexPatterns = new IndexPatternsService({ + const indexPatterns = new DataViewsService({ uiSettings: new UiSettingsPublicToCommon(uiSettings), savedObjectsClient: new SavedObjectsClientPublicToCommon(savedObjects.client), - apiClient: new IndexPatternsApiClient(http), + apiClient: new DataViewsApiClient(http), fieldFormats, onNotification: (toastInputFields) => { notifications.toasts.add(toastInputFields); diff --git a/src/plugins/data/public/search/errors/es_error.test.tsx b/src/plugins/data/public/search/errors/es_error.test.tsx index fd1100ba34afc..4d1bc8b03b8f2 100644 --- a/src/plugins/data/public/search/errors/es_error.test.tsx +++ b/src/plugins/data/public/search/errors/es_error.test.tsx @@ -25,4 +25,31 @@ describe('EsError', () => { expect(typeof esError.attributes).toEqual('object'); expect(esError.attributes).toEqual(error.attributes); }); + + it('contains some explanation of the error in the message', () => { + // error taken from Vega's issue + const error = { + message: + 'x_content_parse_exception: [x_content_parse_exception] Reason: [1:78] [date_histogram] failed to parse field [calendar_interval]', + statusCode: 400, + attributes: { + root_cause: [ + { + type: 'x_content_parse_exception', + reason: '[1:78] [date_histogram] failed to parse field [calendar_interval]', + }, + ], + type: 'x_content_parse_exception', + reason: '[1:78] [date_histogram] failed to parse field [calendar_interval]', + caused_by: { + type: 'illegal_argument_exception', + reason: 'The supplied interval [2q] could not be parsed as a calendar interval.', + }, + }, + } as any; + const esError = new EsError(error); + expect(esError.message).toEqual( + 'EsError: The supplied interval [2q] could not be parsed as a calendar interval.' + ); + }); }); diff --git a/src/plugins/data/public/search/errors/es_error.tsx b/src/plugins/data/public/search/errors/es_error.tsx index 3303d48bf2adb..71c11af48830f 100644 --- a/src/plugins/data/public/search/errors/es_error.tsx +++ b/src/plugins/data/public/search/errors/es_error.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { EuiCodeBlock, EuiSpacer } from '@elastic/eui'; import { ApplicationStart } from 'kibana/public'; +import { i18n } from '@kbn/i18n'; import { KbnError } from '../../../../kibana_utils/common'; import { IEsError } from './types'; import { getRootCause } from './utils'; @@ -17,7 +18,12 @@ export class EsError extends KbnError { readonly attributes: IEsError['attributes']; constructor(protected readonly err: IEsError) { - super('EsError'); + super( + `EsError: ${ + getRootCause(err)?.reason || + i18n.translate('data.esError.unknownRootCause', { defaultMessage: 'unknown' }) + }` + ); this.attributes = err.attributes; } diff --git a/src/plugins/data/public/search/errors/utils.ts b/src/plugins/data/public/search/errors/utils.ts index aba4e965d64c8..cb3e83dc8001c 100644 --- a/src/plugins/data/public/search/errors/utils.ts +++ b/src/plugins/data/public/search/errors/utils.ts @@ -5,8 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - -import { FailedShard } from './types'; +import type { ErrorCause } from '@elastic/elasticsearch/api/types'; +import type { FailedShard, Reason } from './types'; import { KibanaServerError } from '../../../../kibana_utils/common'; export function getFailedShards(err: KibanaServerError): FailedShard | undefined { @@ -15,6 +15,16 @@ export function getFailedShards(err: KibanaServerError): FailedShard | unde return failedShards ? failedShards[0] : undefined; } +function getNestedCause(err: KibanaServerError | ErrorCause): Reason { + const attr = ((err as KibanaServerError).attributes || err) as ErrorCause; + const { type, reason, caused_by: causedBy } = attr; + if (causedBy) { + return getNestedCause(causedBy); + } + return { type, reason }; +} + export function getRootCause(err: KibanaServerError) { - return getFailedShards(err)?.reason; + // Give shard failures priority, then try to get the error navigating nested objects + return getFailedShards(err)?.reason || getNestedCause(err); } diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts index 155638250a2a4..7186938816d5f 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts @@ -501,12 +501,12 @@ describe('SearchInterceptor', () => { opts: { isRestore?: boolean; isStored?: boolean; - sessionId: string; + sessionId?: string; } | null ) => { const sessionServiceMock = sessionService as jest.Mocked; sessionServiceMock.getSearchOptions.mockImplementation(() => - opts + opts && opts.sessionId ? { sessionId: opts.sessionId, isRestore: opts.isRestore ?? false, @@ -515,6 +515,7 @@ describe('SearchInterceptor', () => { : null ); sessionServiceMock.isRestore.mockReturnValue(!!opts?.isRestore); + sessionServiceMock.getSessionId.mockImplementation(() => opts?.sessionId); fetchMock.mockResolvedValue({ result: 200 }); }; @@ -606,6 +607,41 @@ describe('SearchInterceptor', () => { expect(SearchSessionIncompleteWarning).toBeCalledTimes(0); }); + test('should not show warning if a search outside of session is running', async () => { + setup({ + isRestore: false, + isStored: false, + }); + + const responses = [ + { + time: 10, + value: { + isPartial: false, + isRunning: false, + isRestored: false, + id: 1, + rawResponse: { + took: 1, + }, + }, + }, + ]; + mockFetchImplementation(responses); + + const response = searchInterceptor.search( + {}, + { + sessionId: undefined, + } + ); + response.subscribe({ next, error, complete }); + + await timeTravel(10); + + expect(SearchSessionIncompleteWarning).toBeCalledTimes(0); + }); + test('should show warning once if a search is not available during restore', async () => { setup({ isRestore: true, diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts index ff3c173fd18cf..180e826b5bc4e 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts @@ -352,8 +352,14 @@ export class SearchInterceptor { ); }), tap((response) => { - if (this.deps.session.isRestore() && response.isRestored === false) { - this.showRestoreWarning(this.deps.session.getSessionId()); + const isSearchInScopeOfSession = + sessionId && sessionId === this.deps.session.getSessionId(); + if ( + isSearchInScopeOfSession && + this.deps.session.isRestore() && + response.isRestored === false + ) { + this.showRestoreWarning(sessionId); } }), finalize(() => { diff --git a/src/plugins/data/public/stubs.ts b/src/plugins/data/public/stubs.ts index 8e790a2991b05..3d160a56bd8cf 100644 --- a/src/plugins/data/public/stubs.ts +++ b/src/plugins/data/public/stubs.ts @@ -7,4 +7,4 @@ */ export * from '../common/stubs'; -export { createStubIndexPattern } from './data_views/data_views/index_pattern.stub'; +export { createStubDataView } from './data_views/data_views/data_view.stub'; diff --git a/src/plugins/data/server/data_views/routes.ts b/src/plugins/data/server/data_views/routes.ts index 32fa50940bca7..9488285fc7e2c 100644 --- a/src/plugins/data/server/data_views/routes.ts +++ b/src/plugins/data/server/data_views/routes.ts @@ -7,7 +7,7 @@ */ import { schema } from '@kbn/config-schema'; -import { HttpServiceSetup, RequestHandlerContext, StartServicesAccessor } from 'kibana/server'; +import { HttpServiceSetup, StartServicesAccessor } from 'kibana/server'; import { IndexPatternsFetcher } from './fetcher'; import { registerCreateIndexPatternRoute } from './routes/create_index_pattern'; import { registerGetIndexPatternRoute } from './routes/get_index_pattern'; @@ -154,7 +154,7 @@ export function registerRoutes( }), }, }, - async (context: RequestHandlerContext, request: any, response: any) => { + async (context, request, response) => { const { asCurrentUser } = context.core.elasticsearch.client; const indexPatterns = new IndexPatternsFetcher(asCurrentUser); const { pattern, interval, look_back: lookBack, meta_fields: metaFields } = request.query; diff --git a/src/plugins/data/server/data_views/saved_objects_client_wrapper.test.ts b/src/plugins/data/server/data_views/saved_objects_client_wrapper.test.ts new file mode 100644 index 0000000000000..bbe857894b3f0 --- /dev/null +++ b/src/plugins/data/server/data_views/saved_objects_client_wrapper.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { SavedObjectsClientServerToCommon } from './saved_objects_client_wrapper'; +import { SavedObjectsClientContract } from 'src/core/server'; + +import { DataViewSavedObjectConflictError } from '../../common/data_views'; + +describe('SavedObjectsClientPublicToCommon', () => { + const soClient = { resolve: jest.fn() } as unknown as SavedObjectsClientContract; + + test('get saved object - exactMatch', async () => { + const mockedSavedObject = { + version: 'abc', + }; + soClient.resolve = jest + .fn() + .mockResolvedValue({ outcome: 'exactMatch', saved_object: mockedSavedObject }); + const service = new SavedObjectsClientServerToCommon(soClient); + const result = await service.get('index-pattern', '1'); + expect(result).toStrictEqual(mockedSavedObject); + }); + + test('get saved object - aliasMatch', async () => { + const mockedSavedObject = { + version: 'def', + }; + soClient.resolve = jest + .fn() + .mockResolvedValue({ outcome: 'aliasMatch', saved_object: mockedSavedObject }); + const service = new SavedObjectsClientServerToCommon(soClient); + const result = await service.get('index-pattern', '1'); + expect(result).toStrictEqual(mockedSavedObject); + }); + + test('get saved object - conflict', async () => { + const mockedSavedObject = { + version: 'ghi', + }; + + soClient.resolve = jest + .fn() + .mockResolvedValue({ outcome: 'conflict', saved_object: mockedSavedObject }); + const service = new SavedObjectsClientServerToCommon(soClient); + + await expect(service.get('index-pattern', '1')).rejects.toThrow( + DataViewSavedObjectConflictError + ); + }); +}); diff --git a/src/plugins/data/server/data_views/saved_objects_client_wrapper.ts b/src/plugins/data/server/data_views/saved_objects_client_wrapper.ts index 45ad8d85f6086..b37648a3f038e 100644 --- a/src/plugins/data/server/data_views/saved_objects_client_wrapper.ts +++ b/src/plugins/data/server/data_views/saved_objects_client_wrapper.ts @@ -10,6 +10,7 @@ import { SavedObjectsClientContract, SavedObject } from 'src/core/server'; import { SavedObjectsClientCommon, SavedObjectsClientCommonFindArgs, + DataViewSavedObjectConflictError, } from '../../common/data_views'; export class SavedObjectsClientServerToCommon implements SavedObjectsClientCommon { @@ -23,7 +24,11 @@ export class SavedObjectsClientServerToCommon implements SavedObjectsClientCommo } async get(type: string, id: string) { - return await this.savedObjectClient.get(type, id); + const response = await this.savedObjectClient.resolve(type, id); + if (response.outcome === 'conflict') { + throw new DataViewSavedObjectConflictError(id); + } + return response.saved_object; } async update( type: string, diff --git a/src/plugins/data/server/data_views/ui_settings_wrapper.ts b/src/plugins/data/server/data_views/ui_settings_wrapper.ts index 3b00aab7d6bdd..dce552205db2e 100644 --- a/src/plugins/data/server/data_views/ui_settings_wrapper.ts +++ b/src/plugins/data/server/data_views/ui_settings_wrapper.ts @@ -14,11 +14,11 @@ export class UiSettingsServerToCommon implements UiSettingsCommon { constructor(uiSettings: IUiSettingsClient) { this.uiSettings = uiSettings; } - get(key: string) { + get(key: string): Promise { return this.uiSettings.get(key); } - getAll() { + getAll(): Promise> { return this.uiSettings.getAll(); } diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 9d2e94bcf15c0..a17c66c694b2d 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -54,6 +54,7 @@ export { IndexPattern, IndexPatternsService, IndexPatternsService as IndexPatternsCommonService, + DataView, } from '../common'; /** diff --git a/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.test.ts b/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.test.ts index 58a5e875f7c93..d32080928d630 100644 --- a/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/eql_search/eql_search_strategy.test.ts @@ -132,7 +132,6 @@ describe('EQL search strategy', () => { expect(request).toEqual( expect.objectContaining({ ignore_unavailable: true, - ignore_throttled: true, }) ); }); diff --git a/src/plugins/data/server/search/strategies/ese_search/request_utils.test.ts b/src/plugins/data/server/search/strategies/ese_search/request_utils.test.ts index 272e41e8bf82d..91b323de7c07b 100644 --- a/src/plugins/data/server/search/strategies/ese_search/request_utils.test.ts +++ b/src/plugins/data/server/search/strategies/ese_search/request_utils.test.ts @@ -31,12 +31,12 @@ const getMockSearchSessionsConfig = ({ describe('request utils', () => { describe('getIgnoreThrottled', () => { - test('returns `ignore_throttled` as `true` when `includeFrozen` is `false`', async () => { + test('does not return `ignore_throttled` when `includeFrozen` is `false`', async () => { const mockUiSettingsClient = getMockUiSettingsClient({ [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: false, }); const result = await getIgnoreThrottled(mockUiSettingsClient); - expect(result.ignore_throttled).toBe(true); + expect(result).not.toHaveProperty('ignore_throttled'); }); test('returns `ignore_throttled` as `false` when `includeFrozen` is `true`', async () => { diff --git a/src/plugins/data/server/search/strategies/ese_search/request_utils.ts b/src/plugins/data/server/search/strategies/ese_search/request_utils.ts index 8bf4473355ccf..e224215571ca9 100644 --- a/src/plugins/data/server/search/strategies/ese_search/request_utils.ts +++ b/src/plugins/data/server/search/strategies/ese_search/request_utils.ts @@ -23,7 +23,7 @@ export async function getIgnoreThrottled( uiSettingsClient: IUiSettingsClient ): Promise> { const includeFrozen = await uiSettingsClient.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN); - return { ignore_throttled: !includeFrozen }; + return includeFrozen ? { ignore_throttled: false } : {}; } /** diff --git a/src/plugins/discover/public/__mocks__/start_contract.ts b/src/plugins/discover/public/__mocks__/start_contract.ts new file mode 100644 index 0000000000000..ac53eb4978c9d --- /dev/null +++ b/src/plugins/discover/public/__mocks__/start_contract.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { ApplicationStart, PublicAppInfo } from 'src/core/public'; +import { deepFreeze } from '@kbn/std'; +import { BehaviorSubject, Subject } from 'rxjs'; + +const capabilities = deepFreeze({ + catalogue: {}, + management: {}, + navLinks: {}, + discover: { + show: true, + edit: false, + }, +}); + +export const createStartContractMock = (): jest.Mocked => { + const currentAppId$ = new Subject(); + + return { + applications$: new BehaviorSubject>(new Map()), + currentAppId$: currentAppId$.asObservable(), + capabilities, + navigateToApp: jest.fn(), + navigateToUrl: jest.fn(), + getUrlForApp: jest.fn(), + }; +}; diff --git a/src/plugins/discover/public/application/apps/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/apps/main/components/layout/discover_layout.tsx index 7e3d7ff10b3a6..c2d09f31e3e0a 100644 --- a/src/plugins/discover/public/application/apps/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/apps/main/components/layout/discover_layout.tsx @@ -23,11 +23,7 @@ import { METRIC_TYPE } from '@kbn/analytics'; import classNames from 'classnames'; import { DiscoverNoResults } from '../no_results'; import { LoadingSpinner } from '../loading_spinner/loading_spinner'; -import { - esFilters, - IndexPatternField, - indexPatterns as indexPatternsUtils, -} from '../../../../../../../data/public'; +import { esFilters, IndexPatternField } from '../../../../../../../data/public'; import { DiscoverSidebarResponsive } from '../sidebar'; import { DiscoverLayoutProps } from './types'; import { SEARCH_FIELDS_FROM_SOURCE } from '../../../../../../common'; @@ -79,7 +75,7 @@ export function DiscoverLayout({ }, [dataState.fetchStatus]); const timeField = useMemo(() => { - return indexPatternsUtils.isDefault(indexPattern) ? indexPattern.timeFieldName : undefined; + return indexPattern.type !== 'rollup' ? indexPattern.timeFieldName : undefined; }, [indexPattern]); const [isSidebarClosed, setIsSidebarClosed] = useState(false); diff --git a/src/plugins/discover/public/application/apps/main/components/sidebar/__snapshots__/discover_index_pattern_management.test.tsx.snap b/src/plugins/discover/public/application/apps/main/components/sidebar/__snapshots__/discover_index_pattern_management.test.tsx.snap index 3ad902ed22fe8..ebb06e0b2ecd3 100644 --- a/src/plugins/discover/public/application/apps/main/components/sidebar/__snapshots__/discover_index_pattern_management.test.tsx.snap +++ b/src/plugins/discover/public/application/apps/main/components/sidebar/__snapshots__/discover_index_pattern_management.test.tsx.snap @@ -106,7 +106,7 @@ exports[`Discover IndexPattern Management renders correctly 1`] = ` } } selectedIndexPattern={ - IndexPattern { + DataView { "allowNoIndex": false, "deleteFieldFormat": [Function], "fieldAttrs": Object {}, diff --git a/src/plugins/discover/public/application/apps/main/components/top_nav/get_top_nav_links.ts b/src/plugins/discover/public/application/apps/main/components/top_nav/get_top_nav_links.ts index 58a7242974ba2..ba4cd8c3cd524 100644 --- a/src/plugins/discover/public/application/apps/main/components/top_nav/get_top_nav_links.ts +++ b/src/plugins/discover/public/application/apps/main/components/top_nav/get_top_nav_links.ts @@ -112,7 +112,7 @@ export const getTopNavLinks = ({ const sharingData = await getSharingData( searchSource, state.appStateContainer.getState(), - services.uiSettings + services ); services.share.toggleShareContextMenu({ diff --git a/src/plugins/discover/public/application/apps/main/discover_main_route.tsx b/src/plugins/discover/public/application/apps/main/discover_main_route.tsx index 53f95f38c96bd..5141908e44ade 100644 --- a/src/plugins/discover/public/application/apps/main/discover_main_route.tsx +++ b/src/plugins/discover/public/application/apps/main/discover_main_route.tsx @@ -59,7 +59,7 @@ export function DiscoverMainRoute({ services, history }: DiscoverMainProps) { const savedSearchId = id; async function loadDefaultOrCurrentIndexPattern(usedSavedSearch: SavedSearch) { - await data.indexPatterns.ensureDefaultIndexPattern(); + await data.indexPatterns.ensureDefaultDataView(); const { appStateContainer } = getState({ history, uiSettings: config }); const { index } = appStateContainer.getState(); const ip = await loadIndexPattern(index || '', data.indexPatterns, config); diff --git a/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.test.ts b/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.test.ts index 25d0ca5d66eb4..e7205c3f9bc69 100644 --- a/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.test.ts +++ b/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.test.ts @@ -7,32 +7,37 @@ */ import { Capabilities, IUiSettingsClient } from 'kibana/public'; -import { IndexPattern } from 'src/plugins/data/public'; +import type { IndexPattern } from 'src/plugins/data/public'; +import type { DiscoverServices } from '../../../../build_services'; +import { dataPluginMock } from '../../../../../../data/public/mocks'; import { createSearchSourceMock } from '../../../../../../data/common/search/search_source/mocks'; import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../../../common'; import { indexPatternMock } from '../../../../__mocks__/index_pattern'; import { getSharingData, showPublicUrlSwitch } from './get_sharing_data'; describe('getSharingData', () => { - let mockConfig: IUiSettingsClient; + let services: DiscoverServices; beforeEach(() => { - mockConfig = { - get: (key: string) => { - if (key === SORT_DEFAULT_ORDER_SETTING) { - return 'desc'; - } - if (key === DOC_HIDE_TIME_COLUMN_SETTING) { + services = { + data: dataPluginMock.createStartContract(), + uiSettings: { + get: (key: string) => { + if (key === SORT_DEFAULT_ORDER_SETTING) { + return 'desc'; + } + if (key === DOC_HIDE_TIME_COLUMN_SETTING) { + return false; + } return false; - } - return false; + }, }, - } as unknown as IUiSettingsClient; + } as DiscoverServices; }); test('returns valid data for sharing', async () => { const searchSourceMock = createSearchSourceMock({ index: indexPatternMock }); - const result = await getSharingData(searchSourceMock, { columns: [] }, mockConfig); + const result = await getSharingData(searchSourceMock, { columns: [] }, services); expect(result).toMatchInlineSnapshot(` Object { "columns": Array [], @@ -53,7 +58,7 @@ describe('getSharingData', () => { const result = await getSharingData( searchSourceMock, { columns: ['column_a', 'column_b'] }, - mockConfig + services ); expect(result).toMatchInlineSnapshot(` Object { @@ -90,7 +95,7 @@ describe('getSharingData', () => { 'cool-field-6', ], }, - mockConfig + services ); expect(result).toMatchInlineSnapshot(` Object { @@ -116,7 +121,7 @@ describe('getSharingData', () => { }); test('fields conditionally do not have prepended timeField', async () => { - mockConfig = { + services.uiSettings = { get: (key: string) => { if (key === DOC_HIDE_TIME_COLUMN_SETTING) { return true; @@ -141,7 +146,7 @@ describe('getSharingData', () => { 'cool-field-6', ], }, - mockConfig + services ); expect(result).toMatchInlineSnapshot(` Object { diff --git a/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.ts b/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.ts index 65001f49f4d68..420ff0fa11eeb 100644 --- a/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.ts +++ b/src/plugins/discover/public/application/apps/main/utils/get_sharing_data.ts @@ -6,8 +6,10 @@ * Side Public License, v 1. */ -import type { Capabilities, IUiSettingsClient } from 'kibana/public'; -import { ISearchSource } from '../../../../../../data/common'; +import type { Capabilities } from 'kibana/public'; +import type { IUiSettingsClient } from 'src/core/public'; +import type { DataPublicPluginStart } from 'src/plugins/data/public'; +import type { ISearchSource } from 'src/plugins/data/common'; import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../../../common'; import type { SavedSearch, SortOrder } from '../../../../saved_searches/types'; import { getSortForSearchSource } from '../components/doc_table'; @@ -19,8 +21,9 @@ import { AppState } from '../services/discover_state'; export async function getSharingData( currentSearchSource: ISearchSource, state: AppState | SavedSearch, - config: IUiSettingsClient + services: { uiSettings: IUiSettingsClient; data: DataPublicPluginStart } ) { + const { uiSettings: config, data } = services; const searchSource = currentSearchSource.createCopy(); const index = searchSource.getField('index')!; @@ -28,6 +31,8 @@ export async function getSharingData( 'sort', getSortForSearchSource(state.sort as SortOrder[], index, config.get(SORT_DEFAULT_ORDER_SETTING)) ); + // When sharing externally we preserve relative time values + searchSource.setField('filter', data.query.timefilter.timefilter.createRelativeFilter(index)); searchSource.removeField('highlight'); searchSource.removeField('highlightAll'); searchSource.removeField('aggs'); diff --git a/src/plugins/discover/public/application/apps/main/utils/update_search_source.ts b/src/plugins/discover/public/application/apps/main/utils/update_search_source.ts index 74e63c399743f..4dfcbc7b79712 100644 --- a/src/plugins/discover/public/application/apps/main/utils/update_search_source.ts +++ b/src/plugins/discover/public/application/apps/main/utils/update_search_source.ts @@ -10,7 +10,6 @@ import { SORT_DEFAULT_ORDER_SETTING } from '../../../../../common'; import { IndexPattern, ISearchSource } from '../../../../../../data/common'; import { SortOrder } from '../../../../saved_searches/types'; import { DiscoverServices } from '../../../../build_services'; -import { indexPatterns as indexPatternsUtils } from '../../../../../../data/public'; import { getSortForSearchSource } from '../components/doc_table'; /** @@ -52,12 +51,9 @@ export function updateSearchSource( // document-like response. .setPreferredSearchStrategyId('default'); - // this is not the default index pattern, it determines that it's not of type rollup - if (indexPatternsUtils.isDefault(indexPattern)) { - searchSource.setField( - 'filter', - data.query.timefilter.timefilter.createRelativeFilter(indexPattern) - ); + if (indexPattern.type !== 'rollup') { + // Set the date range filter fields from timeFilter using the absolute format. Search sessions requires that it be converted from a relative range + searchSource.setField('filter', data.query.timefilter.timefilter.createFilter(indexPattern)); } if (useNewFieldsApi) { diff --git a/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx b/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx index 500bad34e2758..ef8670f976672 100644 --- a/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx +++ b/src/plugins/discover/public/application/embeddable/saved_search_embeddable.tsx @@ -216,7 +216,7 @@ export class SavedSearchEmbeddable if (!this.savedSearch.sort || !this.savedSearch.sort.length) { this.savedSearch.sort = getDefaultSort( indexPattern, - getServices().uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc') + this.services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc') ); } @@ -226,7 +226,7 @@ export class SavedSearchEmbeddable isLoading: false, sort: getDefaultSort( indexPattern, - getServices().uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc') + this.services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc') ), rows: [], searchDescription: this.savedSearch.description, diff --git a/src/plugins/discover/public/application/embeddable/view_saved_search_action.test.ts b/src/plugins/discover/public/application/embeddable/view_saved_search_action.test.ts new file mode 100644 index 0000000000000..5796dacaa83d8 --- /dev/null +++ b/src/plugins/discover/public/application/embeddable/view_saved_search_action.test.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ContactCardEmbeddable } from 'src/plugins/embeddable/public/lib/test_samples'; + +import { ViewSavedSearchAction } from './view_saved_search_action'; +import { SavedSearchEmbeddable } from './saved_search_embeddable'; +import { createStartContractMock } from '../../__mocks__/start_contract'; +import { savedSearchMock } from '../../__mocks__/saved_search'; +import { discoverServiceMock } from '../../__mocks__/services'; +import { IndexPattern } from 'src/plugins/data/common'; +import { createFilterManagerMock } from 'src/plugins/data/public/query/filter_manager/filter_manager.mock'; +import { ViewMode } from 'src/plugins/embeddable/public'; + +const applicationMock = createStartContractMock(); +const savedSearch = savedSearchMock; +const indexPatterns = [] as IndexPattern[]; +const services = discoverServiceMock; +const filterManager = createFilterManagerMock(); +const searchInput = { + timeRange: { + from: '2021-09-15', + to: '2021-09-16', + }, + id: '1', + viewMode: ViewMode.VIEW, +}; +const executeTriggerActions = async (triggerId: string, context: object) => { + return Promise.resolve(undefined); +}; +const trigger = { id: 'ACTION_VIEW_SAVED_SEARCH' }; +const embeddableConfig = { + savedSearch, + editUrl: '', + editPath: '', + indexPatterns, + editable: true, + filterManager, + services, +}; + +describe('view saved search action', () => { + it('is compatible when embeddable is of type saved search, in view mode && appropriate permissions are set', async () => { + const action = new ViewSavedSearchAction(applicationMock); + const embeddable = new SavedSearchEmbeddable( + embeddableConfig, + searchInput, + executeTriggerActions + ); + expect(await action.isCompatible({ embeddable, trigger })).toBe(true); + }); + + it('is not compatible when embeddable not of type saved search', async () => { + const action = new ViewSavedSearchAction(applicationMock); + const embeddable = new ContactCardEmbeddable( + { + id: '123', + firstName: 'sue', + viewMode: ViewMode.EDIT, + }, + { + execAction: () => Promise.resolve(undefined), + } + ); + expect( + await action.isCompatible({ + embeddable, + trigger, + }) + ).toBe(false); + }); + + it('is not visible when in edit mode', async () => { + const action = new ViewSavedSearchAction(applicationMock); + const input = { ...searchInput, viewMode: ViewMode.EDIT }; + const embeddable = new SavedSearchEmbeddable(embeddableConfig, input, executeTriggerActions); + expect( + await action.isCompatible({ + embeddable, + trigger, + }) + ).toBe(false); + }); + + it('execute navigates to a saved search', async () => { + const action = new ViewSavedSearchAction(applicationMock); + const embeddable = new SavedSearchEmbeddable( + embeddableConfig, + searchInput, + executeTriggerActions + ); + await action.execute({ embeddable, trigger }); + expect(applicationMock.navigateToApp).toHaveBeenCalledWith('discover', { + path: `#/view/${savedSearch.id}`, + }); + }); +}); diff --git a/src/plugins/discover/public/application/embeddable/view_saved_search_action.ts b/src/plugins/discover/public/application/embeddable/view_saved_search_action.ts new file mode 100644 index 0000000000000..69c273f326c61 --- /dev/null +++ b/src/plugins/discover/public/application/embeddable/view_saved_search_action.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { ActionExecutionContext } from 'src/plugins/ui_actions/public'; +import { ApplicationStart } from 'kibana/public'; +import { i18n } from '@kbn/i18n'; +import { IEmbeddable, ViewMode } from '../../../../embeddable/public'; +import { Action } from '../../../../ui_actions/public'; +import { SavedSearchEmbeddable } from './saved_search_embeddable'; +import { SEARCH_EMBEDDABLE_TYPE } from '../../../common'; + +export const ACTION_VIEW_SAVED_SEARCH = 'ACTION_VIEW_SAVED_SEARCH'; + +export interface ViewSearchContext { + embeddable: IEmbeddable; +} + +export class ViewSavedSearchAction implements Action { + public id = ACTION_VIEW_SAVED_SEARCH; + public readonly type = ACTION_VIEW_SAVED_SEARCH; + + constructor(private readonly application: ApplicationStart) {} + + async execute(context: ActionExecutionContext): Promise { + const { embeddable } = context; + const savedSearchId = (embeddable as SavedSearchEmbeddable).getSavedSearch().id; + const path = `#/view/${encodeURIComponent(savedSearchId)}`; + const app = embeddable ? embeddable.getOutput().editApp : undefined; + await this.application.navigateToApp(app ? app : 'discover', { path }); + } + + getDisplayName(context: ActionExecutionContext): string { + return i18n.translate('discover.savedSearchEmbeddable.action.viewSavedSearch.displayName', { + defaultMessage: 'Open in Discover', + }); + } + + getIconType(context: ActionExecutionContext): string | undefined { + return 'inspect'; + } + + async isCompatible(context: ActionExecutionContext) { + const { embeddable } = context; + const { capabilities } = this.application; + const hasDiscoverPermissions = + (capabilities.discover.show as boolean) || (capabilities.discover.save as boolean); + return Boolean( + embeddable.type === SEARCH_EMBEDDABLE_TYPE && + embeddable.getInput().viewMode === ViewMode.VIEW && + hasDiscoverPermissions + ); + } +} diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 0327b25fd864e..afb83d6cbd667 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -60,6 +60,7 @@ import { UsageCollectionSetup } from '../../usage_collection/public'; import { replaceUrlHashQuery } from '../../kibana_utils/public/'; import { IndexPatternFieldEditorStart } from '../../../plugins/index_pattern_field_editor/public'; import { DeferredSpinner } from './shared'; +import { ViewSavedSearchAction } from './application/embeddable/view_saved_search_action'; declare module '../../share/public' { export interface UrlGeneratorStateMapping { @@ -397,6 +398,10 @@ export class DiscoverPlugin // initializeServices are assigned at start and used // when the application/embeddable is mounted + const { uiActions } = plugins; + + const viewSavedSearchAction = new ViewSavedSearchAction(core.application); + uiActions.addTriggerAction('CONTEXT_MENU_TRIGGER', viewSavedSearchAction); setUiActions(plugins.uiActions); const services = buildServices(core, plugins, this.initializerContext); diff --git a/src/plugins/discover/server/saved_objects/search.ts b/src/plugins/discover/server/saved_objects/search.ts index 070f0253f17e0..46284f3cf33b6 100644 --- a/src/plugins/discover/server/saved_objects/search.ts +++ b/src/plugins/discover/server/saved_objects/search.ts @@ -20,9 +20,6 @@ export const searchSavedObjectType: SavedObjectsType = { getTitle(obj) { return obj.attributes.title; }, - getEditUrl(obj) { - return `/management/kibana/objects/savedSearches/${encodeURIComponent(obj.id)}`; - }, getInAppUrl(obj) { return { path: `/app/discover#/view/${encodeURIComponent(obj.id)}`, diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx index 801320adcc470..7e393c6fc14e1 100644 --- a/src/plugins/embeddable/public/plugin.tsx +++ b/src/plugins/embeddable/public/plugin.tsx @@ -173,8 +173,8 @@ export class EmbeddablePublicPlugin implements Plugin { const contactCardFactory = new ContactCardEmbeddableFactory( uiActions.executeTriggerActions, - ({} as unknown) as OverlayStart + {} as unknown as OverlayStart ); setup.registerEmbeddableFactory(contactCardFactory.type, contactCardFactory); diff --git a/src/plugins/embeddable/server/plugin.ts b/src/plugins/embeddable/server/plugin.ts index f50bb3a85766d..f9ad0a1bda372 100644 --- a/src/plugins/embeddable/server/plugin.ts +++ b/src/plugins/embeddable/server/plugin.ts @@ -45,8 +45,8 @@ export class EmbeddableServerPlugin implements Plugin { } public get(id: string): ExpressionType | null { - return this.executor.state.selectors.getType(id); + return this.executor.getType(id) ?? null; } public toJS(): Record { @@ -71,7 +71,7 @@ export class FunctionsRegistry implements IRegistry { } public get(id: string): ExpressionFunction | null { - return this.executor.state.selectors.getFunction(id); + return this.executor.getFunction(id) ?? null; } public toJS(): Record { @@ -95,22 +95,44 @@ export class Executor = Record; + public readonly container: ExecutorContainer; /** * @deprecated */ - public readonly functions: FunctionsRegistry; + public readonly functions = new FunctionsRegistry(this); /** * @deprecated */ - public readonly types: TypesRegistry; + public readonly types = new TypesRegistry(this); + + protected parent?: Executor; constructor(state?: ExecutorState) { - this.state = createExecutorContainer(state); - this.functions = new FunctionsRegistry(this); - this.types = new TypesRegistry(this); + this.container = createExecutorContainer(state); + } + + public get state(): ExecutorState { + const parent = this.parent?.state; + const state = this.container.get(); + + return { + ...(parent ?? {}), + ...state, + types: { + ...(parent?.types ?? {}), + ...state.types, + }, + functions: { + ...(parent?.functions ?? {}), + ...state.functions, + }, + context: { + ...(parent?.context ?? {}), + ...state.context, + }, + }; } public registerFunction( @@ -119,15 +141,18 @@ export class Executor = Record { - return { ...this.state.get().functions }; + return { + ...(this.parent?.getFunctions() ?? {}), + ...this.container.get().functions, + }; } public registerType( @@ -136,23 +161,30 @@ export class Executor = Record { - return { ...this.state.get().types }; + return { + ...(this.parent?.getTypes() ?? {}), + ...this.container.get().types, + }; } public extendContext(extraContext: Record) { - this.state.transitions.extendContext(extraContext); + this.container.transitions.extendContext(extraContext); } public get context(): Record { - return this.state.selectors.getContext(); + return { + ...(this.parent?.context ?? {}), + ...this.container.selectors.getContext(), + }; } /** @@ -199,18 +231,15 @@ export class Executor = Record { - return asts.map((arg) => { - if (arg && typeof arg === 'object') { - return this.walkAst(arg, action); - } - return arg; - }); - }); + link.arguments = mapValues(fnArgs, (asts) => + asts.map((arg) => + arg != null && typeof arg === 'object' ? this.walkAst(arg, action) : arg + ) + ); action(fn, link); } @@ -275,39 +304,19 @@ export class Executor = Record { - if (!fn.migrations[version]) return link; - const updatedAst = fn.migrations[version](link) as ExpressionAstFunction; - link.arguments = updatedAst.arguments; - link.type = updatedAst.type; + if (!fn.migrations[version]) { + return; + } + + ({ arguments: link.arguments, type: link.type } = fn.migrations[version]( + link + ) as ExpressionAstFunction); }); } public fork(): Executor { - const initialState = this.state.get(); - const fork = new Executor(initialState); - - /** - * Synchronize registry state - make any new types, functions and context - * also available in the forked instance of `Executor`. - */ - this.state.state$.subscribe(({ types, functions, context }) => { - const state = fork.state.get(); - fork.state.set({ - ...state, - types: { - ...types, - ...state.types, - }, - functions: { - ...functions, - ...state.functions, - }, - context: { - ...context, - ...state.context, - }, - }); - }); + const fork = new Executor(); + fork.parent = this; return fork; } diff --git a/src/plugins/expressions/common/expression_functions/specs/map_column.ts b/src/plugins/expressions/common/expression_functions/specs/map_column.ts index d897e24aaad83..23aeee6f9581b 100644 --- a/src/plugins/expressions/common/expression_functions/specs/map_column.ts +++ b/src/plugins/expressions/common/expression_functions/specs/map_column.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ -import { Observable, defer, of, zip } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { Observable, combineLatest, defer } from 'rxjs'; +import { defaultIfEmpty, map } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import { ExpressionFunctionDefinition } from '../types'; -import { Datatable, DatatableColumn, DatatableColumnType, getType } from '../../expression_types'; +import { Datatable, DatatableColumnType, getType } from '../../expression_types'; export interface MapColumnArguments { id?: string | null; @@ -81,64 +81,59 @@ export const mapColumn: ExpressionFunctionDefinition< }, }, fn(input, args) { + const metaColumn = args.copyMetaFrom + ? input.columns.find(({ id }) => id === args.copyMetaFrom) + : undefined; const existingColumnIndex = input.columns.findIndex(({ id, name }) => args.id ? id === args.id : name === args.name ); - const id = input.columns[existingColumnIndex]?.id ?? args.id ?? args.name; + const columnIndex = existingColumnIndex === -1 ? input.columns.length : existingColumnIndex; + const id = input.columns[columnIndex]?.id ?? args.id ?? args.name; - return defer(() => { - const rows$ = input.rows.length - ? zip( - ...input.rows.map((row) => - args - .expression({ - type: 'datatable', - columns: [...input.columns], - rows: [row], - }) - .pipe(map((value) => ({ ...row, [id]: value }))) + return defer(() => + combineLatest( + input.rows.map((row) => + args + .expression({ + type: 'datatable', + columns: [...input.columns], + rows: [row], + }) + .pipe( + map((value) => ({ ...row, [id]: value })), + defaultIfEmpty(row) ) - ) - : of([]); - - return rows$.pipe( - map((rows) => { - let type: DatatableColumnType = 'null'; - if (rows.length) { - for (const row of rows) { - const rowType = getType(row[id]); - if (rowType !== 'null') { - type = rowType; - break; - } - } - } - const newColumn: DatatableColumn = { - id, - name: args.name, - meta: { type, params: { id: type } }, - }; - if (args.copyMetaFrom) { - const metaSourceFrom = input.columns.find( - ({ id: columnId }) => columnId === args.copyMetaFrom - ); - newColumn.meta = { ...newColumn.meta, ...(metaSourceFrom?.meta ?? {}) }; + ) + ) + ).pipe( + defaultIfEmpty([] as Datatable['rows']), + map((rows) => { + let type: DatatableColumnType = 'null'; + for (const row of rows) { + const rowType = getType(row[id]); + if (rowType !== 'null') { + type = rowType; + break; } + } - const columns = [...input.columns]; - if (existingColumnIndex === -1) { - columns.push(newColumn); - } else { - columns[existingColumnIndex] = newColumn; - } + const columns = [...input.columns]; + columns[columnIndex] = { + id, + name: args.name, + meta: { + type, + params: { id: type }, + ...(metaColumn?.meta ?? {}), + }, + }; - return { - columns, - rows, - type: 'datatable', - }; - }) - ); - }); + return { + columns, + rows, + type: 'datatable', + }; + }) + ); }, }; diff --git a/src/plugins/expressions/common/expression_functions/specs/tests/map_column.test.ts b/src/plugins/expressions/common/expression_functions/specs/tests/map_column.test.ts index 64a42958ae8a2..6bac0885dc9cc 100644 --- a/src/plugins/expressions/common/expression_functions/specs/tests/map_column.test.ts +++ b/src/plugins/expressions/common/expression_functions/specs/tests/map_column.test.ts @@ -12,8 +12,9 @@ import { Datatable } from '../../../expression_types'; import { mapColumn, MapColumnArguments } from '../map_column'; import { emptyTable, functionWrapper, testTable, tableWithNulls } from './utils'; -const pricePlusTwo = (datatable: Datatable) => - of(typeof datatable.rows[0].price === 'number' ? datatable.rows[0].price + 2 : null); +const pricePlusTwo = jest.fn((datatable: Datatable) => + of(typeof datatable.rows[0].price === 'number' ? datatable.rows[0].price + 2 : null) +); describe('mapColumn', () => { const fn = functionWrapper(mapColumn); @@ -266,4 +267,33 @@ describe('mapColumn', () => { ]); }); }); + + it('supports partial results', () => { + testScheduler.run(({ expectObservable, cold }) => { + pricePlusTwo.mockReturnValueOnce(cold('ab|', { a: 1000, b: 2000 })); + + expectObservable( + runFn(testTable, { + id: 'pricePlusTwo', + name: 'pricePlusTwo', + expression: pricePlusTwo, + }) + ).toBe('01|', [ + expect.objectContaining({ + rows: expect.arrayContaining([ + expect.objectContaining({ + pricePlusTwo: 1000, + }), + ]), + }), + expect.objectContaining({ + rows: expect.arrayContaining([ + expect.objectContaining({ + pricePlusTwo: 2000, + }), + ]), + }), + ]); + }); + }); }); diff --git a/src/plugins/expressions/common/service/expressions_services.test.ts b/src/plugins/expressions/common/service/expressions_services.test.ts index db73d300e1273..620917dc64d4d 100644 --- a/src/plugins/expressions/common/service/expressions_services.test.ts +++ b/src/plugins/expressions/common/service/expressions_services.test.ts @@ -17,11 +17,16 @@ describe('ExpressionsService', () => { const expressions = new ExpressionsService(); expect(expressions.setup()).toMatchObject({ + getFunction: expect.any(Function), getFunctions: expect.any(Function), + getRenderer: expect.any(Function), + getRenderers: expect.any(Function), + getType: expect.any(Function), + getTypes: expect.any(Function), registerFunction: expect.any(Function), registerType: expect.any(Function), registerRenderer: expect.any(Function), - run: expect.any(Function), + fork: expect.any(Function), }); }); @@ -30,7 +35,16 @@ describe('ExpressionsService', () => { expressions.setup(); expect(expressions.start()).toMatchObject({ + getFunction: expect.any(Function), getFunctions: expect.any(Function), + getRenderer: expect.any(Function), + getRenderers: expect.any(Function), + getType: expect.any(Function), + getTypes: expect.any(Function), + registerFunction: expect.any(Function), + registerType: expect.any(Function), + registerRenderer: expect.any(Function), + execute: expect.any(Function), run: expect.any(Function), }); }); @@ -54,21 +68,21 @@ describe('ExpressionsService', () => { const service = new ExpressionsService(); const fork = service.fork(); - expect(fork.executor.state.get().types).toEqual(service.executor.state.get().types); + expect(fork.getTypes()).toEqual(service.getTypes()); }); test('fork keeps all functions of the origin service', () => { const service = new ExpressionsService(); const fork = service.fork(); - expect(fork.executor.state.get().functions).toEqual(service.executor.state.get().functions); + expect(fork.getFunctions()).toEqual(service.getFunctions()); }); test('fork keeps context of the origin service', () => { const service = new ExpressionsService(); const fork = service.fork(); - expect(fork.executor.state.get().context).toEqual(service.executor.state.get().context); + expect(fork.executor.state.context).toEqual(service.executor.state.context); }); test('newly registered functions in origin are also available in fork', () => { @@ -82,7 +96,7 @@ describe('ExpressionsService', () => { fn: () => {}, }); - expect(fork.executor.state.get().functions).toEqual(service.executor.state.get().functions); + expect(fork.getFunctions()).toEqual(service.getFunctions()); }); test('newly registered functions in fork are NOT available in origin', () => { @@ -96,14 +110,15 @@ describe('ExpressionsService', () => { fn: () => {}, }); - expect(Object.values(fork.executor.state.get().functions)).toHaveLength( - Object.values(service.executor.state.get().functions).length + 1 + expect(Object.values(fork.getFunctions())).toHaveLength( + Object.values(service.getFunctions()).length + 1 ); }); test('fork can execute an expression with newly registered function', async () => { const service = new ExpressionsService(); const fork = service.fork(); + fork.start(); service.registerFunction({ name: '__test__', @@ -118,5 +133,28 @@ describe('ExpressionsService', () => { expect(result).toBe('123'); }); + + test('throw on fork if the service is already started', async () => { + const service = new ExpressionsService(); + service.start(); + + expect(() => service.fork()).toThrow(); + }); + }); + + describe('.execute()', () => { + test('throw if the service is not started', () => { + const expressions = new ExpressionsService(); + + expect(() => expressions.execute('foo', null)).toThrow(); + }); + }); + + describe('.run()', () => { + test('throw if the service is not started', () => { + const expressions = new ExpressionsService(); + + expect(() => expressions.run('foo', null)).toThrow(); + }); }); }); diff --git a/src/plugins/expressions/common/service/expressions_services.ts b/src/plugins/expressions/common/service/expressions_services.ts index 2be4f5207bb82..f21eaa34d7868 100644 --- a/src/plugins/expressions/common/service/expressions_services.ts +++ b/src/plugins/expressions/common/service/expressions_services.ts @@ -41,22 +41,86 @@ import { * The public contract that `ExpressionsService` provides to other plugins * in Kibana Platform in *setup* life-cycle. */ -export type ExpressionsServiceSetup = Pick< - ExpressionsService, - | 'getFunction' - | 'getFunctions' - | 'getRenderer' - | 'getRenderers' - | 'getType' - | 'getTypes' - | 'registerFunction' - | 'registerRenderer' - | 'registerType' - | 'run' - | 'fork' - | 'extract' - | 'inject' ->; +export interface ExpressionsServiceSetup { + /** + * Get a registered `ExpressionFunction` by its name, which was registered + * using the `registerFunction` method. The returned `ExpressionFunction` + * instance is an internal representation of the function in Expressions + * service - do not mutate that object. + * @deprecated Use start contract instead. + */ + getFunction(name: string): ReturnType; + + /** + * Returns POJO map of all registered expression functions, where keys are + * names of the functions and values are `ExpressionFunction` instances. + * @deprecated Use start contract instead. + */ + getFunctions(): ReturnType; + + /** + * Returns POJO map of all registered expression types, where keys are + * names of the types and values are `ExpressionType` instances. + * @deprecated Use start contract instead. + */ + getTypes(): ReturnType; + + /** + * Create a new instance of `ExpressionsService`. The new instance inherits + * all state of the original `ExpressionsService`, including all expression + * types, expression functions and context. Also, all new types and functions + * registered in the original services AFTER the forking event will be + * available in the forked instance. However, all new types and functions + * registered in the forked instances will NOT be available to the original + * service. + * @param name A fork name that can be used to get fork instance later. + */ + fork(name?: string): ExpressionsService; + + /** + * Register an expression function, which will be possible to execute as + * part of the expression pipeline. + * + * Below we register a function which simply sleeps for given number of + * milliseconds to delay the execution and outputs its input as-is. + * + * ```ts + * expressions.registerFunction({ + * name: 'sleep', + * args: { + * time: { + * aliases: ['_'], + * help: 'Time in milliseconds for how long to sleep', + * types: ['number'], + * }, + * }, + * help: '', + * fn: async (input, args, context) => { + * await new Promise(r => setTimeout(r, args.time)); + * return input; + * }, + * } + * ``` + * + * The actual function is defined in the `fn` key. The function can be *async*. + * It receives three arguments: (1) `input` is the output of the previous function + * or the initial input of the expression if the function is first in chain; + * (2) `args` are function arguments as defined in expression string, that can + * be edited by user (e.g in case of Canvas); (3) `context` is a shared object + * passed to all functions that can be used for side-effects. + */ + registerFunction( + functionDefinition: AnyExpressionFunctionDefinition | (() => AnyExpressionFunctionDefinition) + ): void; + + registerType( + typeDefinition: AnyExpressionTypeDefinition | (() => AnyExpressionTypeDefinition) + ): void; + + registerRenderer( + definition: AnyExpressionRenderDefinition | (() => AnyExpressionRenderDefinition) + ): void; +} export interface ExpressionExecutionParams { searchContext?: SerializableRecord; @@ -97,7 +161,13 @@ export interface ExpressionsServiceStart { * instance is an internal representation of the function in Expressions * service - do not mutate that object. */ - getFunction: (name: string) => ReturnType; + getFunction(name: string): ReturnType; + + /** + * Returns POJO map of all registered expression functions, where keys are + * names of the functions and values are `ExpressionFunction` instances. + */ + getFunctions(): ReturnType; /** * Get a registered `ExpressionRenderer` by its name, which was registered @@ -105,7 +175,13 @@ export interface ExpressionsServiceStart { * instance is an internal representation of the renderer in Expressions * service - do not mutate that object. */ - getRenderer: (name: string) => ReturnType; + getRenderer(name: string): ReturnType; + + /** + * Returns POJO map of all registered expression renderers, where keys are + * names of the renderers and values are `ExpressionRenderer` instances. + */ + getRenderers(): ReturnType; /** * Get a registered `ExpressionType` by its name, which was registered @@ -113,7 +189,13 @@ export interface ExpressionsServiceStart { * instance is an internal representation of the type in Expressions * service - do not mutate that object. */ - getType: (name: string) => ReturnType; + getType(name: string): ReturnType; + + /** + * Returns POJO map of all registered expression types, where keys are + * names of the types and values are `ExpressionType` instances. + */ + getTypes(): ReturnType; /** * Executes expression string or a parsed expression AST and immediately @@ -139,34 +221,23 @@ export interface ExpressionsServiceStart { * expressions.run('...', null, { elasticsearchClient }); * ``` */ - run: ( + run( ast: string | ExpressionAstExpression, input: Input, params?: ExpressionExecutionParams - ) => Observable>; + ): Observable>; /** * Starts expression execution and immediately returns `ExecutionContract` * instance that tracks the progress of the execution and can be used to * interact with the execution. */ - execute: ( + execute( ast: string | ExpressionAstExpression, // This any is for legacy reasons. input: Input, params?: ExpressionExecutionParams - ) => ExecutionContract; - - /** - * Create a new instance of `ExpressionsService`. The new instance inherits - * all state of the original `ExpressionsService`, including all expression - * types, expression functions and context. Also, all new types and functions - * registered in the original services AFTER the forking event will be - * available in the forked instance. However, all new types and functions - * registered in the forked instances will NOT be available to the original - * service. - */ - fork: () => ExpressionsService; + ): ExecutionContract; } export interface ExpressionServiceParams { @@ -193,7 +264,19 @@ export interface ExpressionServiceParams { * * so that JSDoc appears in developers IDE when they use those `plugins.expressions.registerFunction(`. */ -export class ExpressionsService implements PersistableStateService { +export class ExpressionsService + implements + PersistableStateService, + ExpressionsServiceSetup, + ExpressionsServiceStart +{ + /** + * @note Workaround since the expressions service is frozen. + */ + private static started = new WeakSet(); + private children = new Map(); + private parent?: ExpressionsService; + public readonly executor: Executor; public readonly renderers: ExpressionRendererRegistry; @@ -205,94 +288,85 @@ export class ExpressionsService implements PersistableStateService { - * await new Promise(r => setTimeout(r, args.time)); - * return input; - * }, - * } - * ``` - * - * The actual function is defined in the `fn` key. The function can be *async*. - * It receives three arguments: (1) `input` is the output of the previous function - * or the initial input of the expression if the function is first in chain; - * (2) `args` are function arguments as defined in expression string, that can - * be edited by user (e.g in case of Canvas); (3) `context` is a shared object - * passed to all functions that can be used for side-effects. - */ - public readonly registerFunction = ( - functionDefinition: AnyExpressionFunctionDefinition | (() => AnyExpressionFunctionDefinition) - ): void => this.executor.registerFunction(functionDefinition); - - public readonly registerType = ( - typeDefinition: AnyExpressionTypeDefinition | (() => AnyExpressionTypeDefinition) - ): void => this.executor.registerType(typeDefinition); + private isStarted(): boolean { + return !!(ExpressionsService.started.has(this) || this.parent?.isStarted()); + } - public readonly registerRenderer = ( - definition: AnyExpressionRenderDefinition | (() => AnyExpressionRenderDefinition) - ): void => this.renderers.register(definition); + private assertSetup() { + if (this.isStarted()) { + throw new Error('The expression service is already started and can no longer be configured.'); + } + } - public readonly run: ExpressionsServiceStart['run'] = (ast, input, params) => - this.executor.run(ast, input, params); + private assertStart() { + if (!this.isStarted()) { + throw new Error('The expressions service has not started yet.'); + } + } public readonly getFunction: ExpressionsServiceStart['getFunction'] = (name) => this.executor.getFunction(name); - /** - * Returns POJO map of all registered expression functions, where keys are - * names of the functions and values are `ExpressionFunction` instances. - */ - public readonly getFunctions = (): ReturnType => + public readonly getFunctions: ExpressionsServiceStart['getFunctions'] = () => this.executor.getFunctions(); - public readonly getRenderer: ExpressionsServiceStart['getRenderer'] = (name) => - this.renderers.get(name); + public readonly getRenderer: ExpressionsServiceStart['getRenderer'] = (name) => { + this.assertStart(); - /** - * Returns POJO map of all registered expression renderers, where keys are - * names of the renderers and values are `ExpressionRenderer` instances. - */ - public readonly getRenderers = (): ReturnType => - this.renderers.toJS(); + return this.renderers.get(name); + }; - public readonly getType: ExpressionsServiceStart['getType'] = (name) => - this.executor.getType(name); + public readonly getRenderers: ExpressionsServiceStart['getRenderers'] = () => { + this.assertStart(); - /** - * Returns POJO map of all registered expression types, where keys are - * names of the types and values are `ExpressionType` instances. - */ - public readonly getTypes = (): ReturnType => this.executor.getTypes(); + return this.renderers.toJS(); + }; + + public readonly getType: ExpressionsServiceStart['getType'] = (name) => { + this.assertStart(); + + return this.executor.getType(name); + }; + + public readonly getTypes: ExpressionsServiceStart['getTypes'] = () => this.executor.getTypes(); + + public readonly registerFunction: ExpressionsServiceSetup['registerFunction'] = ( + functionDefinition + ) => this.executor.registerFunction(functionDefinition); + + public readonly registerType: ExpressionsServiceSetup['registerType'] = (typeDefinition) => + this.executor.registerType(typeDefinition); + + public readonly registerRenderer: ExpressionsServiceSetup['registerRenderer'] = (definition) => + this.renderers.register(definition); + + public readonly fork: ExpressionsServiceSetup['fork'] = (name) => { + this.assertSetup(); + + const executor = this.executor.fork(); + const renderers = this.renderers; + const fork = new (this.constructor as typeof ExpressionsService)({ executor, renderers }); + fork.parent = this; + + if (name) { + this.children.set(name, fork); + } + + return fork; + }; public readonly execute: ExpressionsServiceStart['execute'] = ((ast, input, params) => { + this.assertStart(); const execution = this.executor.createExecution(ast, params); execution.start(input); + return execution.contract; }) as ExpressionsServiceStart['execute']; - public readonly fork = () => { - const executor = this.executor.fork(); - const renderers = this.renderers; - const fork = new (this.constructor as typeof ExpressionsService)({ executor, renderers }); + public readonly run: ExpressionsServiceStart['run'] = (ast, input, params) => { + this.assertStart(); - return fork; + return this.executor.run(ast, input, params); }; /** @@ -371,8 +445,12 @@ export class ExpressionsService implements PersistableStateService { service.registerFunction(func); } + service.start(); + const moduleMock = { __execution: undefined, __getLastExecution: () => moduleMock.__execution, diff --git a/src/plugins/expressions/public/mocks.tsx b/src/plugins/expressions/public/mocks.tsx index 3a5450fc02837..f2f6a6807f339 100644 --- a/src/plugins/expressions/public/mocks.tsx +++ b/src/plugins/expressions/public/mocks.tsx @@ -16,19 +16,13 @@ export type Start = jest.Mocked; const createSetupContract = (): Setup => { const setupContract: Setup = { - extract: jest.fn(), fork: jest.fn(), getFunction: jest.fn(), getFunctions: jest.fn(), - getRenderer: jest.fn(), - getRenderers: jest.fn(), - getType: jest.fn(), getTypes: jest.fn(), - inject: jest.fn(), registerFunction: jest.fn(), registerRenderer: jest.fn(), registerType: jest.fn(), - run: jest.fn(), }; return setupContract; }; @@ -38,10 +32,12 @@ const createStartContract = (): Start => { execute: jest.fn(), ExpressionLoader: jest.fn(), ExpressionRenderHandler: jest.fn(), - fork: jest.fn(), getFunction: jest.fn(), + getFunctions: jest.fn(), getRenderer: jest.fn(), + getRenderers: jest.fn(), getType: jest.fn(), + getTypes: jest.fn(), loader: jest.fn(), ReactExpressionRenderer: jest.fn((props) => <>), render: jest.fn(), diff --git a/src/plugins/expressions/public/plugin.test.ts b/src/plugins/expressions/public/plugin.test.ts index 1963eb1f1b3f7..61ff0d8b54033 100644 --- a/src/plugins/expressions/public/plugin.test.ts +++ b/src/plugins/expressions/public/plugin.test.ts @@ -32,16 +32,6 @@ describe('ExpressionsPublicPlugin', () => { expect(setup.getFunctions().add.name).toBe('add'); }); }); - - describe('.run()', () => { - test('can execute simple expression', async () => { - const { setup } = await expressionsPluginMock.createPlugin(); - const { result } = await setup - .run('var_set name="foo" value="bar" | var name="foo"', null) - .toPromise(); - expect(result).toBe('bar'); - }); - }); }); describe('start contract', () => { diff --git a/src/plugins/expressions/server/mocks.ts b/src/plugins/expressions/server/mocks.ts index f4379145f6a6c..bf36ab3c5daa9 100644 --- a/src/plugins/expressions/server/mocks.ts +++ b/src/plugins/expressions/server/mocks.ts @@ -13,37 +13,24 @@ import { coreMock } from '../../../core/server/mocks'; export type Setup = jest.Mocked; export type Start = jest.Mocked; -const createSetupContract = (): Setup => { - const setupContract: Setup = { - extract: jest.fn(), - fork: jest.fn(), - getFunction: jest.fn(), - getFunctions: jest.fn(), - getRenderer: jest.fn(), - getRenderers: jest.fn(), - getType: jest.fn(), - getTypes: jest.fn(), - inject: jest.fn(), - registerFunction: jest.fn(), - registerRenderer: jest.fn(), - registerType: jest.fn(), - run: jest.fn(), - }; - return setupContract; -}; - -const createStartContract = (): Start => { - const startContract: Start = { +const createSetupContract = (): Setup => ({ + fork: jest.fn(), + getFunction: jest.fn(), + getFunctions: jest.fn(), + getTypes: jest.fn(), + registerFunction: jest.fn(), + registerRenderer: jest.fn(), + registerType: jest.fn(), +}); + +const createStartContract = (): Start => + ({ execute: jest.fn(), - fork: jest.fn(), getFunction: jest.fn(), getRenderer: jest.fn(), getType: jest.fn(), run: jest.fn(), - }; - - return startContract; -}; + } as unknown as Start); const createPlugin = async () => { const pluginInitializerContext = coreMock.createPluginInitializerContext(); diff --git a/src/plugins/expressions/server/plugin.test.ts b/src/plugins/expressions/server/plugin.test.ts index c41cda36e7623..52ecf1ff9979e 100644 --- a/src/plugins/expressions/server/plugin.test.ts +++ b/src/plugins/expressions/server/plugin.test.ts @@ -24,15 +24,5 @@ describe('ExpressionsServerPlugin', () => { expect(setup.getFunctions().add.name).toBe('add'); }); }); - - describe('.run()', () => { - test('can execute simple expression', async () => { - const { setup } = await expressionsPluginMock.createPlugin(); - const { result } = await setup - .run('var_set name="foo" value="bar" | var name="foo"', null) - .toPromise(); - expect(result).toBe('bar'); - }); - }); }); }); diff --git a/src/plugins/home/kibana.json b/src/plugins/home/kibana.json index b3bd915bee143..3f1916f3142ff 100644 --- a/src/plugins/home/kibana.json +++ b/src/plugins/home/kibana.json @@ -8,6 +8,6 @@ "server": true, "ui": true, "requiredPlugins": ["data", "share", "urlForwarding"], - "optionalPlugins": ["usageCollection", "telemetry"], + "optionalPlugins": ["usageCollection", "telemetry", "customIntegrations"], "requiredBundles": ["kibanaReact"] } diff --git a/src/plugins/home/server/plugin.test.ts b/src/plugins/home/server/plugin.test.ts index 88e07970cc440..fdf671e10ad09 100644 --- a/src/plugins/home/server/plugin.test.ts +++ b/src/plugins/home/server/plugin.test.ts @@ -7,38 +7,51 @@ */ import { registryForTutorialsMock, registryForSampleDataMock } from './plugin.test.mocks'; -import { HomeServerPlugin } from './plugin'; +import { HomeServerPlugin, HomeServerPluginSetupDependencies } from './plugin'; import { coreMock, httpServiceMock } from '../../../core/server/mocks'; +import { customIntegrationsMock } from '../../custom_integrations/server/mocks'; describe('HomeServerPlugin', () => { + let homeServerPluginSetupDependenciesMock: HomeServerPluginSetupDependencies; + let mockCoreSetup: ReturnType; + beforeEach(() => { registryForTutorialsMock.setup.mockClear(); registryForTutorialsMock.start.mockClear(); registryForSampleDataMock.setup.mockClear(); registryForSampleDataMock.start.mockClear(); + + homeServerPluginSetupDependenciesMock = { + customIntegrations: customIntegrationsMock.createSetup(), + }; + mockCoreSetup = coreMock.createSetup(); }); describe('setup', () => { - let mockCoreSetup: ReturnType; let initContext: ReturnType; let routerMock: ReturnType; beforeEach(() => { - mockCoreSetup = coreMock.createSetup(); routerMock = httpServiceMock.createRouter(); mockCoreSetup.http.createRouter.mockReturnValue(routerMock); initContext = coreMock.createPluginInitializerContext(); }); test('wires up tutorials provider service and returns registerTutorial and addScopedTutorialContextFactory', () => { - const setup = new HomeServerPlugin(initContext).setup(mockCoreSetup, {}); + const setup = new HomeServerPlugin(initContext).setup( + mockCoreSetup, + homeServerPluginSetupDependenciesMock + ); expect(setup).toHaveProperty('tutorials'); expect(setup.tutorials).toHaveProperty('registerTutorial'); expect(setup.tutorials).toHaveProperty('addScopedTutorialContextFactory'); }); test('wires up sample data provider service and returns registerTutorial and addScopedTutorialContextFactory', () => { - const setup = new HomeServerPlugin(initContext).setup(mockCoreSetup, {}); + const setup = new HomeServerPlugin(initContext).setup( + mockCoreSetup, + homeServerPluginSetupDependenciesMock + ); expect(setup).toHaveProperty('sampleData'); expect(setup.sampleData).toHaveProperty('registerSampleDataset'); expect(setup.sampleData).toHaveProperty('getSampleDatasets'); @@ -48,7 +61,7 @@ describe('HomeServerPlugin', () => { }); test('registers the `/api/home/hits_status` route', () => { - new HomeServerPlugin(initContext).setup(mockCoreSetup, {}); + new HomeServerPlugin(initContext).setup(mockCoreSetup, homeServerPluginSetupDependenciesMock); expect(routerMock.post).toHaveBeenCalledTimes(1); expect(routerMock.post).toHaveBeenCalledWith( @@ -63,7 +76,9 @@ describe('HomeServerPlugin', () => { describe('start', () => { const initContext = coreMock.createPluginInitializerContext(); test('is defined', () => { - const start = new HomeServerPlugin(initContext).start(); + const plugin = new HomeServerPlugin(initContext); + plugin.setup(mockCoreSetup, homeServerPluginSetupDependenciesMock); // setup() must always be called before start() + const start = plugin.start(); expect(start).toBeDefined(); expect(start).toHaveProperty('tutorials'); expect(start).toHaveProperty('sampleData'); diff --git a/src/plugins/home/server/plugin.ts b/src/plugins/home/server/plugin.ts index a1463c4c8138b..7c830dd8d5bc3 100644 --- a/src/plugins/home/server/plugin.ts +++ b/src/plugins/home/server/plugin.ts @@ -19,9 +19,11 @@ import { UsageCollectionSetup } from '../../usage_collection/server'; import { capabilitiesProvider } from './capabilities_provider'; import { sampleDataTelemetry } from './saved_objects'; import { registerRoutes } from './routes'; +import { CustomIntegrationsPluginSetup } from '../../custom_integrations/server'; -interface HomeServerPluginSetupDependencies { +export interface HomeServerPluginSetupDependencies { usageCollection?: UsageCollectionSetup; + customIntegrations?: CustomIntegrationsPluginSetup; } export class HomeServerPlugin implements Plugin { @@ -37,7 +39,7 @@ export class HomeServerPlugin implements Plugin; diff --git a/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts b/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts index a82699c231ad4..5c7ec0a3382bf 100644 --- a/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts +++ b/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts @@ -18,6 +18,8 @@ import { TutorialsCategory, ScopedTutorialContextFactory, } from './lib/tutorials_registry_types'; +import { CustomIntegrationsPluginSetup } from '../../../../custom_integrations/server'; +import { customIntegrationsMock } from '../../../../custom_integrations/server/mocks'; const INVALID_TUTORIAL: TutorialSchema = { id: 'test', @@ -69,6 +71,11 @@ describe('TutorialsRegistry', () => { let mockCoreSetup: MockedKeys; let testProvider: TutorialProvider; let testScopedTutorialContextFactory: ScopedTutorialContextFactory; + let mockCustomIntegrationsPluginSetup: MockedKeys; + + beforeEach(() => { + mockCustomIntegrationsPluginSetup = customIntegrationsMock.createSetup(); + }); describe('GET /api/kibana/home/tutorials', () => { beforeEach(() => { @@ -83,13 +90,13 @@ describe('TutorialsRegistry', () => { describe('setup', () => { test('exposes proper contract', () => { - const setup = new TutorialsRegistry().setup(mockCoreSetup); + const setup = new TutorialsRegistry().setup(mockCoreSetup, mockCustomIntegrationsPluginSetup); expect(setup).toHaveProperty('registerTutorial'); expect(setup).toHaveProperty('addScopedTutorialContextFactory'); }); test('registerTutorial throws when registering a tutorial with an invalid schema', () => { - const setup = new TutorialsRegistry().setup(mockCoreSetup); + const setup = new TutorialsRegistry().setup(mockCoreSetup, mockCustomIntegrationsPluginSetup); testProvider = ({}) => invalidTutorialProvider; expect(() => setup.registerTutorial(testProvider)).toThrowErrorMatchingInlineSnapshot( `"Unable to register tutorial spec because its invalid. Error: [name]: is not allowed to be empty"` @@ -97,13 +104,34 @@ describe('TutorialsRegistry', () => { }); test('registerTutorial registers a tutorial with a valid schema', () => { - const setup = new TutorialsRegistry().setup(mockCoreSetup); + const setup = new TutorialsRegistry().setup(mockCoreSetup, mockCustomIntegrationsPluginSetup); testProvider = ({}) => validTutorialProvider; expect(() => setup.registerTutorial(testProvider)).not.toThrowError(); + + // @ts-expect-error + expect(mockCustomIntegrationsPluginSetup.registerCustomIntegration.mock.calls).toEqual([ + [ + { + id: 'test', + title: 'new tutorial provider', + categories: [], + uiInternalPath: '/app/home#/tutorial/test', + description: 'short description', + icons: [ + { + src: 'alert', + type: 'eui', + }, + ], + shipper: 'tutorial', + isBeta: false, + }, + ], + ]); }); test('addScopedTutorialContextFactory throws when given a scopedTutorialContextFactory that is not a function', () => { - const setup = new TutorialsRegistry().setup(mockCoreSetup); + const setup = new TutorialsRegistry().setup(mockCoreSetup, mockCustomIntegrationsPluginSetup); const testItem = {} as TutorialProvider; expect(() => setup.addScopedTutorialContextFactory(testItem) @@ -113,7 +141,7 @@ describe('TutorialsRegistry', () => { }); test('addScopedTutorialContextFactory adds a scopedTutorialContextFactory when given a function', () => { - const setup = new TutorialsRegistry().setup(mockCoreSetup); + const setup = new TutorialsRegistry().setup(mockCoreSetup, mockCustomIntegrationsPluginSetup); testScopedTutorialContextFactory = ({}) => 'string'; expect(() => setup.addScopedTutorialContextFactory(testScopedTutorialContextFactory) diff --git a/src/plugins/home/server/services/tutorials/tutorials_registry.ts b/src/plugins/home/server/services/tutorials/tutorials_registry.ts index 05f5600af307a..8f7ecd7d7ccf5 100644 --- a/src/plugins/home/server/services/tutorials/tutorials_registry.ts +++ b/src/plugins/home/server/services/tutorials/tutorials_registry.ts @@ -12,14 +12,46 @@ import { TutorialContextFactory, ScopedTutorialContextFactory, } from './lib/tutorials_registry_types'; -import { tutorialSchema } from './lib/tutorial_schema'; +import { TutorialSchema, tutorialSchema } from './lib/tutorial_schema'; import { builtInTutorials } from '../../tutorials/register'; +import { CustomIntegrationsPluginSetup } from '../../../../custom_integrations/server'; +import { Category, CATEGORY_DISPLAY } from '../../../../custom_integrations/common'; +import { HOME_APP_BASE_PATH } from '../../../common/constants'; + +function registerTutorialWithCustomIntegrations( + customIntegrations: CustomIntegrationsPluginSetup, + tutorial: TutorialSchema +) { + const allowedCategories: Category[] = (tutorial.integrationBrowserCategories ?? []).filter( + (category) => { + return CATEGORY_DISPLAY.hasOwnProperty(category); + } + ) as Category[]; + + customIntegrations.registerCustomIntegration({ + id: tutorial.id, + title: tutorial.name, + categories: allowedCategories, + uiInternalPath: `${HOME_APP_BASE_PATH}#/tutorial/${tutorial.id}`, + description: tutorial.shortDescription, + icons: tutorial.euiIconType + ? [ + { + type: 'eui', + src: tutorial.euiIconType, + }, + ] + : [], + shipper: 'tutorial', + isBeta: false, + }); +} export class TutorialsRegistry { private tutorialProviders: TutorialProvider[] = []; // pre-register all the tutorials we know we want in here private readonly scopedTutorialContextFactories: TutorialContextFactory[] = []; - public setup(core: CoreSetup) { + public setup(core: CoreSetup, customIntegrations?: CustomIntegrationsPluginSetup) { const router = core.http.createRouter(); router.get( { path: '/api/kibana/home/tutorials', validate: false }, @@ -31,7 +63,6 @@ export class TutorialsRegistry { }, initialContext ); - return res.ok({ body: this.tutorialProviders.map((tutorialProvider) => { return tutorialProvider(scopedContext); // All the tutorialProviders need to be refactored so that they don't need the server. @@ -41,13 +72,17 @@ export class TutorialsRegistry { ); return { registerTutorial: (specProvider: TutorialProvider) => { + const emptyContext = {}; + let tutorial: TutorialSchema; try { - const emptyContext = {}; - tutorialSchema.validate(specProvider(emptyContext)); + tutorial = tutorialSchema.validate(specProvider(emptyContext)); } catch (error) { throw new Error(`Unable to register tutorial spec because its invalid. ${error}`); } + if (customIntegrations && tutorial) { + registerTutorialWithCustomIntegrations(customIntegrations, tutorial); + } this.tutorialProviders.push(specProvider); }, diff --git a/src/plugins/home/tsconfig.json b/src/plugins/home/tsconfig.json index f43c40e35349d..fa98b98ff8e1c 100644 --- a/src/plugins/home/tsconfig.json +++ b/src/plugins/home/tsconfig.json @@ -11,6 +11,7 @@ "references": [ { "path": "../../core/tsconfig.json" }, { "path": "../data/tsconfig.json" }, + { "path": "../custom_integrations/tsconfig.json" }, { "path": "../kibana_react/tsconfig.json" }, { "path": "../share/tsconfig.json" }, { "path": "../url_forwarding/tsconfig.json" }, diff --git a/src/plugins/kibana_react/README.md b/src/plugins/kibana_react/README.md index adbdb628ea9dd..5071c6c93f152 100644 --- a/src/plugins/kibana_react/README.md +++ b/src/plugins/kibana_react/README.md @@ -75,20 +75,6 @@ const Demo = ({ kibana }) => { export default withKibana(Demo); ``` -Using `` render prop. - -```tsx -import { UseKibana } from 'kibana-react'; - -const Demo = () => { - return ( - - {(kibana) =>
{kibana.services.uiSettings.get('theme:darkMode') ? 'dark' : 'light'}
} -
- ); -}; -``` - ## `uiSettings` service Wrappers around Core's `uiSettings` service. diff --git a/src/plugins/kibana_react/public/code_editor/code_editor.test.helpers.tsx b/src/plugins/kibana_react/public/code_editor/code_editor.test.helpers.tsx index cee1ecad2196a..e0b868f3a8b08 100644 --- a/src/plugins/kibana_react/public/code_editor/code_editor.test.helpers.tsx +++ b/src/plugins/kibana_react/public/code_editor/code_editor.test.helpers.tsx @@ -9,9 +9,9 @@ import React, { useEffect, KeyboardEventHandler } from 'react'; import { monaco } from '@kbn/monaco'; function createEditorInstance() { - const keyDownListeners: any[] = []; - const didShowListeners: any[] = []; - const didHideListeners: any[] = []; + const keyDownListeners: Array<(e?: unknown) => void> = []; + const didShowListeners: Array<(e?: unknown) => void> = []; + const didHideListeners: Array<(e?: unknown) => void> = []; let areSuggestionsVisible = false; const editorInstance = { @@ -69,7 +69,10 @@ type MockedEditor = ReturnType; export const mockedEditorInstance: MockedEditor = createEditorInstance(); // mock -const mockMonacoEditor = ({ editorWillMount, editorDidMount }: any) => { +const mockMonacoEditor = ({ + editorWillMount, + editorDidMount, +}: Record void>) => { editorWillMount(monaco); useEffect(() => { diff --git a/src/plugins/kibana_react/public/code_editor/code_editor.tsx b/src/plugins/kibana_react/public/code_editor/code_editor.tsx index 29b905c511d4c..07bda19bf6d14 100644 --- a/src/plugins/kibana_react/public/code_editor/code_editor.tsx +++ b/src/plugins/kibana_react/public/code_editor/code_editor.tsx @@ -135,7 +135,9 @@ export const CodeEditor: React.FC = ({ const MonacoEditor: typeof ReactMonacoEditor = useMemo(() => { const isMockedComponent = typeof ReactMonacoEditor === 'function' && ReactMonacoEditor.name === 'JestMockEditor'; - return isMockedComponent ? (ReactMonacoEditor as any)() : ReactMonacoEditor; + return isMockedComponent + ? (ReactMonacoEditor as unknown as () => typeof ReactMonacoEditor)() + : ReactMonacoEditor; }, []); const isReadOnly = options?.readOnly ?? false; diff --git a/src/plugins/kibana_react/public/context/context.tsx b/src/plugins/kibana_react/public/context/context.tsx index 974bd4e894791..c9dc3df90864d 100644 --- a/src/plugins/kibana_react/public/context/context.tsx +++ b/src/plugins/kibana_react/public/context/context.tsx @@ -26,7 +26,7 @@ export const useKibana = (): KibanaReactContextValue< > => useContext(context as unknown as React.Context>); -export const withKibana = }>( +export const withKibana = }>( type: React.ComponentType ): React.FC> => { const EnhancedType: React.FC> = (props: Omit) => { @@ -36,10 +36,6 @@ export const withKibana = return EnhancedType; }; -export const UseKibana: React.FC<{ - children: (kibana: KibanaReactContextValue) => React.ReactNode; -}> = ({ children }) => <>{children(useKibana())}; - export const createKibanaReactContext = ( services: Services ): KibanaReactContext => { @@ -58,7 +54,7 @@ export const createKibanaReactContext = ( () => createKibanaReactContext({ ...services, ...oldValue.services, ...newServices }), [services, oldValue, newServices] ); - return createElement(context.Provider as React.ComponentType, { + return createElement(context.Provider, { value: newValue, children, }); diff --git a/src/plugins/kibana_react/public/context/index.ts b/src/plugins/kibana_react/public/context/index.ts index 12f8bfccbb592..b34951b298836 100644 --- a/src/plugins/kibana_react/public/context/index.ts +++ b/src/plugins/kibana_react/public/context/index.ts @@ -12,6 +12,5 @@ export { KibanaContextProvider, useKibana, withKibana, - UseKibana, } from './context'; export { KibanaReactContext, KibanaReactContextValue, KibanaServices } from './types'; diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx index ad3fb0e2e6396..f071bd9fab25a 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx @@ -26,6 +26,7 @@ export const ElasticAgentCard: FunctionComponent = ({ title, href, button, + layout, ...cardRest }) => { const { @@ -58,7 +59,8 @@ export const ElasticAgentCard: FunctionComponent = ({ image={addBasePath(`${basePathUrl}elastic_agent_card.svg`)} betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined} footer={footer} - {...(cardRest as any)} + layout={layout as 'vertical' | undefined} + {...cardRest} /> ); }; diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_beats_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_beats_card.tsx index d0a8ceddb8dc5..0372d12096489 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_beats_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_beats_card.tsx @@ -23,6 +23,7 @@ export const ElasticBeatsCard: FunctionComponent = ({ button, href, solution, // unused for now + layout, ...cardRest }) => { const { @@ -58,7 +59,8 @@ export const ElasticBeatsCard: FunctionComponent = ({ )} betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined} footer={footer} - {...(cardRest as any)} + layout={layout as 'vertical' | undefined} + {...cardRest} /> ); }; diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx index 682d0267e1a7e..9cc38cc5f6038 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { i18n } from '@kbn/i18n'; import React, { FunctionComponent } from 'react'; import { EuiButton, EuiCard, EuiCardProps } from '@elastic/eui'; import { NoDataPageActions, NO_DATA_RECOMMENDED } from '../no_data_page'; @@ -17,6 +18,7 @@ export const NoDataCard: FunctionComponent = ({ recommended, title, button, + layout, ...cardRest }) => { const footer = @@ -25,10 +27,16 @@ export const NoDataCard: FunctionComponent = ({ return ( ); }; diff --git a/src/plugins/kibana_react/public/react_router_navigate/react_router_navigate.tsx b/src/plugins/kibana_react/public/react_router_navigate/react_router_navigate.tsx index db122d034371d..5abd77c9dc9b6 100644 --- a/src/plugins/kibana_react/public/react_router_navigate/react_router_navigate.tsx +++ b/src/plugins/kibana_react/public/react_router_navigate/react_router_navigate.tsx @@ -7,6 +7,7 @@ */ import { ScopedHistory } from 'kibana/public'; +import { MouseEvent } from 'react'; import { History, parsePath } from 'history'; interface LocationObject { @@ -15,10 +16,10 @@ interface LocationObject { hash?: string; } -const isModifiedEvent = (event: any) => +const isModifiedEvent = (event: MouseEvent) => !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); -const isLeftClickEvent = (event: any) => event.button === 0; +const isLeftClickEvent = (event: MouseEvent) => event.button === 0; export const toLocationObject = (to: string | LocationObject) => typeof to === 'string' ? parsePath(to) : to; @@ -34,7 +35,7 @@ export const reactRouterNavigate = ( export const reactRouterOnClickHandler = (history: ScopedHistory | History, to: string | LocationObject, onClickCallback?: Function) => - (event: any) => { + (event: MouseEvent) => { if (onClickCallback) { onClickCallback(event); } @@ -43,7 +44,9 @@ export const reactRouterOnClickHandler = return; } - if (event.target.getAttribute('target')) { + if ( + (event.target as unknown as { getAttribute: (a: string) => unknown })?.getAttribute('target') + ) { return; } diff --git a/src/plugins/kibana_react/public/split_panel/containers/panel_container.tsx b/src/plugins/kibana_react/public/split_panel/containers/panel_container.tsx index 86f73f9331881..69beb565ad857 100644 --- a/src/plugins/kibana_react/public/split_panel/containers/panel_container.tsx +++ b/src/plugins/kibana_react/public/split_panel/containers/panel_container.tsx @@ -17,7 +17,7 @@ export interface Props { children: ReactNode; className?: string; resizerClassName?: string; - onPanelWidthChange?: (arrayOfPanelWidths: number[]) => any; + onPanelWidthChange?: (arrayOfPanelWidths: number[]) => void; } interface State { diff --git a/src/plugins/kibana_react/public/split_panel/context.tsx b/src/plugins/kibana_react/public/split_panel/context.tsx index bad39f8bd5ef9..e236b5037e7f3 100644 --- a/src/plugins/kibana_react/public/split_panel/context.tsx +++ b/src/plugins/kibana_react/public/split_panel/context.tsx @@ -12,7 +12,7 @@ import { PanelRegistry } from './registry'; const PanelContext = createContext({ registry: new PanelRegistry() }); interface ContextProps { - children: any; + children: JSX.Element; registry: PanelRegistry; } diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index 30d09f4bf8657..18a88790b425a 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -26,17 +26,13 @@ import React from 'react'; import { KibanaPageTemplate } from '../page_template'; import { toMountPoint } from '../util'; -interface Item { - id?: string; -} - -export interface TableListViewProps { +export interface TableListViewProps { createItem?(): void; - deleteItems?(items: object[]): Promise; - editItem?(item: object): void; + deleteItems?(items: V[]): Promise; + editItem?(item: V): void; entityName: string; entityNamePlural: string; - findItems(query: string): Promise<{ total: number; hits: object[] }>; + findItems(query: string): Promise<{ total: number; hits: V[] }>; listingLimit: number; initialFilter: string; initialPageSize: number; @@ -44,7 +40,7 @@ export interface TableListViewProps { * Should be an EuiEmptyPrompt (but TS doesn't support this typing) */ emptyPrompt?: JSX.Element; - tableColumns: Array>; + tableColumns: Array>; tableListTitle: string; toastNotifications: ToastsStart; /** @@ -63,8 +59,8 @@ export interface TableListViewProps { searchFilters?: SearchFilterConfig[]; } -export interface TableListViewState { - items: object[]; +export interface TableListViewState { + items: V[]; hasInitialFetchReturned: boolean; isFetchingItems: boolean; isDeletingItems: boolean; @@ -81,11 +77,14 @@ export interface TableListViewState { // and not supporting server-side paging. // This component does not try to tackle these problems (yet) and is just feature matching the legacy component // TODO support server side sorting/paging once title and description are sortable on the server. -class TableListView extends React.Component { +class TableListView extends React.Component< + TableListViewProps, + TableListViewState +> { private pagination = {}; private _isMounted = false; - constructor(props: TableListViewProps) { + constructor(props: TableListViewProps) { super(props); this.pagination = { @@ -134,7 +133,7 @@ class TableListView extends React.Component(response.hits, 'title') : response.hits, totalItems: response.total, showLimitError: response.total > this.props.listingLimit, }); @@ -404,17 +403,17 @@ class TableListView extends React.Component { + onSelectionChange: (obj: V[]) => { this.setState({ selectedIds: obj - .map((item) => item.id) - .filter((id: undefined | string): id is string => Boolean(id)), + .map((item) => (item as Record)?.id) + .filter((id): id is string => Boolean(id)), }); }, } : undefined; - const actions: EuiTableActionsColumnType['actions'] = [ + const actions: EuiTableActionsColumnType['actions'] = [ { name: i18n.translate('kibana-react.tableListView.listing.table.editActionName', { defaultMessage: 'Edit', @@ -427,7 +426,7 @@ class TableListView extends React.Component !error, + enabled: (v) => !(v as unknown as { error: string })?.error, onClick: this.props.editItem, }, ]; diff --git a/src/plugins/kibana_react/public/util/mount_point_portal.tsx b/src/plugins/kibana_react/public/util/mount_point_portal.tsx index 07d2edfa717b9..d0753c68d1f2d 100644 --- a/src/plugins/kibana_react/public/util/mount_point_portal.tsx +++ b/src/plugins/kibana_react/public/util/mount_point_portal.tsx @@ -60,12 +60,12 @@ export const MountPointPortal: React.FC = ({ children, se } }; -class MountPointPortalErrorBoundary extends Component<{}, { error?: any }> { +class MountPointPortalErrorBoundary extends Component<{}, { error?: unknown }> { state = { error: undefined, }; - static getDerivedStateFromError(error: any) { + static getDerivedStateFromError(error: unknown) { return { error }; } diff --git a/src/plugins/kibana_react/public/util/test_helpers/react_mount_serializer.ts b/src/plugins/kibana_react/public/util/test_helpers/react_mount_serializer.ts index 6438ff0b8d98f..4d1575bf16184 100644 --- a/src/plugins/kibana_react/public/util/test_helpers/react_mount_serializer.ts +++ b/src/plugins/kibana_react/public/util/test_helpers/react_mount_serializer.ts @@ -6,11 +6,14 @@ * Side Public License, v 1. */ -export function test(value: any) { +export function test(value?: Record) { return value && value.__reactMount__; } -export function print(value: any, serialize: any) { +export function print( + value: Record, + serialize: (args: Record) => { replace: (s1: string, s2: string) => unknown } +) { // there is no proper way to correctly indent multiline values // so the trick here is to use the Object representation and rewriting the root object name return serialize({ diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index bc38b63730b20..53eb49e1013b0 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -276,6 +276,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'long', _meta: { description: 'Non-default value of setting.' }, }, + 'metrics:allowStringIndices': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'query:allowLeadingWildcards': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 24a20b458c789..b76ef14e62b8c 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -91,6 +91,7 @@ export interface UsageStats { 'savedObjects:listingLimit': number; 'query:queryString:options': string; 'metrics:max_buckets': number; + 'metrics:allowStringIndices': boolean; 'query:allowLeadingWildcards': boolean; metaFields: string[]; 'indexPattern:placeholder': string; diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index b0e0b8b2298ab..0ac4c61f4a711 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -6,6 +6,9 @@ * Side Public License, v 1. */ +import { PluginInitializerContext } from 'src/core/public'; +import { KibanaUtilsPublicPlugin } from './plugin'; + // TODO: https://github.com/elastic/kibana/issues/109893 /* eslint-disable @kbn/eslint/no_export_all */ @@ -78,10 +81,8 @@ export { export { applyDiff } from './state_management/utils/diff_object'; export { createStartServicesGetter, StartServicesGetter } from './core/create_start_service_getter'; -/** dummy plugin, we just want kibanaUtils to have its own bundle */ -export function plugin() { - return new (class KibanaUtilsPlugin { - setup() {} - start() {} - })(); +export { KibanaUtilsSetup } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new KibanaUtilsPublicPlugin(initializerContext); } diff --git a/src/plugins/kibana_utils/public/mocks.ts b/src/plugins/kibana_utils/public/mocks.ts new file mode 100644 index 0000000000000..a537c2fc74e90 --- /dev/null +++ b/src/plugins/kibana_utils/public/mocks.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { KibanaUtilsSetup, KibanaUtilsStart } from './plugin'; + +export type Setup = jest.Mocked; +export type Start = jest.Mocked; + +const createSetupContract = (): Setup => { + return { + setVersion: jest.fn(), + }; +}; + +const createStartContract = (): Start => { + return undefined; +}; + +export const kibanaUtilsPluginMock = { + createSetupContract, + createStartContract, +}; diff --git a/src/plugins/kibana_utils/public/plugin.ts b/src/plugins/kibana_utils/public/plugin.ts new file mode 100644 index 0000000000000..b255aa34ccfdb --- /dev/null +++ b/src/plugins/kibana_utils/public/plugin.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; +import { History } from 'history'; +import { setVersion } from './set_version'; + +export interface KibanaUtilsSetup { + setVersion: (history: Pick) => void; +} + +export type KibanaUtilsStart = undefined; + +export class KibanaUtilsPublicPlugin implements Plugin { + private readonly version: string; + + constructor(initializerContext: PluginInitializerContext) { + this.version = initializerContext.env.packageInfo.version; + } + + public setup(core: CoreSetup): KibanaUtilsSetup { + return { + setVersion: this.setVersion, + }; + } + + public start(core: CoreStart): KibanaUtilsStart { + return undefined; + } + + public stop() {} + + private setVersion = (history: Pick) => { + setVersion(history, this.version); + }; +} diff --git a/src/plugins/kibana_utils/public/set_version.test.ts b/src/plugins/kibana_utils/public/set_version.test.ts new file mode 100644 index 0000000000000..eb70d889d0f03 --- /dev/null +++ b/src/plugins/kibana_utils/public/set_version.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { History } from 'history'; +import { setVersion } from './set_version'; + +describe('setVersion', () => { + test('sets version, if one is not set', () => { + const history: Pick = { + location: { + hash: '', + search: '', + pathname: '/', + state: {}, + }, + replace: jest.fn(), + }; + setVersion(history, '1.2.3'); + + expect(history.replace).toHaveBeenCalledTimes(1); + expect(history.replace).toHaveBeenCalledWith('/?_v=1.2.3'); + }); + + test('overwrites, if version already set to a different value', () => { + const history: Pick = { + location: { + hash: '/view/dashboards', + search: 'a=b&_v=7.16.6', + pathname: '/foo/bar', + state: {}, + }, + replace: jest.fn(), + }; + setVersion(history, '8.0.0'); + + expect(history.replace).toHaveBeenCalledTimes(1); + expect(history.replace).toHaveBeenCalledWith('/foo/bar?a=b&_v=8.0.0#/view/dashboards'); + }); + + test('does nothing, if version already set to correct value', () => { + const history: Pick = { + location: { + hash: '/view/dashboards', + search: 'a=b&_v=8.0.0', + pathname: '/foo/bar', + state: {}, + }, + replace: jest.fn(), + }; + setVersion(history, '8.0.0'); + + expect(history.replace).toHaveBeenCalledTimes(0); + }); +}); diff --git a/src/plugins/kibana_utils/public/set_version.ts b/src/plugins/kibana_utils/public/set_version.ts new file mode 100644 index 0000000000000..b3acb39ed5134 --- /dev/null +++ b/src/plugins/kibana_utils/public/set_version.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { History } from 'history'; + +export const setVersion = (history: Pick, version: string) => { + const search = new URLSearchParams(history.location.search); + if (search.get('_v') === version) return; + search.set('_v', version); + const path = + history.location.pathname + + '?' + + search.toString() + + (history.location.hash ? '#' + history.location.hash : ''); + history.replace(path); +}; diff --git a/src/plugins/kibana_utils/server/index.ts b/src/plugins/kibana_utils/server/index.ts index 483c5aa92b45e..42847042be151 100644 --- a/src/plugins/kibana_utils/server/index.ts +++ b/src/plugins/kibana_utils/server/index.ts @@ -15,6 +15,7 @@ export { Get, Set, url, + mergeMigrationFunctionMaps, } from '../common'; export { KbnServerError, reportServerError, getKbnServerError } from './report_server_error'; diff --git a/src/plugins/presentation_util/README.mdx b/src/plugins/presentation_util/README.mdx index 35b80e3634534..575e8002e6eb8 100755 --- a/src/plugins/presentation_util/README.mdx +++ b/src/plugins/presentation_util/README.mdx @@ -162,7 +162,7 @@ Once your services and providers are defined, and you have at least one set of f import { pluginServices } from './services'; import { registry } from './services/kibana'; - public async start( + public start( coreStart: CoreStart, startPlugins: StartDeps ): Promise { diff --git a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts b/src/plugins/saved_objects/public/saved_object/saved_object.test.ts index 2f45ee211c8c9..bd8d69d6b693e 100644 --- a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts +++ b/src/plugins/saved_objects/public/saved_object/saved_object.test.ts @@ -20,7 +20,7 @@ import { coreMock } from '../../../../core/public/mocks'; import { dataPluginMock, createSearchSourceMock } from '../../../../plugins/data/public/mocks'; import { createStubIndexPattern } from '../../../../plugins/data/common/stubs'; import { SavedObjectAttributes, SimpleSavedObject } from 'kibana/public'; -import { IndexPattern } from '../../../data/common'; +import { DataView } from '../../../data/common'; import { savedObjectsDecoratorRegistryMock } from './decorators/registry.mock'; describe('Saved Object', () => { @@ -725,7 +725,7 @@ describe('Saved Object', () => { type: 'dashboard', afterESResp: afterESRespCallback, searchSource: true, - indexPattern: { id: indexPatternId } as IndexPattern, + indexPattern: { id: indexPatternId } as DataView, }; stubESResponse( @@ -752,7 +752,7 @@ describe('Saved Object', () => { return savedObject.init!().then(() => { expect(afterESRespCallback).toHaveBeenCalled(); const index = savedObject.searchSource!.getField('index'); - expect(index instanceof IndexPattern).toBe(true); + expect(index instanceof DataView).toBe(true); expect(index!.id).toEqual(indexPatternId); }); }); @@ -765,7 +765,7 @@ describe('Saved Object', () => { type: 'dashboard', afterESResp: afterESRespCallback, searchSource: false, - indexPattern: { id: indexPatternId } as IndexPattern, + indexPattern: { id: indexPatternId } as DataView, }; stubESResponse(getMockedDocResponse(indexPatternId)); diff --git a/src/plugins/saved_objects_management/kibana.json b/src/plugins/saved_objects_management/kibana.json index b8207e0627b81..3043a7cb67fe2 100644 --- a/src/plugins/saved_objects_management/kibana.json +++ b/src/plugins/saved_objects_management/kibana.json @@ -8,7 +8,7 @@ "server": true, "ui": true, "requiredPlugins": ["management", "data"], - "optionalPlugins": ["dashboard", "visualizations", "discover", "home", "savedObjectsTaggingOss", "spaces"], + "optionalPlugins": ["home", "savedObjectsTaggingOss", "spaces"], "extraPublicDirs": ["public/lib"], "requiredBundles": ["kibanaReact", "home"] } diff --git a/src/plugins/saved_objects_management/public/index.ts b/src/plugins/saved_objects_management/public/index.ts index e23a6550e9443..92e01ab903699 100644 --- a/src/plugins/saved_objects_management/public/index.ts +++ b/src/plugins/saved_objects_management/public/index.ts @@ -18,8 +18,6 @@ export { SavedObjectsManagementColumnServiceStart, SavedObjectsManagementColumn, SavedObjectsManagementRecord, - ISavedObjectsManagementServiceRegistry, - SavedObjectsManagementServiceRegistryEntry, } from './services'; export { ProcessedImportResponse, processImportResponse, FailedImport } from './lib'; export { SavedObjectRelation, SavedObjectWithMetadata, SavedObjectMetadata } from './types'; diff --git a/src/plugins/saved_objects_management/public/lib/create_field_list.test.ts b/src/plugins/saved_objects_management/public/lib/create_field_list.test.ts deleted file mode 100644 index f7b60b116a2bf..0000000000000 --- a/src/plugins/saved_objects_management/public/lib/create_field_list.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { SimpleSavedObject, SavedObjectReference } from '../../../../core/public'; -import { savedObjectsServiceMock } from '../../../../core/public/mocks'; -import { createFieldList } from './create_field_list'; - -const savedObjectClientMock = savedObjectsServiceMock.createStartContract().client; - -const createObject = ( - attributes: T, - references: SavedObjectReference[] = [] -): SimpleSavedObject => - new SimpleSavedObject(savedObjectClientMock, { - id: 'id', - type: 'type', - migrationVersion: {}, - attributes, - references, - }); - -describe('createFieldList', () => { - it('generate fields based on the object attributes', () => { - const obj = createObject({ - textField: 'some text', - numberField: 12, - boolField: true, - }); - expect(createFieldList(obj)).toMatchInlineSnapshot(` - Array [ - Object { - "name": "textField", - "type": "text", - "value": "some text", - }, - Object { - "name": "numberField", - "type": "number", - "value": 12, - }, - Object { - "name": "boolField", - "type": "boolean", - "value": true, - }, - Object { - "name": "references", - "type": "array", - "value": "[]", - }, - ] - `); - }); - - it('detects json fields', () => { - const obj = createObject({ - jsonField: `{"data": "value"}`, - }); - expect(createFieldList(obj)).toMatchInlineSnapshot(` - Array [ - Object { - "name": "jsonField", - "type": "json", - "value": "{ - \\"data\\": \\"value\\" - }", - }, - Object { - "name": "references", - "type": "array", - "value": "[]", - }, - ] - `); - }); - - it('handles array fields', () => { - const obj = createObject({ - someArray: [1, 2, 3], - }); - expect(createFieldList(obj)).toMatchInlineSnapshot(` - Array [ - Object { - "name": "someArray", - "type": "array", - "value": "[ - 1, - 2, - 3 - ]", - }, - Object { - "name": "references", - "type": "array", - "value": "[]", - }, - ] - `); - }); - - it(`generates a field for the object's references`, () => { - const obj = createObject( - { - someString: 'foo', - }, - [ - { id: 'ref1', type: 'type', name: 'Ref 1' }, - { id: 'ref12', type: 'other-type', name: 'Ref 2' }, - ] - ); - expect(createFieldList(obj)).toMatchInlineSnapshot(` - Array [ - Object { - "name": "someString", - "type": "text", - "value": "foo", - }, - Object { - "name": "references", - "type": "array", - "value": "[ - { - \\"id\\": \\"ref1\\", - \\"type\\": \\"type\\", - \\"name\\": \\"Ref 1\\" - }, - { - \\"id\\": \\"ref12\\", - \\"type\\": \\"other-type\\", - \\"name\\": \\"Ref 2\\" - } - ]", - }, - ] - `); - }); - - it('recursively collect nested fields', () => { - const obj = createObject({ - firstLevel: { - firstLevelField: 'foo', - secondLevel: { - secondLevelFieldA: 'A', - secondLevelFieldB: 'B', - }, - }, - }); - expect(createFieldList(obj)).toMatchInlineSnapshot(` - Array [ - Object { - "name": "firstLevel.firstLevelField", - "type": "text", - "value": "foo", - }, - Object { - "name": "firstLevel.secondLevel.secondLevelFieldA", - "type": "text", - "value": "A", - }, - Object { - "name": "firstLevel.secondLevel.secondLevelFieldB", - "type": "text", - "value": "B", - }, - Object { - "name": "references", - "type": "array", - "value": "[]", - }, - ] - `); - }); -}); diff --git a/src/plugins/saved_objects_management/public/lib/create_field_list.ts b/src/plugins/saved_objects_management/public/lib/create_field_list.ts deleted file mode 100644 index 329ed80857696..0000000000000 --- a/src/plugins/saved_objects_management/public/lib/create_field_list.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { forOwn, keyBy, isNumber, isBoolean, isPlainObject, isString } from 'lodash'; -import { SimpleSavedObject } from '../../../../core/public'; -import { castEsToKbnFieldTypeName } from '../../../data/public'; -import { ObjectField } from '../management_section/types'; -import { SavedObjectLoader } from '../../../saved_objects/public'; -import { SavedObjectWithMetadata } from '../types'; - -const maxRecursiveIterations = 20; - -export function createFieldList( - object: SimpleSavedObject | SavedObjectWithMetadata, - service?: SavedObjectLoader -): ObjectField[] { - let fields = Object.entries(object.attributes as Record).reduce( - (objFields, [key, value]) => { - return [...objFields, ...createFields(key, value)]; - }, - [] as ObjectField[] - ); - // Special handling for references which isn't within "attributes" - fields = [...fields, ...createFields('references', object.references)]; - - if (service && (service as any).Class) { - addFieldsFromClass((service as any).Class, fields); - } - - return fields; -} - -/** - * Creates a field definition and pushes it to the memo stack. This function - * is designed to be used in conjunction with _.reduce(). If the - * values is plain object it will recurse through all the keys till it hits - * a string, number or an array. - * - * @param {string} key The key of the field - * @param {mixed} value The value of the field - * @param {array} parents The parent keys to the field - * @returns {array} - */ -const createFields = (key: string, value: any, parents: string[] = []): ObjectField[] => { - const path = [...parents, key]; - if (path.length > maxRecursiveIterations) { - return []; - } - - const field: ObjectField = { type: 'text', name: path.join('.'), value }; - - if (isString(field.value)) { - try { - field.value = JSON.stringify(JSON.parse(field.value), undefined, 2); - field.type = 'json'; - } catch (err) { - field.type = 'text'; - } - } else if (isNumber(field.value)) { - field.type = 'number'; - } else if (Array.isArray(field.value)) { - field.type = 'array'; - field.value = JSON.stringify(field.value, undefined, 2); - } else if (isBoolean(field.value)) { - field.type = 'boolean'; - } else if (isPlainObject(field.value)) { - let fields: ObjectField[] = []; - forOwn(field.value, (childValue, childKey) => { - fields = [...fields, ...createFields(childKey as string, childValue, path)]; - }); - return fields; - } - - return [field]; -}; - -const addFieldsFromClass = function ( - Class: { mapping: Record; searchSource: any }, - fields: ObjectField[] -) { - const fieldMap = keyBy(fields, 'name'); - - forOwn(Class.mapping, (esType, name) => { - if (!name || fieldMap[name]) { - return; - } - - const getFieldTypeFromEsType = () => { - switch (castEsToKbnFieldTypeName(esType)) { - case 'string': - return 'text'; - case 'number': - return 'number'; - case 'boolean': - return 'boolean'; - default: - return 'json'; - } - }; - - fields.push({ - name, - type: getFieldTypeFromEsType(), - value: undefined, - }); - }); - - if (Class.searchSource && !fieldMap['kibanaSavedObjectMeta.searchSourceJSON']) { - fields.push({ - name: 'kibanaSavedObjectMeta.searchSourceJSON', - type: 'json', - value: '{}', - }); - } - - if (!fieldMap.references) { - fields.push({ - name: 'references', - type: 'array', - value: '[]', - }); - } -}; diff --git a/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts b/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts deleted file mode 100644 index 28853f836085c..0000000000000 --- a/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { Capabilities } from '../../../../core/public'; -import { canViewInApp } from './in_app_url'; - -const createCapabilities = (sections: Record): Capabilities => { - return { - navLinks: {}, - management: {}, - catalogue: {}, - ...sections, - }; -}; - -describe('canViewInApp', () => { - it('should handle saved searches', () => { - let uiCapabilities = createCapabilities({ - discover: { - show: true, - }, - }); - expect(canViewInApp(uiCapabilities, 'search')).toEqual(true); - expect(canViewInApp(uiCapabilities, 'searches')).toEqual(true); - - uiCapabilities = createCapabilities({ - discover: { - show: false, - }, - }); - expect(canViewInApp(uiCapabilities, 'search')).toEqual(false); - expect(canViewInApp(uiCapabilities, 'searches')).toEqual(false); - }); - - it('should handle visualizations', () => { - let uiCapabilities = createCapabilities({ - visualize: { - show: true, - }, - }); - expect(canViewInApp(uiCapabilities, 'visualization')).toEqual(true); - expect(canViewInApp(uiCapabilities, 'visualizations')).toEqual(true); - - uiCapabilities = createCapabilities({ - visualize: { - show: false, - }, - }); - expect(canViewInApp(uiCapabilities, 'visualization')).toEqual(false); - expect(canViewInApp(uiCapabilities, 'visualizations')).toEqual(false); - }); - - it('should handle index patterns', () => { - let uiCapabilities = createCapabilities({ - management: { - kibana: { - indexPatterns: true, - }, - }, - }); - expect(canViewInApp(uiCapabilities, 'index-pattern')).toEqual(true); - expect(canViewInApp(uiCapabilities, 'index-patterns')).toEqual(true); - expect(canViewInApp(uiCapabilities, 'indexPatterns')).toEqual(true); - - uiCapabilities = createCapabilities({ - management: { - kibana: { - indexPatterns: false, - }, - }, - }); - expect(canViewInApp(uiCapabilities, 'index-pattern')).toEqual(false); - expect(canViewInApp(uiCapabilities, 'index-patterns')).toEqual(false); - expect(canViewInApp(uiCapabilities, 'indexPatterns')).toEqual(false); - }); - - it('should handle dashboards', () => { - let uiCapabilities = createCapabilities({ - dashboard: { - show: true, - }, - }); - expect(canViewInApp(uiCapabilities, 'dashboard')).toEqual(true); - expect(canViewInApp(uiCapabilities, 'dashboards')).toEqual(true); - - uiCapabilities = createCapabilities({ - dashboard: { - show: false, - }, - }); - expect(canViewInApp(uiCapabilities, 'dashboard')).toEqual(false); - expect(canViewInApp(uiCapabilities, 'dashboards')).toEqual(false); - }); - - it('should have a default case', () => { - let uiCapabilities = createCapabilities({ - foo: { - show: true, - }, - }); - expect(canViewInApp(uiCapabilities, 'foo')).toEqual(true); - - uiCapabilities = createCapabilities({ - foo: { - show: false, - }, - }); - expect(canViewInApp(uiCapabilities, 'foo')).toEqual(false); - }); -}); diff --git a/src/plugins/saved_objects_management/public/lib/in_app_url.ts b/src/plugins/saved_objects_management/public/lib/in_app_url.ts deleted file mode 100644 index c102ec21a83d0..0000000000000 --- a/src/plugins/saved_objects_management/public/lib/in_app_url.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { Capabilities } from 'src/core/public'; - -export function canViewInApp(uiCapabilities: Capabilities, type: string): boolean { - switch (type) { - case 'search': - case 'searches': - return uiCapabilities.discover.show as boolean; - case 'visualization': - case 'visualizations': - return uiCapabilities.visualize.show as boolean; - case 'index-pattern': - case 'index-patterns': - case 'indexPatterns': - return uiCapabilities.management.kibana.indexPatterns as boolean; - case 'dashboard': - case 'dashboards': - return uiCapabilities.dashboard.show as boolean; - default: - return uiCapabilities[type].show as boolean; - } -} diff --git a/src/plugins/saved_objects_management/public/lib/index.ts b/src/plugins/saved_objects_management/public/lib/index.ts index aefa5b614f618..e317bb5e39f73 100644 --- a/src/plugins/saved_objects_management/public/lib/index.ts +++ b/src/plugins/saved_objects_management/public/lib/index.ts @@ -8,7 +8,6 @@ export { fetchExportByTypeAndSearch } from './fetch_export_by_type_and_search'; export { fetchExportObjects } from './fetch_export_objects'; -export { canViewInApp } from './in_app_url'; export { getRelationships } from './get_relationships'; export { getSavedObjectCounts } from './get_saved_object_counts'; export { getSavedObjectLabel } from './get_saved_object_label'; @@ -24,6 +23,5 @@ export { getDefaultTitle } from './get_default_title'; export { findObjects } from './find_objects'; export { bulkGetObjects } from './bulk_get_objects'; export { extractExportDetails, SavedObjectsExportResultDetails } from './extract_export_details'; -export { createFieldList } from './create_field_list'; export { getAllowedTypes } from './get_allowed_types'; export { getTagFindReferences } from './get_tag_references'; diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx index 43cd5c93aa807..45170ad14f92c 100644 --- a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx +++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx @@ -15,12 +15,10 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import { CoreSetup } from 'src/core/public'; import { ManagementAppMountParams } from '../../../management/public'; import { StartDependencies, SavedObjectsManagementPluginStart } from '../plugin'; -import { ISavedObjectsManagementServiceRegistry } from '../services'; import { getAllowedTypes } from './../lib'; interface MountParams { core: CoreSetup; - serviceRegistry: ISavedObjectsManagementServiceRegistry; mountParams: ManagementAppMountParams; } @@ -32,11 +30,7 @@ const title = i18n.translate('savedObjectsManagement.objects.savedObjectsTitle', const SavedObjectsEditionPage = lazy(() => import('./saved_objects_edition_page')); const SavedObjectsTablePage = lazy(() => import('./saved_objects_table_page')); -export const mountManagementSection = async ({ - core, - mountParams, - serviceRegistry, -}: MountParams) => { +export const mountManagementSection = async ({ core, mountParams }: MountParams) => { const [coreStart, { data, savedObjectsTaggingOss, spaces: spacesApi }, pluginStart] = await core.getStartServices(); const { element, history, setBreadcrumbs } = mountParams; @@ -62,12 +56,11 @@ export const mountManagementSection = async ({ - + }> @@ -82,7 +75,6 @@ export const mountManagementSection = async ({ taggingApi={savedObjectsTaggingOss?.getTaggingApi()} spacesApi={spacesApi} dataStart={data} - serviceRegistry={serviceRegistry} actionRegistry={pluginStart.actions} columnRegistry={pluginStart.columns} allowedTypes={allowedObjectTypes} diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/__snapshots__/saved_object_view.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/__snapshots__/saved_object_view.test.tsx.snap new file mode 100644 index 0000000000000..8e3a954677b87 --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/object_view/__snapshots__/saved_object_view.test.tsx.snap @@ -0,0 +1,64 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SavedObjectEdition should render normally 1`] = ` + + + +
+ + + + + + +`; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap index c72e000e95e75..26ff23b50d87b 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap @@ -11,17 +11,7 @@ exports[`Intro component renders correctly 1`] = ` > - } + pageTitle="Inspect saved object" rightSideItems={ Array [ @@ -48,13 +38,9 @@ exports[`Intro component renders correctly 1`] = ` size="s" > , ] @@ -64,17 +50,7 @@ exports[`Intro component renders correctly 1`] = ` className="euiPageHeader euiPageHeader--bottomBorder euiPageHeader--responsive euiPageHeader--center" > - } + pageTitle="Inspect saved object" responsive={true} rightSideItems={ Array [ @@ -89,7 +65,7 @@ exports[`Intro component renders correctly 1`] = ` id="savedObjectsManagement.view.viewItemButtonLabel" values={ Object { - "title": "search", + "title": "saved object", } } /> @@ -102,13 +78,9 @@ exports[`Intro component renders correctly 1`] = ` size="s" > , ] @@ -136,17 +108,7 @@ exports[`Intro component renders correctly 1`] = `

- - Edit search - + Inspect saved object

@@ -234,11 +196,11 @@ exports[`Intro component renders correctly 1`] = ` id="savedObjectsManagement.view.viewItemButtonLabel" values={ Object { - "title": "search", + "title": "saved object", } } > - View search + View saved object
@@ -316,15 +278,11 @@ exports[`Intro component renders correctly 1`] = ` className="euiButton__text" > - Delete search + Delete diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/inspect.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/inspect.test.tsx.snap new file mode 100644 index 0000000000000..f35030ad736cc --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/inspect.test.tsx.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Inspect component renders correctly 1`] = ` + +`; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/intro.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/intro.test.tsx.snap deleted file mode 100644 index 9c9349b0524c0..0000000000000 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/intro.test.tsx.snap +++ /dev/null @@ -1,80 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Intro component renders correctly 1`] = ` - - - } - > -
-
- - - - Proceed with caution! - - -
- -
- -
-
- - Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn’t be. - -
-
-
-
-
-
-
-
-`; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap index 4227351f8e94d..c55583679f264 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap @@ -1,353 +1,541 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`NotFoundErrors component renders correctly for index-pattern type 1`] = ` - + } > - - } +
- - + +
+ +
-
- -
-
- - The index pattern associated with this object no longer exists. - -
-
- + + The index pattern associated with this object no longer exists. + +
+
+ + Saved objects APIs + , + } + } + > + If you know what this error means, you can use the + - If you know what this error means, go ahead and fix it — otherwise click the delete button above. - -
+ + Saved objects APIs + + + + + + + (opens in a new tab or window) + + + + + + to fix it — otherwise click the delete button above. +
-
-
- -
- - +
+ + + + +
`; exports[`NotFoundErrors component renders correctly for index-pattern-field type 1`] = ` - + } > - - } +
- - + +
+ +
-
- -
-
- - A field associated with this object no longer exists in the index pattern. - -
-
- + + A field associated with this object no longer exists in the index pattern. + +
+
+ + Saved objects APIs + , + } + } + > + If you know what this error means, you can use the + - If you know what this error means, go ahead and fix it — otherwise click the delete button above. - -
+ + Saved objects APIs + + + + + + + (opens in a new tab or window) + + + + + + to fix it — otherwise click the delete button above. +
-
-
- -
- - +
+ + + + +
`; exports[`NotFoundErrors component renders correctly for search type 1`] = ` - + } > - - } +
- - + +
+ +
-
- -
-
- - The saved search associated with this object no longer exists. - -
-
- + + The saved search associated with this object no longer exists. + +
+
+ + Saved objects APIs + , + } + } + > + If you know what this error means, you can use the + - If you know what this error means, go ahead and fix it — otherwise click the delete button above. - -
+ + Saved objects APIs + + + + + + + (opens in a new tab or window) + + + + + + to fix it — otherwise click the delete button above. +
-
-
- -
- - +
+ + + + +
`; exports[`NotFoundErrors component renders correctly for unknown type 1`] = ` - + } > - - } +
- - + +
+ +
-
- -
-
-
- +
+ + Saved objects APIs + , + } + } + > + If you know what this error means, you can use the + - If you know what this error means, go ahead and fix it — otherwise click the delete button above. - -
+ + Saved objects APIs + + + + + + + (opens in a new tab or window) + + + + + + to fix it — otherwise click the delete button above. +
- -
- -
- - +
+ +
+
+
+
`; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/field.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/field.test.tsx deleted file mode 100644 index 1fd70c65fd9c4..0000000000000 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/field.test.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { I18nProvider } from '@kbn/i18n/react'; -import { Field } from './field'; -import { FieldState, FieldType } from '../../types'; - -describe('Field component', () => { - const mountField = (props: { - type: FieldType; - name: string; - value: any; - disabled: boolean; - state?: FieldState; - onChange: (name: string, state: FieldState) => void; - }) => - mount( - - - - ).find('Field'); - - const defaultProps = { - type: 'text' as FieldType, - name: 'field', - value: '', - disabled: false, - state: undefined, - onChange: (name: string, state: FieldState) => undefined, - }; - - it('uses the field name as the label', () => { - let mounted = mountField({ ...defaultProps, name: 'some.name' }); - expect(mounted.find('EuiFormLabel').text()).toMatchInlineSnapshot(`"some.name"`); - - mounted = mountField({ ...defaultProps, name: 'someother.name' }); - expect(mounted.find('EuiFormLabel').text()).toMatchInlineSnapshot(`"someother.name"`); - }); - - it('renders a EuiCodeEditor for json type', () => { - const mounted = mountField({ ...defaultProps, type: 'json' }); - expect(mounted.exists('EuiCodeEditor')).toEqual(true); - }); - - it('renders a EuiCodeEditor for array type', () => { - const mounted = mountField({ ...defaultProps, type: 'array' }); - expect(mounted.exists('EuiCodeEditor')).toEqual(true); - }); - - it('renders a EuiSwitch for boolean type', () => { - const mounted = mountField({ ...defaultProps, type: 'boolean' }); - expect(mounted.exists('EuiSwitch')).toEqual(true); - }); - - it('display correct label for boolean type depending on value', () => { - let mounted = mountField({ ...defaultProps, type: 'boolean', value: true }); - expect(mounted.find('EuiSwitch').text()).toMatchInlineSnapshot(`"On"`); - - mounted = mountField({ ...defaultProps, type: 'boolean', value: false }); - expect(mounted.find('EuiSwitch').text()).toMatchInlineSnapshot(`"Off"`); - }); - - it('renders a EuiFieldNumber for number type', () => { - const mounted = mountField({ ...defaultProps, type: 'number' }); - expect(mounted.exists('EuiFieldNumber')).toEqual(true); - }); - - it('renders a EuiFieldText for text type', () => { - const mounted = mountField({ ...defaultProps, type: 'text' }); - expect(mounted.exists('EuiFieldText')).toEqual(true); - }); - - it('renders a EuiFieldText as fallback', () => { - const mounted = mountField({ ...defaultProps, type: 'unknown-type' as any }); - expect(mounted.exists('EuiFieldText')).toEqual(true); - }); -}); diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx deleted file mode 100644 index 2273527dd63f1..0000000000000 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/field.tsx +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { PureComponent } from 'react'; -import { EuiFieldNumber, EuiFieldText, EuiFormRow, EuiSwitch, EuiCodeEditor } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { FieldState, FieldType } from '../../types'; - -interface FieldProps { - type: FieldType; - name: string; - value: any; - disabled: boolean; - state?: FieldState; - onChange: (name: string, state: FieldState) => void; -} - -export class Field extends PureComponent { - render() { - const { name } = this.props; - - return ( - - {this.renderField()} - - ); - } - - onCodeEditorChange(targetValue: any) { - const { name, onChange } = this.props; - let invalid = false; - try { - JSON.parse(targetValue); - } catch (e) { - invalid = true; - } - onChange(name, { - value: targetValue, - invalid, - }); - } - - onFieldChange(targetValue: any) { - const { name, type, onChange } = this.props; - - let newParsedValue = targetValue; - let invalid = false; - if (type === 'number') { - try { - newParsedValue = Number(newParsedValue); - } catch (e) { - invalid = true; - } - } - onChange(name, { - value: newParsedValue, - invalid, - }); - } - - renderField() { - const { type, name, state, disabled } = this.props; - const currentValue = state?.value ?? this.props.value; - - switch (type) { - case 'number': - return ( - this.onFieldChange(e.target.value)} - disabled={disabled} - data-test-subj={`savedObjects-editField-${name}`} - /> - ); - case 'boolean': - return ( - - ) : ( - - ) - } - checked={!!currentValue} - onChange={(e) => this.onFieldChange(e.target.checked)} - disabled={disabled} - data-test-subj={`savedObjects-editField-${name}`} - /> - ); - case 'json': - case 'array': - return ( -
- this.onCodeEditorChange(value)} - width="100%" - height="auto" - minLines={6} - maxLines={30} - isReadOnly={disabled} - setOptions={{ - showLineNumbers: true, - tabSize: 2, - useSoftTabs: true, - }} - editorProps={{ - $blockScrolling: Infinity, - }} - showGutter={true} - /> -
- ); - default: - return ( - this.onFieldChange(e.target.value)} - disabled={disabled} - data-test-subj={`savedObjects-editField-${name}`} - /> - ); - } - } - - private get fieldId() { - const { name } = this.props; - return `savedObjects-editField-${name}`; - } -} diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/form.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/form.tsx deleted file mode 100644 index 8e33e0fbdc5e2..0000000000000 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/form.tsx +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { Component } from 'react'; -import { - EuiForm, - EuiFlexGroup, - EuiFlexItem, - EuiButton, - EuiButtonEmpty, - EuiSpacer, -} from '@elastic/eui'; -import { set } from '@elastic/safer-lodash-set'; -import { cloneDeep } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { SavedObjectsClientContract } from '../../../../../../core/public'; -import { SavedObjectLoader } from '../../../../../saved_objects/public'; -import { Field } from './field'; -import { ObjectField, FieldState, SubmittedFormData } from '../../types'; -import { createFieldList } from '../../../lib'; -import { SavedObjectWithMetadata } from '../../../types'; - -interface FormProps { - object: SavedObjectWithMetadata; - service: SavedObjectLoader; - savedObjectsClient: SavedObjectsClientContract; - editionEnabled: boolean; - onSave: (form: SubmittedFormData) => Promise; -} - -interface FormState { - fields: ObjectField[]; - fieldStates: Record; - submitting: boolean; -} - -export class Form extends Component { - constructor(props: FormProps) { - super(props); - this.state = { - fields: [], - fieldStates: {}, - submitting: false, - }; - } - - componentDidMount() { - const { object, service } = this.props; - - const fields = createFieldList(object, service); - - this.setState({ - fields, - }); - } - - render() { - const { editionEnabled, service } = this.props; - const { fields, fieldStates, submitting } = this.state; - const isValid = this.isFormValid(); - return ( - - {fields.map((field) => ( - - ))} - - - {editionEnabled && ( - - - - - - )} - - - - - - - - - ); - } - - handleFieldChange = (name: string, newState: FieldState) => { - this.setState({ - fieldStates: { - ...this.state.fieldStates, - [name]: newState, - }, - }); - }; - - isFormValid() { - const { fieldStates } = this.state; - return !Object.values(fieldStates).some((state) => state.invalid === true); - } - - onCancel = () => { - window.history.back(); - }; - - onSubmit = async () => { - const { object, onSave } = this.props; - const { fields, fieldStates } = this.state; - - if (!this.isFormValid()) { - return; - } - - this.setState({ - submitting: true, - }); - - const source = cloneDeep(object.attributes as any); - fields.forEach((field) => { - let value = fieldStates[field.name]?.value ?? field.value; - - if (field.type === 'array' && typeof value === 'string') { - value = JSON.parse(value); - } - - set(source, field.name, value); - }); - - // we extract the `references` field that does not belong to attributes - const { references, ...attributes } = source; - - await onSave({ attributes, references }); - - this.setState({ - submitting: false, - }); - }; -} diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/header.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/header.test.tsx index dbbd2485096f9..796632f9747a9 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/header.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/header.test.tsx @@ -19,6 +19,7 @@ describe('Intro component', () => { type: string; viewUrl: string; onDeleteClick: () => void; + title?: string; }) => mount( @@ -42,32 +43,11 @@ describe('Intro component', () => { expect(mounted).toMatchSnapshot(); }); - it('displays correct title depending on canEdit', () => { - let mounted = mountHeader({ - ...defaultProps, - canEdit: true, - }); - expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Edit search"`); - - mounted = mountHeader({ - ...defaultProps, - canEdit: false, - }); - expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"View search"`); - }); - - it('displays correct title depending on type', () => { - let mounted = mountHeader({ - ...defaultProps, - type: 'some-type', - }); - expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Edit some-type"`); - - mounted = mountHeader({ - ...defaultProps, - type: 'another-type', - }); - expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Edit another-type"`); + it('displays correct title if one is provided', () => { + let mounted = mountHeader({ ...defaultProps, title: 'my saved search' }); + expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Inspect my saved search"`); + mounted = mountHeader({ ...defaultProps, title: 'my other saved search' }); + expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Inspect my other saved search"`); }); it('only displays delete button if canDelete is true', () => { diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/header.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/header.tsx index 9a13a1d232cb3..10374b839ca48 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/header.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/header.tsx @@ -9,43 +9,24 @@ import React from 'react'; import { EuiButton, EuiPageHeader } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; interface HeaderProps { - canEdit: boolean; canDelete: boolean; canViewInApp: boolean; - type: string; viewUrl: string; onDeleteClick: () => void; + title?: string; } -const renderConditionalTitle = (canEdit: boolean, type: string) => - canEdit ? ( - - ) : ( - - ); - -export const Header = ({ - canEdit, - canDelete, - canViewInApp, - type, - viewUrl, - onDeleteClick, -}: HeaderProps) => { +export const Header = ({ canDelete, canViewInApp, viewUrl, onDeleteClick, title }: HeaderProps) => { return ( ), @@ -71,8 +52,7 @@ export const Header = ({ > ), diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/index.ts b/src/plugins/saved_objects_management/public/management_section/object_view/components/index.ts index ffffd589d5ef8..55322afb3fabb 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/index.ts +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/index.ts @@ -7,6 +7,5 @@ */ export { Header } from './header'; +export { Inspect } from './inspect'; export { NotFoundErrors } from './not_found_errors'; -export { Intro } from './intro'; -export { Form } from './form'; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/inspect.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/inspect.test.tsx new file mode 100644 index 0000000000000..433728baf6fc1 --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/inspect.test.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { ShallowWrapper } from 'enzyme'; +import { shallowWithI18nProvider } from '@kbn/test/jest'; +import { Inspect, InspectProps } from './inspect'; +import { SavedObjectWithMetadata } from '../../../../common'; + +describe('Inspect component', () => { + let defaultProps: { object: SavedObjectWithMetadata }; + const shallowRender = (overrides: Partial = {}) => { + return shallowWithI18nProvider( + + ) as unknown as ShallowWrapper; + }; + beforeEach(() => { + defaultProps = { + object: { + id: '1', + type: 'index-pattern', + attributes: { + title: `MyIndexPattern*`, + }, + meta: { + title: `MyIndexPattern*`, + icon: 'indexPatternApp', + editUrl: '#/management/kibana/indexPatterns/patterns/1', + inAppUrl: { + path: '/management/kibana/indexPatterns/patterns/1', + uiCapabilitiesPath: 'management.kibana.indexPatterns', + }, + }, + references: [], + }, + }; + }); + + it('renders correctly', async () => { + const component = shallowRender(); + await new Promise((resolve) => process.nextTick(resolve)); + component.update(); + const codeEditorComponent = component.find('CodeEditor'); + expect(codeEditorComponent).toMatchSnapshot(); + }); + + it("does not include `meta` in the value that's rendered", async () => { + const component = shallowRender(); + await new Promise((resolve) => process.nextTick(resolve)); + component.update(); + const codeEditorComponent = component.find('CodeEditor'); + // find could return nothing + const editorValue = codeEditorComponent + ? (codeEditorComponent.prop('value') as unknown as string) + : ''; + // we assert against the expected object props rather than asserting that 'meta' is removed + expect(Object.keys(JSON.parse(editorValue))).toEqual([ + 'id', + 'type', + 'attributes', + 'references', + ]); + }); +}); diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/inspect.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/inspect.tsx new file mode 100644 index 0000000000000..58d6da8ce935b --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/inspect.tsx @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React, { FC, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { XJsonLang } from '@kbn/monaco'; +import { omit } from 'lodash'; +import { EuiButtonEmpty, EuiCopy, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { CodeEditor } from '../../../../../kibana_react/public'; +import { SavedObjectWithMetadata } from '../../../../common'; + +export interface InspectProps { + object: SavedObjectWithMetadata; +} +const codeEditorAriaLabel = (title: string) => + i18n.translate('savedObjectsManagement.view.inspectCodeEditorAriaLabel', { + defaultMessage: 'inspect { title }', + values: { + title, + }, + }); +const copyToClipboardLabel = i18n.translate('savedObjectsManagement.view.copyToClipboardLabel', { + defaultMessage: 'Copy to clipboard', +}); + +export const Inspect: FC = ({ object }) => { + const title = object.meta.title || 'saved object'; + + const objectAsJsonString = useMemo(() => JSON.stringify(omit(object, 'meta'), null, 2), [object]); + + return ( + + +
+ + {(copy) => ( + + {copyToClipboardLabel} + + )} + + +
+ +
+
+ ); +}; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.test.tsx deleted file mode 100644 index 0b869743f03c7..0000000000000 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { I18nProvider } from '@kbn/i18n/react'; -import { Intro } from './intro'; - -describe('Intro component', () => { - it('renders correctly', () => { - const mounted = mount( - - - - ); - expect(mounted.find('Intro')).toMatchSnapshot(); - }); -}); diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx deleted file mode 100644 index 0431208d34ad5..0000000000000 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { EuiCallOut } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -export const Intro = () => { - return ( - - } - iconType="alert" - color="warning" - > -
- -
-
- ); -}; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.test.tsx index 767cc1ac59f47..5eab44cb416e9 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.test.tsx @@ -10,44 +10,49 @@ import React from 'react'; import { mount } from 'enzyme'; import { I18nProvider } from '@kbn/i18n/react'; import { NotFoundErrors } from './not_found_errors'; +import { docLinksServiceMock } from '../../../../../../core/public/mocks'; describe('NotFoundErrors component', () => { const mountError = (type: string) => mount( - + ).find('NotFoundErrors'); it('renders correctly for search type', () => { const mounted = mountError('search'); - expect(mounted).toMatchSnapshot(); + const callOut = mounted.find('EuiCallOut'); + expect(callOut).toMatchSnapshot(); expect(mounted.text()).toMatchInlineSnapshot( - `"There is a problem with this saved objectThe saved search associated with this object no longer exists.If you know what this error means, go ahead and fix it — otherwise click the delete button above."` + `"There is a problem with this saved objectThe saved search associated with this object no longer exists.If you know what this error means, you can use the Saved objects APIs(opens in a new tab or window) to fix it — otherwise click the delete button above."` ); }); it('renders correctly for index-pattern type', () => { const mounted = mountError('index-pattern'); - expect(mounted).toMatchSnapshot(); + const callOut = mounted.find('EuiCallOut'); + expect(callOut).toMatchSnapshot(); expect(mounted.text()).toMatchInlineSnapshot( - `"There is a problem with this saved objectThe index pattern associated with this object no longer exists.If you know what this error means, go ahead and fix it — otherwise click the delete button above."` + `"There is a problem with this saved objectThe index pattern associated with this object no longer exists.If you know what this error means, you can use the Saved objects APIs(opens in a new tab or window) to fix it — otherwise click the delete button above."` ); }); it('renders correctly for index-pattern-field type', () => { const mounted = mountError('index-pattern-field'); - expect(mounted).toMatchSnapshot(); + const callOut = mounted.find('EuiCallOut'); + expect(callOut).toMatchSnapshot(); expect(mounted.text()).toMatchInlineSnapshot( - `"There is a problem with this saved objectA field associated with this object no longer exists in the index pattern.If you know what this error means, go ahead and fix it — otherwise click the delete button above."` + `"There is a problem with this saved objectA field associated with this object no longer exists in the index pattern.If you know what this error means, you can use the Saved objects APIs(opens in a new tab or window) to fix it — otherwise click the delete button above."` ); }); it('renders correctly for unknown type', () => { const mounted = mountError('unknown'); - expect(mounted).toMatchSnapshot(); + const callOut = mounted.find('EuiCallOut'); + expect(callOut).toMatchSnapshot(); expect(mounted.text()).toMatchInlineSnapshot( - `"There is a problem with this saved objectIf you know what this error means, go ahead and fix it — otherwise click the delete button above."` + `"There is a problem with this saved objectIf you know what this error means, you can use the Saved objects APIs(opens in a new tab or window) to fix it — otherwise click the delete button above."` ); }); }); diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx index 2bce7b387a7e4..e3a349b1f4aa5 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx @@ -8,13 +8,23 @@ import React from 'react'; import { EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiLink } from '@elastic/eui'; +import { DocLinksStart } from '../../../../../../core/public'; interface NotFoundErrors { type: string; + docLinks: DocLinksStart['links']; } +const savedObjectsApisLinkText = i18n.translate( + 'savedObjectsManagement.view.howToFixErrorDescriptionLinkText', + { + defaultMessage: 'Saved objects APIs', + } +); -export const NotFoundErrors = ({ type }: NotFoundErrors) => { +export const NotFoundErrors = ({ type, docLinks }: NotFoundErrors) => { const getMessage = () => { switch (type) { case 'search': @@ -58,7 +68,18 @@ export const NotFoundErrors = ({ type }: NotFoundErrors) => {
+ {savedObjectsApisLinkText} + + ), + }} />
diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.scss b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.scss new file mode 100644 index 0000000000000..656f93468db90 --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.scss @@ -0,0 +1,3 @@ +.savedObjectsManagementObjectView { + height: 100%; +} diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.test.mocks.ts b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.test.mocks.ts new file mode 100644 index 0000000000000..7243955100690 --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.test.mocks.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +jest.doMock('lodash', () => { + const original = jest.requireActual('lodash'); + return { + ...original, + get: (func: Function) => { + function get(this: any, args: any[]) { + return func.apply(this, args); + } + return get; + }, + }; +}); + +export const bulkGetObjectsMock = jest.fn(); +jest.doMock('../../lib/bulk_get_objects', () => ({ + bulkGetObjects: bulkGetObjectsMock, +})); diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.test.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.test.tsx new file mode 100644 index 0000000000000..13a806361e543 --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.test.tsx @@ -0,0 +1,329 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { bulkGetObjectsMock } from './saved_object_view.test.mocks'; + +import React from 'react'; +import { ShallowWrapper } from 'enzyme'; +import { shallowWithI18nProvider } from '@kbn/test/jest'; + +import { + httpServiceMock, + overlayServiceMock, + notificationServiceMock, + savedObjectsServiceMock, + applicationServiceMock, + uiSettingsServiceMock, + scopedHistoryMock, + docLinksServiceMock, +} from '../../../../../core/public/mocks'; + +import { + SavedObjectEdition, + SavedObjectEditionProps, + SavedObjectEditionState, +} from './saved_object_view'; + +const resolvePromises = () => new Promise((resolve) => process.nextTick(resolve)); + +describe('SavedObjectEdition', () => { + let defaultProps: SavedObjectEditionProps; + let http: ReturnType; + let overlays: ReturnType; + let notifications: ReturnType; + let savedObjects: ReturnType; + let uiSettings: ReturnType; + let history: ReturnType; + let applications: ReturnType; + let docLinks: ReturnType; + + const shallowRender = (overrides: Partial = {}) => { + return shallowWithI18nProvider( + + ) as unknown as ShallowWrapper< + SavedObjectEditionProps, + SavedObjectEditionState, + SavedObjectEdition + >; + }; + + beforeEach(() => { + http = httpServiceMock.createStartContract(); + overlays = overlayServiceMock.createStartContract(); + notifications = notificationServiceMock.createStartContract(); + savedObjects = savedObjectsServiceMock.createStartContract(); + uiSettings = uiSettingsServiceMock.createStartContract(); + history = scopedHistoryMock.create(); + docLinks = docLinksServiceMock.createStartContract(); + applications = applicationServiceMock.createStartContract(); + applications.capabilities = { + navLinks: {}, + management: {}, + catalogue: {}, + savedObjectsManagement: { + read: true, + edit: false, + delete: false, + }, + }; + + http.post.mockResolvedValue([]); + + defaultProps = { + id: '1', + savedObjectType: 'dashboard', + http, + capabilities: applications.capabilities, + overlays, + notifications, + savedObjectsClient: savedObjects.client, + history, + uiSettings, + docLinks: docLinks.links, + }; + + bulkGetObjectsMock.mockImplementation(() => [{}]); + }); + + it('should render normally', async () => { + bulkGetObjectsMock.mockImplementation(() => + Promise.resolve([ + { + id: '1', + type: 'dashboard', + attributes: { + title: `MyDashboard*`, + }, + meta: { + title: `MyDashboard*`, + icon: 'dashboardApp', + inAppUrl: { + path: '/app/dashboards#/view/1', + uiCapabilitiesPath: 'management.kibana.dashboard', + }, + }, + }, + ]) + ); + const component = shallowRender(); + // Ensure all promises resolve + await resolvePromises(); + // Ensure the state changes are reflected + component.update(); + expect(component).toMatchSnapshot(); + }); + + it('should add danger toast when bulk get fails', async () => { + bulkGetObjectsMock.mockImplementation(() => + Promise.resolve([ + { + error: { + message: 'Not found', + }, + }, + ]) + ); + const component = shallowRender({ notFoundType: 'does_not_exist' }); + + await resolvePromises(); + + component.update(); + + expect(notifications.toasts.addDanger).toHaveBeenCalledTimes(1); + }); + + it('should add danger toast when bulk get throws', async () => { + bulkGetObjectsMock.mockImplementation(() => Promise.reject(new Error('fail'))); + const component = shallowRender({ notFoundType: 'does_not_exist' }); + + await resolvePromises(); + + component.update(); + + expect(notifications.toasts.addDanger).toHaveBeenCalledTimes(1); + }); + + it('should pass the correct props to the child components', async () => { + const savedObjectItem = { + id: '1', + type: 'index-pattern', + attributes: { + title: `MyIndexPattern*`, + }, + meta: { + title: `MyIndexPattern*`, + icon: 'indexPatternApp', + editUrl: '#/management/kibana/indexPatterns/patterns/1', + inAppUrl: { + path: '/management/kibana/indexPatterns/patterns/1', + uiCapabilitiesPath: 'management.kibana.indexPatterns', + }, + hiddenType: false, + }, + }; + bulkGetObjectsMock.mockImplementation(() => Promise.resolve([savedObjectItem])); + applications.capabilities = { + navLinks: {}, + management: {}, + catalogue: {}, + savedObjectsManagement: { + read: true, + edit: false, + delete: true, + }, + }; + const component = shallowRender({ + capabilities: applications.capabilities, + }); + + await resolvePromises(); + + component.update(); + const headerComponent = component.find('Header'); + expect(headerComponent.prop('canViewInApp')).toBe(true); + expect(headerComponent.prop('canDelete')).toBe(true); + expect(headerComponent.prop('viewUrl')).toEqual('/management/kibana/indexPatterns/patterns/1'); + const inspectComponent = component.find('Inspect'); + expect(inspectComponent.prop('object')).toEqual(savedObjectItem); + }); + + it("does not render Inspect if there isn't an object", async () => { + bulkGetObjectsMock.mockImplementation(() => Promise.resolve([])); + applications.capabilities = { + navLinks: {}, + management: {}, + catalogue: {}, + savedObjectsManagement: { + read: true, + edit: false, + delete: true, + }, + }; + const component = shallowRender({ + capabilities: applications.capabilities, + }); + + await resolvePromises(); + + component.update(); + const inspectComponent = component.find('Inspect'); + expect(inspectComponent).toEqual({}); + }); + + describe('delete', () => { + const savedObjectItem = { + id: '1', + type: 'index-pattern', + attributes: { + title: `MyIndexPattern*`, + }, + meta: { + title: `MyIndexPattern*`, + icon: 'indexPatternApp', + editUrl: '#/management/kibana/indexPatterns/patterns/1', + inAppUrl: { + path: '/management/kibana/indexPatterns/patterns/1', + uiCapabilitiesPath: 'management.kibana.indexPatterns', + }, + hiddenType: false, + }, + }; + + it('should display a confirmation message on deleting the saved object', async () => { + bulkGetObjectsMock.mockImplementation(() => Promise.resolve([savedObjectItem])); + const mockSavedObjectsClient = { + ...defaultProps.savedObjectsClient, + delete: jest.fn().mockImplementation(() => ({})), + }; + applications.capabilities = { + navLinks: {}, + management: {}, + catalogue: {}, + savedObjectsManagement: { + read: true, + edit: false, + delete: true, + }, + }; + overlays.openConfirm.mockResolvedValue(false); + const component = shallowRender({ + capabilities: applications.capabilities, + savedObjectsClient: mockSavedObjectsClient, + overlays, + }); + + await resolvePromises(); + + component.update(); + component.instance().delete(); + expect(overlays.openConfirm).toHaveBeenCalledWith( + 'This action permanently removes the object from Kibana.', + { + buttonColor: 'danger', + confirmButtonText: 'Delete', + title: `Delete '${savedObjectItem.meta.title}'?`, + } + ); + }); + + it('should route back if action is confirm and user accepted', async () => { + bulkGetObjectsMock.mockImplementation(() => Promise.resolve([savedObjectItem])); + const mockSavedObjectsClient = { + ...defaultProps.savedObjectsClient, + delete: jest.fn().mockImplementation(() => ({})), + }; + applications.capabilities = { + navLinks: {}, + management: {}, + catalogue: {}, + savedObjectsManagement: { + read: true, + edit: false, + delete: true, + }, + }; + overlays.openConfirm.mockResolvedValue(true); + const component = shallowRender({ + capabilities: applications.capabilities, + savedObjectsClient: mockSavedObjectsClient, + overlays, + }); + + await resolvePromises(); + + component.update(); + component.instance().delete(); + expect(overlays.openConfirm).toHaveBeenCalledTimes(1); + expect(history.location.pathname).toEqual('/'); + }); + + it('should not enable delete if the saved object is hidden', async () => { + bulkGetObjectsMock.mockImplementation(() => + Promise.resolve([{ ...savedObjectItem, meta: { hiddenType: true } }]) + ); + applications.capabilities = { + navLinks: {}, + management: {}, + catalogue: {}, + savedObjectsManagement: { + read: true, + edit: false, + delete: true, + }, + }; + const component = shallowRender({ + capabilities: applications.capabilities, + }); + + await resolvePromises(); + + component.update(); + expect(component.find('Header').prop('canDelete')).toBe(false); + }); + }); +}); diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx index 079a1c07da197..64b6e27309dd2 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx @@ -8,7 +8,9 @@ import React, { Component } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiSpacer } from '@elastic/eui'; +import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { get } from 'lodash'; +import { KibanaContextProvider } from '../../../../kibana_react/public'; import { Capabilities, SavedObjectsClientContract, @@ -16,27 +18,27 @@ import { NotificationsStart, ScopedHistory, HttpSetup, + IUiSettingsClient, + DocLinksStart, } from '../../../../../core/public'; -import { ISavedObjectsManagementServiceRegistry } from '../../services'; -import { Header, NotFoundErrors, Intro, Form } from './components'; -import { canViewInApp, bulkGetObjects } from '../../lib'; -import { SubmittedFormData } from '../types'; +import { Header, Inspect, NotFoundErrors } from './components'; +import { bulkGetObjects } from '../../lib/bulk_get_objects'; import { SavedObjectWithMetadata } from '../../types'; - -interface SavedObjectEditionProps { +import './saved_object_view.scss'; +export interface SavedObjectEditionProps { id: string; + savedObjectType: string; http: HttpSetup; - serviceName: string; - serviceRegistry: ISavedObjectsManagementServiceRegistry; capabilities: Capabilities; overlays: OverlayStart; notifications: NotificationsStart; notFoundType?: string; savedObjectsClient: SavedObjectsClientContract; history: ScopedHistory; + uiSettings: IUiSettingsClient; + docLinks: DocLinksStart['links']; } - -interface SavedObjectEditionState { +export interface SavedObjectEditionState { type: string; object?: SavedObjectWithMetadata; } @@ -45,7 +47,6 @@ const unableFindSavedObjectNotificationMessage = i18n.translate( 'savedObjectsManagement.objectView.unableFindSavedObjectNotificationMessage', { defaultMessage: 'Unable to find saved object' } ); - export class SavedObjectEdition extends Component< SavedObjectEditionProps, SavedObjectEditionState @@ -53,8 +54,7 @@ export class SavedObjectEdition extends Component< constructor(props: SavedObjectEditionProps) { super(props); - const { serviceRegistry, serviceName } = props; - const type = serviceRegistry.get(serviceName)!.service.type; + const { savedObjectType: type } = props; this.state = { object: undefined, @@ -85,54 +85,46 @@ export class SavedObjectEdition extends Component< }); } + canViewInApp(capabilities: Capabilities, obj?: SavedObjectWithMetadata) { + return obj && obj.meta.inAppUrl + ? get(capabilities, obj?.meta.inAppUrl?.uiCapabilitiesPath, false) && + Boolean(obj?.meta.inAppUrl?.path) + : false; + } + render() { - const { capabilities, notFoundType, serviceRegistry, http, serviceName, savedObjectsClient } = - this.props; - const { type } = this.state; + const { capabilities, notFoundType, http, uiSettings, docLinks } = this.props; const { object } = this.state; - const { edit: canEdit, delete: canDelete } = capabilities.savedObjectsManagement as Record< - string, - boolean - >; - const canView = canViewInApp(capabilities, type) && Boolean(object?.meta.inAppUrl?.path); - const service = serviceRegistry.get(serviceName)!.service; - + const { delete: canDelete } = capabilities.savedObjectsManagement as Record; + const canView = this.canViewInApp(capabilities, object); return ( -
-
this.delete()} - viewUrl={http.basePath.prepend(object?.meta.inAppUrl?.path || '')} - /> - - {notFoundType && ( - <> - - - - )} - {canEdit && ( - <> - - - - )} - {object && ( - <> - -
+ + +
this.delete()} + viewUrl={http.basePath.prepend(object?.meta.inAppUrl?.path || '')} + title={object?.meta.title} /> - - )} -
+ + {notFoundType && ( + + + + )} + {object && ( + + + + )} + + ); } @@ -167,15 +159,6 @@ export class SavedObjectEdition extends Component< } } - saveChanges = async ({ attributes, references }: SubmittedFormData) => { - const { savedObjectsClient, notifications } = this.props; - const { object, type } = this.state; - - await savedObjectsClient.update(object!.type, object!.id, attributes, { references }); - notifications.toasts.addSuccess(`Updated '${attributes.title}' ${type} object`); - this.redirectToListing(); - }; - redirectToListing() { this.props.history.push('/'); } diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap index 46ea319ebc168..327a9635462cc 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap @@ -192,7 +192,6 @@ exports[`SavedObjectsTable should render normally 1`] = ` Object { "id": "2", "meta": Object { - "editUrl": "/management/kibana/objects/savedSearches/2", "icon": "search", "inAppUrl": Object { "path": "/discover/2", @@ -205,7 +204,6 @@ exports[`SavedObjectsTable should render normally 1`] = ` Object { "id": "3", "meta": Object { - "editUrl": "/management/kibana/objects/savedDashboards/3", "icon": "dashboardApp", "inAppUrl": Object { "path": "/dashboard/3", @@ -218,7 +216,6 @@ exports[`SavedObjectsTable should render normally 1`] = ` Object { "id": "4", "meta": Object { - "editUrl": "/management/kibana/objects/savedVisualizations/4", "icon": "visualizeApp", "inAppUrl": Object { "path": "/edit/4", diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap index 6c07cb0c46ec6..7b69840b0ea6b 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/relationships.test.tsx.snap @@ -85,7 +85,6 @@ exports[`Relationships should render dashboards normally 1`] = ` Object { "id": "1", "meta": Object { - "editUrl": "/management/kibana/objects/savedVisualizations/1", "icon": "visualizeApp", "inAppUrl": Object { "path": "/app/visualize#/edit/1", @@ -99,7 +98,6 @@ exports[`Relationships should render dashboards normally 1`] = ` Object { "id": "2", "meta": Object { - "editUrl": "/management/kibana/objects/savedVisualizations/2", "icon": "visualizeApp", "inAppUrl": Object { "path": "/app/visualize#/edit/2", @@ -288,7 +286,6 @@ exports[`Relationships should render index patterns normally 1`] = ` Object { "id": "1", "meta": Object { - "editUrl": "/management/kibana/objects/savedSearches/1", "icon": "search", "inAppUrl": Object { "path": "/app/discover#//1", @@ -302,7 +299,6 @@ exports[`Relationships should render index patterns normally 1`] = ` Object { "id": "2", "meta": Object { - "editUrl": "/management/kibana/objects/savedVisualizations/2", "icon": "visualizeApp", "inAppUrl": Object { "path": "/app/visualize#/edit/2", @@ -645,7 +641,6 @@ exports[`Relationships should render searches normally 1`] = ` Object { "id": "2", "meta": Object { - "editUrl": "/management/kibana/objects/savedVisualizations/2", "icon": "visualizeApp", "inAppUrl": Object { "path": "/app/visualize#/edit/2", @@ -794,7 +789,6 @@ exports[`Relationships should render visualizations normally 1`] = ` Object { "id": "1", "meta": Object { - "editUrl": "/management/kibana/objects/savedDashboards/1", "icon": "dashboardApp", "inAppUrl": Object { "path": "/app/kibana#/dashboard/1", @@ -808,7 +802,6 @@ exports[`Relationships should render visualizations normally 1`] = ` Object { "id": "2", "meta": Object { - "editUrl": "/management/kibana/objects/savedDashboards/2", "icon": "dashboardApp", "inAppUrl": Object { "path": "/app/kibana#/dashboard/2", diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap index bb426c91e827c..8325e7dc886e8 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap @@ -146,7 +146,6 @@ exports[`Table prevents saved objects from being deleted 1`] = ` Object { "actions": Array [ Object { - "available": [Function], "data-test-subj": "savedObjectsTableAction-inspect", "description": "Inspect this saved object", "icon": "inspect", @@ -362,7 +361,6 @@ exports[`Table should render normally 1`] = ` Object { "actions": Array [ Object { - "available": [Function], "data-test-subj": "savedObjectsTableAction-inspect", "description": "Inspect this saved object", "icon": "inspect", diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx index 30d172b89256e..acdab1db40370 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx @@ -11,7 +11,6 @@ import { importFileMock, resolveImportErrorsMock } from './flyout.test.mocks'; import React from 'react'; import { shallowWithI18nProvider } from '@kbn/test/jest'; import { coreMock, httpServiceMock } from '../../../../../../core/public/mocks'; -import { serviceRegistryMock } from '../../../services/service_registry.mock'; import { Flyout, FlyoutProps, FlyoutState } from './flyout'; import { ShallowWrapper } from 'enzyme'; import { dataPluginMock } from '../../../../../data/public/mocks'; @@ -49,7 +48,6 @@ describe('Flyout', () => { } as any, http, allowedTypes: ['search', 'index-pattern', 'visualization'], - serviceRegistry: serviceRegistryMock.create(), search, basePath, }; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx index 26de8c5f8b25a..607b3aeeac275 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx @@ -43,7 +43,6 @@ import { processImportResponse, ProcessedImportResponse, } from '../../../lib'; -import { ISavedObjectsManagementServiceRegistry } from '../../../services'; import { FailedImportConflict, RetryDecision } from '../../../lib/resolve_import_errors'; import { OverwriteModal } from './overwrite_modal'; import { ImportModeControl, ImportMode } from './import_mode_control'; @@ -53,7 +52,6 @@ const CREATE_NEW_COPIES_DEFAULT = false; const OVERWRITE_ALL_DEFAULT = true; export interface FlyoutProps { - serviceRegistry: ISavedObjectsManagementServiceRegistry; allowedTypes: string[]; close: () => void; done: () => void; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx index 8b07351f6c2c2..c24faf4e12687 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import './import_summary.scss'; import _ from 'lodash'; import React, { Fragment, FC, useMemo } from 'react'; import { @@ -30,6 +29,7 @@ import type { IBasePath, } from 'kibana/public'; import { getDefaultTitle, getSavedObjectLabel, FailedImport } from '../../../lib'; +import './import_summary.scss'; const DEFAULT_ICON = 'apps'; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx index 4716594aa669b..b31c8ebbc4e9e 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx @@ -32,7 +32,6 @@ describe('Relationships', () => { id: '1', relationship: 'parent', meta: { - editUrl: '/management/kibana/objects/savedSearches/1', icon: 'search', inAppUrl: { path: '/app/discover#//1', @@ -46,7 +45,6 @@ describe('Relationships', () => { id: '2', relationship: 'parent', meta: { - editUrl: '/management/kibana/objects/savedVisualizations/2', icon: 'visualizeApp', inAppUrl: { path: '/app/visualize#/edit/2', @@ -116,7 +114,6 @@ describe('Relationships', () => { id: '2', relationship: 'parent', meta: { - editUrl: '/management/kibana/objects/savedVisualizations/2', icon: 'visualizeApp', inAppUrl: { path: '/app/visualize#/edit/2', @@ -136,7 +133,6 @@ describe('Relationships', () => { meta: { title: 'MySearch', icon: 'search', - editUrl: '/management/kibana/objects/savedSearches/1', inAppUrl: { path: '/discover/1', uiCapabilitiesPath: 'discover.show', @@ -172,7 +168,6 @@ describe('Relationships', () => { id: '1', relationship: 'parent', meta: { - editUrl: '/management/kibana/objects/savedDashboards/1', icon: 'dashboardApp', inAppUrl: { path: '/app/kibana#/dashboard/1', @@ -186,7 +181,6 @@ describe('Relationships', () => { id: '2', relationship: 'parent', meta: { - editUrl: '/management/kibana/objects/savedDashboards/2', icon: 'dashboardApp', inAppUrl: { path: '/app/kibana#/dashboard/2', @@ -206,7 +200,6 @@ describe('Relationships', () => { meta: { title: 'MyViz', icon: 'visualizeApp', - editUrl: '/management/kibana/objects/savedVisualizations/1', inAppUrl: { path: '/edit/1', uiCapabilitiesPath: 'visualize.show', @@ -242,7 +235,6 @@ describe('Relationships', () => { id: '1', relationship: 'child', meta: { - editUrl: '/management/kibana/objects/savedVisualizations/1', icon: 'visualizeApp', inAppUrl: { path: '/app/visualize#/edit/1', @@ -256,7 +248,6 @@ describe('Relationships', () => { id: '2', relationship: 'child', meta: { - editUrl: '/management/kibana/objects/savedVisualizations/2', icon: 'visualizeApp', inAppUrl: { path: '/app/visualize#/edit/2', @@ -276,7 +267,6 @@ describe('Relationships', () => { meta: { title: 'MyDashboard', icon: 'dashboardApp', - editUrl: '/management/kibana/objects/savedDashboards/1', inAppUrl: { path: '/dashboard/1', uiCapabilitiesPath: 'dashboard.show', @@ -316,7 +306,6 @@ describe('Relationships', () => { meta: { title: 'MyDashboard', icon: 'dashboardApp', - editUrl: '/management/kibana/objects/savedDashboards/1', inAppUrl: { path: '/dashboard/1', uiCapabilitiesPath: 'dashboard.show', diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx index f9171c7928dbe..8eb48ac91da66 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx @@ -298,7 +298,7 @@ export class Relationships extends Component goInspectObject(object), - available: (object: SavedObjectWithMetadata) => !!object.meta.editUrl, + available: (object: SavedObjectWithMetadata) => !!(object.type && object.id), }, ], }, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx index 4e4bd51c4bb84..0645c0955f7ac 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx @@ -243,7 +243,6 @@ export class Table extends PureComponent { type: 'icon', icon: 'inspect', onClick: (object) => goInspectObject(object), - available: (object) => !!object.meta.editUrl, 'data-test-subj': 'savedObjectsTableAction-inspect', }, { diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx index 21a629097cbb4..025a7a320327f 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx @@ -28,7 +28,6 @@ import { applicationServiceMock, } from '../../../../../core/public/mocks'; import { dataPluginMock } from '../../../../data/public/mocks'; -import { serviceRegistryMock } from '../../services/service_registry.mock'; import { actionServiceMock } from '../../services/action_service.mock'; import { columnServiceMock } from '../../services/column_service.mock'; import { @@ -122,7 +121,6 @@ describe('SavedObjectsTable', () => { defaultProps = { allowedTypes, - serviceRegistry: serviceRegistryMock.create(), actionRegistry: actionServiceMock.createStart(), columnRegistry: columnServiceMock.createStart(), savedObjectsClient: savedObjects.client, @@ -159,7 +157,6 @@ describe('SavedObjectsTable', () => { meta: { title: `MySearch`, icon: 'search', - editUrl: '/management/kibana/objects/savedSearches/2', inAppUrl: { path: '/discover/2', uiCapabilitiesPath: 'discover.show', @@ -172,7 +169,6 @@ describe('SavedObjectsTable', () => { meta: { title: `MyDashboard`, icon: 'dashboardApp', - editUrl: '/management/kibana/objects/savedDashboards/3', inAppUrl: { path: '/dashboard/3', uiCapabilitiesPath: 'dashboard.show', @@ -185,7 +181,6 @@ describe('SavedObjectsTable', () => { meta: { title: `MyViz`, icon: 'visualizeApp', - editUrl: '/management/kibana/objects/savedVisualizations/4', inAppUrl: { path: '/edit/4', uiCapabilitiesPath: 'visualize.show', diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx index d4067cc21c2be..5001b52e819c2 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx @@ -37,7 +37,6 @@ import { } from '../../lib'; import { SavedObjectWithMetadata } from '../../types'; import { - ISavedObjectsManagementServiceRegistry, SavedObjectsManagementActionServiceStart, SavedObjectsManagementColumnServiceStart, } from '../../services'; @@ -58,7 +57,6 @@ interface ExportAllOption { export interface SavedObjectsTableProps { allowedTypes: string[]; - serviceRegistry: ISavedObjectsManagementServiceRegistry; actionRegistry: SavedObjectsManagementActionServiceStart; columnRegistry: SavedObjectsManagementColumnServiceStart; savedObjectsClient: SavedObjectsClientContract; @@ -540,7 +538,6 @@ export class SavedObjectsTable extends Component void; history: ScopedHistory; }) => { - const { service: serviceName, id } = useParams<{ service: string; id: string }>(); + const { type, id } = useParams<{ type: string; id: string }>(); const capabilities = coreStart.application.capabilities; + const dockLinks = coreStart.docLinks.links; const { search } = useLocation(); const query = parse(search); - const service = serviceRegistry.get(serviceName); useEffect(() => { setBreadcrumbs([ @@ -42,27 +40,31 @@ const SavedObjectsEditionPage = ({ href: '/', }, { - text: i18n.translate('savedObjectsManagement.breadcrumb.edit', { - defaultMessage: 'Edit {savedObjectType}', - values: { savedObjectType: service?.service.type ?? 'object' }, + text: i18n.translate('savedObjectsManagement.breadcrumb.inspect', { + defaultMessage: 'Inspect {savedObjectType}', + values: { savedObjectType: type }, }), }, ]); - }, [setBreadcrumbs, service]); + }, [setBreadcrumbs, type]); return ( - + ); diff --git a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx index f22f0333ec229..31b058cd65315 100644 --- a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx +++ b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx @@ -17,7 +17,6 @@ import type { SpacesApi, SpacesContextProps } from '../../../../../x-pack/plugin import { DataPublicPluginStart } from '../../../data/public'; import { SavedObjectsTaggingApi } from '../../../saved_objects_tagging_oss/public'; import { - ISavedObjectsManagementServiceRegistry, SavedObjectsManagementActionServiceStart, SavedObjectsManagementColumnServiceStart, } from '../services'; @@ -31,7 +30,6 @@ const SavedObjectsTablePage = ({ taggingApi, spacesApi, allowedTypes, - serviceRegistry, actionRegistry, columnRegistry, setBreadcrumbs, @@ -41,7 +39,6 @@ const SavedObjectsTablePage = ({ taggingApi?: SavedObjectsTaggingApi; spacesApi?: SpacesApi; allowedTypes: string[]; - serviceRegistry: ISavedObjectsManagementServiceRegistry; actionRegistry: SavedObjectsManagementActionServiceStart; columnRegistry: SavedObjectsManagementColumnServiceStart; setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; @@ -75,13 +72,11 @@ const SavedObjectsTablePage = ({ spacesApi ? spacesApi.ui.components.getSpacesContextProvider : getEmptyFunctionComponent, [spacesApi] ); - return ( { - const { editUrl } = savedObject.meta; - if (editUrl) { - return coreStart.application.navigateToUrl( - coreStart.http.basePath.prepend(`/app${editUrl}`) - ); - } + const savedObjectEditUrl = savedObject.meta.editUrl + ? `/app${savedObject.meta.editUrl}` + : `/app/management/kibana/objects/${savedObject.type}/${savedObject.id}`; + coreStart.application.navigateToUrl(coreStart.http.basePath.prepend(savedObjectEditUrl)); }} canGoInApp={(savedObject) => { const { inAppUrl } = savedObject.meta; diff --git a/src/plugins/saved_objects_management/public/management_section/types.ts b/src/plugins/saved_objects_management/public/management_section/types.ts deleted file mode 100644 index 81c4bef1e1450..0000000000000 --- a/src/plugins/saved_objects_management/public/management_section/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { SavedObjectReference } from '../../../../core/types'; - -export interface ObjectField { - type: FieldType; - name: string; - value: any; -} - -export type FieldType = 'text' | 'number' | 'boolean' | 'array' | 'json'; - -export interface FieldState { - value?: any; - invalid?: boolean; -} - -export interface SubmittedFormData { - attributes: any; - references: SavedObjectReference[]; -} diff --git a/src/plugins/saved_objects_management/public/mocks.ts b/src/plugins/saved_objects_management/public/mocks.ts index c0675620e2594..b8ad4cd1ea885 100644 --- a/src/plugins/saved_objects_management/public/mocks.ts +++ b/src/plugins/saved_objects_management/public/mocks.ts @@ -8,14 +8,12 @@ import { actionServiceMock } from './services/action_service.mock'; import { columnServiceMock } from './services/column_service.mock'; -import { serviceRegistryMock } from './services/service_registry.mock'; import { SavedObjectsManagementPluginSetup, SavedObjectsManagementPluginStart } from './plugin'; const createSetupContractMock = (): jest.Mocked => { const mock = { actions: actionServiceMock.createSetup(), columns: columnServiceMock.createSetup(), - serviceRegistry: serviceRegistryMock.create(), }; return mock; }; @@ -29,7 +27,6 @@ const createStartContractMock = (): jest.Mocked, @@ -80,8 +69,7 @@ export class SavedObjectsManagementPlugin defaultMessage: 'Saved Objects', }), description: i18n.translate('savedObjectsManagement.objects.savedObjectsDescription', { - defaultMessage: - 'Import, export, and manage your saved searches, visualizations, and dashboards.', + defaultMessage: 'Import, export, and manage your saved objects.', }), icon: 'savedObjectsApp', path: '/app/management/kibana/objects', @@ -101,19 +89,14 @@ export class SavedObjectsManagementPlugin const { mountManagementSection } = await import('./management_section'); return mountManagementSection({ core, - serviceRegistry: this.serviceRegistry, mountParams, }); }, }); - // depends on `getStartServices`, should not be awaited - registerServices(this.serviceRegistry, core.getStartServices); - return { actions: actionSetup, columns: columnSetup, - serviceRegistry: this.serviceRegistry, }; } diff --git a/src/plugins/saved_objects_management/public/register_services.ts b/src/plugins/saved_objects_management/public/register_services.ts deleted file mode 100644 index da65c8c9f130b..0000000000000 --- a/src/plugins/saved_objects_management/public/register_services.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { StartServicesAccessor } from '../../../core/public'; -import { SavedObjectsManagementPluginStart, StartDependencies } from './plugin'; -import { ISavedObjectsManagementServiceRegistry } from './services'; - -export const registerServices = async ( - registry: ISavedObjectsManagementServiceRegistry, - getStartServices: StartServicesAccessor -) => { - const [, { dashboard, visualizations, discover }] = await getStartServices(); - - if (dashboard) { - registry.register({ - id: 'savedDashboards', - title: 'dashboards', - service: dashboard.getSavedDashboardLoader(), - }); - } - - if (visualizations) { - registry.register({ - id: 'savedVisualizations', - title: 'visualizations', - service: visualizations.savedVisualizationsLoader, - }); - } - - if (discover) { - registry.register({ - id: 'savedSearches', - title: 'searches', - service: discover.savedSearchLoader, - }); - } -}; diff --git a/src/plugins/saved_objects_management/public/services/index.ts b/src/plugins/saved_objects_management/public/services/index.ts index 4ff259d48f1a6..f3c0100d61599 100644 --- a/src/plugins/saved_objects_management/public/services/index.ts +++ b/src/plugins/saved_objects_management/public/services/index.ts @@ -16,11 +16,6 @@ export { SavedObjectsManagementColumnServiceStart, SavedObjectsManagementColumnServiceSetup, } from './column_service'; -export { - SavedObjectsManagementServiceRegistry, - ISavedObjectsManagementServiceRegistry, - SavedObjectsManagementServiceRegistryEntry, -} from './service_registry'; export { SavedObjectsManagementAction, SavedObjectsManagementColumn, diff --git a/src/plugins/saved_objects_management/public/services/service_registry.ts b/src/plugins/saved_objects_management/public/services/service_registry.ts deleted file mode 100644 index 9e4ed5a48993c..0000000000000 --- a/src/plugins/saved_objects_management/public/services/service_registry.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { PublicMethodsOf } from '@kbn/utility-types'; -import { SavedObjectLoader } from '../../../saved_objects/public'; - -export interface SavedObjectsManagementServiceRegistryEntry { - id: string; - service: SavedObjectLoader; - title: string; -} - -export type ISavedObjectsManagementServiceRegistry = - PublicMethodsOf; - -export class SavedObjectsManagementServiceRegistry { - private readonly registry = new Map(); - - public register(entry: SavedObjectsManagementServiceRegistryEntry) { - if (this.registry.has(entry.id)) { - throw new Error(''); - } - this.registry.set(entry.id, entry); - } - - public all(): SavedObjectsManagementServiceRegistryEntry[] { - return [...this.registry.values()]; - } - - public get(id: string): SavedObjectsManagementServiceRegistryEntry | undefined { - return this.registry.get(id); - } -} diff --git a/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts index 13adf2764b555..ce371ea590230 100644 --- a/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts +++ b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts @@ -17,6 +17,7 @@ export const registerGetAllowedTypesRoute = (router: IRouter) => { async (context, req, res) => { const allowedTypes = context.core.savedObjects.typeRegistry .getImportableAndExportableTypes() + .filter((type) => type.management!.visibleInManagement ?? true) .map((type) => type.name); return res.ok({ diff --git a/src/plugins/saved_objects_management/tsconfig.json b/src/plugins/saved_objects_management/tsconfig.json index 545d4697ca2cd..58483e144aab8 100644 --- a/src/plugins/saved_objects_management/tsconfig.json +++ b/src/plugins/saved_objects_management/tsconfig.json @@ -13,13 +13,11 @@ ], "references": [ { "path": "../../core/tsconfig.json" }, - { "path": "../dashboard/tsconfig.json" }, { "path": "../data/tsconfig.json" }, - { "path": "../discover/tsconfig.json" }, { "path": "../home/tsconfig.json" }, { "path": "../kibana_react/tsconfig.json" }, { "path": "../management/tsconfig.json" }, - { "path": "../visualizations/tsconfig.json" }, + { "path": "../saved_objects_tagging_oss/tsconfig.json" }, { "path": "../../../x-pack/plugins/spaces/tsconfig.json" }, ] } diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 0a81da0cdceba..2363c0ca103a2 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -7428,6 +7428,12 @@ "description": "Non-default value of setting." } }, + "metrics:allowStringIndices": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "query:allowLeadingWildcards": { "type": "boolean", "_meta": { diff --git a/src/plugins/vis_default_editor/public/components/controls/date_ranges.test.tsx b/src/plugins/vis_default_editor/public/components/controls/date_ranges.test.tsx index f10c695662546..02cc0aadfff61 100644 --- a/src/plugins/vis_default_editor/public/components/controls/date_ranges.test.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/date_ranges.test.tsx @@ -55,6 +55,9 @@ describe('DateRangesParamEditor component', () => { }); it('should validate range values with date math', function () { + const mockedConsoleWarn = jest.spyOn(console, 'warn'); // mocked console.warn to avoid console messages when running tests + mockedConsoleWarn.mockImplementation(() => {}); + const component = mountWithIntl(); // should allow empty values @@ -86,5 +89,7 @@ describe('DateRangesParamEditor component', () => { component.setProps({ value: [{ from: '5/5/2005+3d' }] }); expect(setValidity).toHaveBeenNthCalledWith(10, false); + + mockedConsoleWarn.mockRestore(); }); }); diff --git a/src/plugins/vis_default_editor/public/components/controls/percentiles.test.tsx b/src/plugins/vis_default_editor/public/components/controls/percentiles.test.tsx index 849253840f18c..c009196c20d8c 100644 --- a/src/plugins/vis_default_editor/public/components/controls/percentiles.test.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/percentiles.test.tsx @@ -9,10 +9,22 @@ import React from 'react'; import { AggParamEditorProps } from '../agg_param_props'; import { IAggConfig } from 'src/plugins/data/public'; -import { mount } from 'enzyme'; +import { mountWithIntl as mount } from '@kbn/test/jest'; import { PercentilesEditor } from './percentiles'; import { EditorVisState } from '../sidebar/state/reducers'; +// mocking random id generator function +jest.mock('@elastic/eui', () => { + const original = jest.requireActual('@elastic/eui'); + + return { + ...original, + htmlIdGenerator: (fn: unknown) => { + let counter = 0; + return () => counter++; + }, + }; +}); describe('PercentilesEditor component', () => { let setValue: jest.Mock; let setValidity: jest.Mock; diff --git a/src/plugins/vis_type_timeseries/tsconfig.json b/src/plugins/vis_type_timeseries/tsconfig.json deleted file mode 100644 index 68097d8cff786..0000000000000 --- a/src/plugins/vis_type_timeseries/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./target/types", - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "include": [ - "common/**/*", - "public/**/*", - "server/**/*", - "*.ts" - ], - "references": [ - { "path": "../../core/tsconfig.json" }, - { "path": "../charts/tsconfig.json" }, - { "path": "../data/tsconfig.json" }, - { "path": "../expressions/tsconfig.json" }, - { "path": "../visualizations/tsconfig.json" }, - { "path": "../visualize/tsconfig.json" }, - { "path": "../kibana_utils/tsconfig.json" }, - { "path": "../kibana_react/tsconfig.json" }, - { "path": "../usage_collection/tsconfig.json" }, - ] -} diff --git a/src/plugins/vis_types/metric/server/index.ts b/src/plugins/vis_types/metric/server/index.ts index 740fe3426dd84..a14a44b6caa80 100644 --- a/src/plugins/vis_types/metric/server/index.ts +++ b/src/plugins/vis_types/metric/server/index.ts @@ -12,9 +12,6 @@ import { configSchema, ConfigSchema } from '../config'; export const config: PluginConfigDescriptor = { schema: configSchema, - deprecations: ({ renameFromRoot }) => [ - renameFromRoot('metric_vis.enabled', 'vis_type_metric.enabled'), - ], }; export const plugin = () => ({ diff --git a/src/plugins/vis_types/pie/config.ts b/src/plugins/vis_types/pie/config.ts new file mode 100644 index 0000000000000..b831d26854c30 --- /dev/null +++ b/src/plugins/vis_types/pie/config.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +export const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), +}); + +export type ConfigSchema = TypeOf; diff --git a/src/plugins/vis_types/pie/server/index.ts b/src/plugins/vis_types/pie/server/index.ts index 201071fbb5fca..1e92bedb3d11c 100644 --- a/src/plugins/vis_types/pie/server/index.ts +++ b/src/plugins/vis_types/pie/server/index.ts @@ -5,6 +5,13 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ + +import { PluginConfigDescriptor } from 'src/core/server'; +import { configSchema, ConfigSchema } from '../config'; import { VisTypePieServerPlugin } from './plugin'; +export const config: PluginConfigDescriptor = { + schema: configSchema, +}; + export const plugin = () => new VisTypePieServerPlugin(); diff --git a/src/plugins/vis_types/pie/tsconfig.json b/src/plugins/vis_types/pie/tsconfig.json index 9a0a3418d72db..99e25a4eba632 100644 --- a/src/plugins/vis_types/pie/tsconfig.json +++ b/src/plugins/vis_types/pie/tsconfig.json @@ -9,7 +9,8 @@ "include": [ "common/**/*", "public/**/*", - "server/**/*" + "server/**/*", + "*.ts" ], "references": [ { "path": "../../../core/tsconfig.json" }, diff --git a/src/plugins/vis_types/table/server/index.ts b/src/plugins/vis_types/table/server/index.ts index b98fdd9c445db..2f84e8daef450 100644 --- a/src/plugins/vis_types/table/server/index.ts +++ b/src/plugins/vis_types/table/server/index.ts @@ -14,9 +14,6 @@ import { registerVisTypeTableUsageCollector } from './usage_collector'; export const config: PluginConfigDescriptor = { schema: configSchema, - deprecations: ({ renameFromRoot }) => [ - renameFromRoot('table_vis.enabled', 'vis_type_table.enabled'), - ], }; export const plugin = () => ({ diff --git a/src/plugins/vis_types/tagcloud/server/index.ts b/src/plugins/vis_types/tagcloud/server/index.ts index 6899a333a8812..a14a44b6caa80 100644 --- a/src/plugins/vis_types/tagcloud/server/index.ts +++ b/src/plugins/vis_types/tagcloud/server/index.ts @@ -12,9 +12,6 @@ import { configSchema, ConfigSchema } from '../config'; export const config: PluginConfigDescriptor = { schema: configSchema, - deprecations: ({ renameFromRoot }) => [ - renameFromRoot('tagcloud.enabled', 'vis_type_tagcloud.enabled'), - ], }; export const plugin = () => ({ diff --git a/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts b/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts index e44d74cfd72ab..e9a076b4dc832 100644 --- a/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts +++ b/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts @@ -120,7 +120,7 @@ export function getTimelionRequestHandler({ const err = new Error( `${i18n.translate('timelion.requestHandlerErrorTitle', { defaultMessage: 'Timelion request error', - })}: ${e.body.title} ${e.body.message}` + })}:${e.body.title ? ' ' + e.body.title : ''} ${e.body.message}` ); err.stack = e.stack; throw err; diff --git a/src/plugins/vis_types/timelion/server/handlers/chain_runner.js b/src/plugins/vis_types/timelion/server/handlers/chain_runner.js index b7bdbcdcb57a6..3710d015f3f69 100644 --- a/src/plugins/vis_types/timelion/server/handlers/chain_runner.js +++ b/src/plugins/vis_types/timelion/server/handlers/chain_runner.js @@ -25,7 +25,15 @@ export default function chainRunner(tlConfig) { let sheet; function throwWithCell(cell, exception) { - throw new Error(' in cell #' + (cell + 1) + ': ' + exception.message); + throw new Error( + i18n.translate('timelion.serverSideErrors.errorInCell', { + defaultMessage: ' in cell #{number}: {message}', + values: { + number: cell + 1, + message: exception.message, + }, + }) + ); } // Invokes a modifier function, resolving arguments into series as needed diff --git a/src/plugins/vis_types/timelion/server/routes/run.ts b/src/plugins/vis_types/timelion/server/routes/run.ts index b3ab3c61c15d8..b8c0ce4ea6599 100644 --- a/src/plugins/vis_types/timelion/server/routes/run.ts +++ b/src/plugins/vis_types/timelion/server/routes/run.ts @@ -94,15 +94,18 @@ export function runRoute( allowedGraphiteUrls: configManager.getGraphiteUrls(), esShardTimeout: configManager.getEsShardTimeout(), }); - const chainRunner = chainRunnerFn(tlConfig); - const sheet = await Bluebird.all(chainRunner.processRequest(request.body)); - - return response.ok({ - body: { - sheet, - stats: chainRunner.getStats(), - }, - }); + try { + const chainRunner = chainRunnerFn(tlConfig); + const sheet = await Bluebird.all(chainRunner.processRequest(request.body)); + return response.ok({ + body: { + sheet, + stats: chainRunner.getStats(), + }, + }); + } catch (e) { + return response.badRequest({ body: { message: e.message } }); + } }) ); } diff --git a/src/plugins/vis_type_timeseries/common/__mocks__/index_patterns_utils.ts b/src/plugins/vis_types/timeseries/common/__mocks__/index_patterns_utils.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/__mocks__/index_patterns_utils.ts rename to src/plugins/vis_types/timeseries/common/__mocks__/index_patterns_utils.ts diff --git a/src/plugins/vis_type_timeseries/common/agg_utils.test.ts b/src/plugins/vis_types/timeseries/common/agg_utils.test.ts similarity index 99% rename from src/plugins/vis_type_timeseries/common/agg_utils.test.ts rename to src/plugins/vis_types/timeseries/common/agg_utils.test.ts index 63d81e2c43d40..21fa870c2ca04 100644 --- a/src/plugins/vis_type_timeseries/common/agg_utils.test.ts +++ b/src/plugins/vis_types/timeseries/common/agg_utils.test.ts @@ -13,7 +13,7 @@ import { getAggsByPredicate, getAggsByType, } from './agg_utils'; -import { METRIC_TYPES } from '../../data/common'; +import { METRIC_TYPES } from '../../../data/common'; import { TSVB_METRIC_TYPES } from './enums'; import type { Metric } from './types'; diff --git a/src/plugins/vis_type_timeseries/common/agg_utils.ts b/src/plugins/vis_types/timeseries/common/agg_utils.ts similarity index 99% rename from src/plugins/vis_type_timeseries/common/agg_utils.ts rename to src/plugins/vis_types/timeseries/common/agg_utils.ts index 2f0488bdc4dbe..71f13542b10f4 100644 --- a/src/plugins/vis_type_timeseries/common/agg_utils.ts +++ b/src/plugins/vis_types/timeseries/common/agg_utils.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { filter } from 'lodash'; import { Assign } from 'utility-types'; -import { METRIC_TYPES } from '../../data/common'; +import { METRIC_TYPES } from '../../../data/common'; import { TSVB_METRIC_TYPES } from './enums'; import type { Metric, MetricType } from './types'; diff --git a/src/plugins/vis_type_timeseries/common/basic_aggs.ts b/src/plugins/vis_types/timeseries/common/basic_aggs.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/basic_aggs.ts rename to src/plugins/vis_types/timeseries/common/basic_aggs.ts diff --git a/src/plugins/vis_type_timeseries/common/calculate_label.test.ts b/src/plugins/vis_types/timeseries/common/calculate_label.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/calculate_label.test.ts rename to src/plugins/vis_types/timeseries/common/calculate_label.test.ts diff --git a/src/plugins/vis_type_timeseries/common/calculate_label.ts b/src/plugins/vis_types/timeseries/common/calculate_label.ts similarity index 98% rename from src/plugins/vis_type_timeseries/common/calculate_label.ts rename to src/plugins/vis_types/timeseries/common/calculate_label.ts index d054698536b5b..e5cf053d310aa 100644 --- a/src/plugins/vis_type_timeseries/common/calculate_label.ts +++ b/src/plugins/vis_types/timeseries/common/calculate_label.ts @@ -10,7 +10,7 @@ import { includes, startsWith } from 'lodash'; import { i18n } from '@kbn/i18n'; import { getMetricLabel } from './agg_utils'; import { extractFieldLabel } from './fields_utils'; -import { METRIC_TYPES } from '../../data/common'; +import { METRIC_TYPES } from '../../../data/common'; import { TSVB_METRIC_TYPES } from './enums'; import type { Metric, SanitizedFieldType } from './types'; diff --git a/src/plugins/vis_type_timeseries/common/constants.ts b/src/plugins/vis_types/timeseries/common/constants.ts similarity index 82% rename from src/plugins/vis_type_timeseries/common/constants.ts rename to src/plugins/vis_types/timeseries/common/constants.ts index bddbf095e895e..4f15cea7faad3 100644 --- a/src/plugins/vis_type_timeseries/common/constants.ts +++ b/src/plugins/vis_types/timeseries/common/constants.ts @@ -6,7 +6,10 @@ * Side Public License, v 1. */ -export const MAX_BUCKETS_SETTING = 'metrics:max_buckets'; +export const UI_SETTINGS = { + MAX_BUCKETS_SETTING: 'metrics:max_buckets', + ALLOW_STRING_INDICES: 'metrics:allowStringIndices', +}; export const INDEXES_SEPARATOR = ','; export const AUTO_INTERVAL = 'auto'; export const ROUTES = { diff --git a/src/plugins/vis_type_timeseries/common/empty_label.ts b/src/plugins/vis_types/timeseries/common/empty_label.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/empty_label.ts rename to src/plugins/vis_types/timeseries/common/empty_label.ts diff --git a/src/plugins/vis_type_timeseries/common/enums/index.ts b/src/plugins/vis_types/timeseries/common/enums/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/enums/index.ts rename to src/plugins/vis_types/timeseries/common/enums/index.ts diff --git a/src/plugins/vis_type_timeseries/common/enums/metric_types.ts b/src/plugins/vis_types/timeseries/common/enums/metric_types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/enums/metric_types.ts rename to src/plugins/vis_types/timeseries/common/enums/metric_types.ts diff --git a/src/plugins/vis_type_timeseries/common/enums/model_types.ts b/src/plugins/vis_types/timeseries/common/enums/model_types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/enums/model_types.ts rename to src/plugins/vis_types/timeseries/common/enums/model_types.ts diff --git a/src/plugins/vis_type_timeseries/common/enums/panel_types.ts b/src/plugins/vis_types/timeseries/common/enums/panel_types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/enums/panel_types.ts rename to src/plugins/vis_types/timeseries/common/enums/panel_types.ts diff --git a/src/plugins/vis_type_timeseries/common/enums/timerange_data_modes.ts b/src/plugins/vis_types/timeseries/common/enums/timerange_data_modes.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/enums/timerange_data_modes.ts rename to src/plugins/vis_types/timeseries/common/enums/timerange_data_modes.ts diff --git a/src/plugins/vis_type_timeseries/common/errors.ts b/src/plugins/vis_types/timeseries/common/errors.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/errors.ts rename to src/plugins/vis_types/timeseries/common/errors.ts diff --git a/src/plugins/vis_type_timeseries/common/fields_utils.test.ts b/src/plugins/vis_types/timeseries/common/fields_utils.test.ts similarity index 96% rename from src/plugins/vis_type_timeseries/common/fields_utils.test.ts rename to src/plugins/vis_types/timeseries/common/fields_utils.test.ts index f056c38b0c0c3..228dfbfd2db9d 100644 --- a/src/plugins/vis_type_timeseries/common/fields_utils.test.ts +++ b/src/plugins/vis_types/timeseries/common/fields_utils.test.ts @@ -7,7 +7,7 @@ */ import { toSanitizedFieldType } from './fields_utils'; -import type { FieldSpec } from '../../data/common'; +import type { FieldSpec } from '../../../data/common'; describe('fields_utils', () => { describe('toSanitizedFieldType', () => { diff --git a/src/plugins/vis_type_timeseries/common/fields_utils.ts b/src/plugins/vis_types/timeseries/common/fields_utils.ts similarity index 93% rename from src/plugins/vis_type_timeseries/common/fields_utils.ts rename to src/plugins/vis_types/timeseries/common/fields_utils.ts index 1af0340dfa525..d6987b9cdae9c 100644 --- a/src/plugins/vis_type_timeseries/common/fields_utils.ts +++ b/src/plugins/vis_types/timeseries/common/fields_utils.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { FieldSpec } from '../../data/common'; -import { isNestedField } from '../../data/common'; +import { FieldSpec } from '../../../data/common'; +import { isNestedField } from '../../../data/common'; import { FetchedIndexPattern, SanitizedFieldType } from './types'; import { FieldNotFoundError } from './errors'; diff --git a/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts b/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts similarity index 98% rename from src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts rename to src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts index cac607f7c0f90..e9f3be64079ac 100644 --- a/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts +++ b/src/plugins/vis_types/timeseries/common/index_patterns_utils.test.ts @@ -12,7 +12,7 @@ import { fetchIndexPattern, } from './index_patterns_utils'; import { Panel } from './types'; -import { IndexPattern, IndexPatternsService } from '../../data/common'; +import { IndexPattern, IndexPatternsService } from '../../../data/common'; describe('isStringTypeIndexPattern', () => { test('should returns true on string-based index', () => { diff --git a/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts b/src/plugins/vis_types/timeseries/common/index_patterns_utils.ts similarity index 97% rename from src/plugins/vis_type_timeseries/common/index_patterns_utils.ts rename to src/plugins/vis_types/timeseries/common/index_patterns_utils.ts index 1a8c277efbf7c..0a65e9e16d130 100644 --- a/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts +++ b/src/plugins/vis_types/timeseries/common/index_patterns_utils.ts @@ -8,7 +8,7 @@ import { uniq } from 'lodash'; import type { Panel, IndexPatternValue, FetchedIndexPattern } from '../common/types'; -import { IndexPatternsService } from '../../data/common'; +import { IndexPatternsService } from '../../../data/common'; export const isStringTypeIndexPattern = ( indexPatternValue: IndexPatternValue diff --git a/src/plugins/vis_type_timeseries/common/interval_regexp.test.ts b/src/plugins/vis_types/timeseries/common/interval_regexp.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/interval_regexp.test.ts rename to src/plugins/vis_types/timeseries/common/interval_regexp.test.ts diff --git a/src/plugins/vis_type_timeseries/common/interval_regexp.ts b/src/plugins/vis_types/timeseries/common/interval_regexp.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/interval_regexp.ts rename to src/plugins/vis_types/timeseries/common/interval_regexp.ts diff --git a/src/plugins/vis_type_timeseries/common/last_value_utils.test.ts b/src/plugins/vis_types/timeseries/common/last_value_utils.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/last_value_utils.test.ts rename to src/plugins/vis_types/timeseries/common/last_value_utils.test.ts diff --git a/src/plugins/vis_type_timeseries/common/last_value_utils.ts b/src/plugins/vis_types/timeseries/common/last_value_utils.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/last_value_utils.ts rename to src/plugins/vis_types/timeseries/common/last_value_utils.ts diff --git a/src/plugins/vis_type_timeseries/common/operators_utils.test.ts b/src/plugins/vis_types/timeseries/common/operators_utils.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/operators_utils.test.ts rename to src/plugins/vis_types/timeseries/common/operators_utils.test.ts diff --git a/src/plugins/vis_type_timeseries/common/operators_utils.ts b/src/plugins/vis_types/timeseries/common/operators_utils.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/operators_utils.ts rename to src/plugins/vis_types/timeseries/common/operators_utils.ts diff --git a/src/plugins/vis_type_timeseries/common/to_percentile_number.ts b/src/plugins/vis_types/timeseries/common/to_percentile_number.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/to_percentile_number.ts rename to src/plugins/vis_types/timeseries/common/to_percentile_number.ts diff --git a/src/plugins/vis_type_timeseries/common/types/color_rules.ts b/src/plugins/vis_types/timeseries/common/types/color_rules.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/types/color_rules.ts rename to src/plugins/vis_types/timeseries/common/types/color_rules.ts diff --git a/src/plugins/vis_type_timeseries/common/types/index.ts b/src/plugins/vis_types/timeseries/common/types/index.ts similarity index 95% rename from src/plugins/vis_type_timeseries/common/types/index.ts rename to src/plugins/vis_types/timeseries/common/types/index.ts index fb8e217fe704c..123b6723d8ccd 100644 --- a/src/plugins/vis_type_timeseries/common/types/index.ts +++ b/src/plugins/vis_types/timeseries/common/types/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Filter, IndexPattern, Query } from '../../../data/common'; +import { Filter, IndexPattern, Query } from '../../../../data/common'; import { Panel } from './panel_model'; export { Metric, Series, Panel, MetricType } from './panel_model'; diff --git a/src/plugins/vis_type_timeseries/common/types/panel_model.ts b/src/plugins/vis_types/timeseries/common/types/panel_model.ts similarity index 98% rename from src/plugins/vis_type_timeseries/common/types/panel_model.ts rename to src/plugins/vis_types/timeseries/common/types/panel_model.ts index 6fd2e727ade32..f71602fdf0443 100644 --- a/src/plugins/vis_type_timeseries/common/types/panel_model.ts +++ b/src/plugins/vis_types/timeseries/common/types/panel_model.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { METRIC_TYPES, Query } from '../../../data/common'; +import { METRIC_TYPES, Query } from '../../../../data/common'; import { PANEL_TYPES, TOOLTIP_MODES, TSVB_METRIC_TYPES } from '../enums'; import { IndexPatternValue, Annotation } from './index'; import { ColorRules, BackgroundColorRules, BarColorRules, GaugeColorRules } from './color_rules'; diff --git a/src/plugins/vis_type_timeseries/common/types/vis_data.ts b/src/plugins/vis_types/timeseries/common/types/vis_data.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/types/vis_data.ts rename to src/plugins/vis_types/timeseries/common/types/vis_data.ts diff --git a/src/plugins/vis_type_timeseries/common/ui_restrictions.ts b/src/plugins/vis_types/timeseries/common/ui_restrictions.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/ui_restrictions.ts rename to src/plugins/vis_types/timeseries/common/ui_restrictions.ts diff --git a/src/plugins/vis_type_timeseries/common/validate_interval.ts b/src/plugins/vis_types/timeseries/common/validate_interval.ts similarity index 93% rename from src/plugins/vis_type_timeseries/common/validate_interval.ts rename to src/plugins/vis_types/timeseries/common/validate_interval.ts index 7c7a4e7badfc0..78a2410f905c9 100644 --- a/src/plugins/vis_type_timeseries/common/validate_interval.ts +++ b/src/plugins/vis_types/timeseries/common/validate_interval.ts @@ -7,7 +7,7 @@ */ import { GTE_INTERVAL_RE } from './interval_regexp'; -import { parseInterval, TimeRangeBounds } from '../../data/common'; +import { parseInterval, TimeRangeBounds } from '../../../data/common'; import { ValidateIntervalError } from './errors'; export function validateInterval(bounds: TimeRangeBounds, interval: string, maxBuckets: number) { diff --git a/src/plugins/vis_type_timeseries/common/vis_data_utils.ts b/src/plugins/vis_types/timeseries/common/vis_data_utils.ts similarity index 100% rename from src/plugins/vis_type_timeseries/common/vis_data_utils.ts rename to src/plugins/vis_types/timeseries/common/vis_data_utils.ts diff --git a/src/plugins/vis_type_timeseries/jest.config.js b/src/plugins/vis_types/timeseries/jest.config.js similarity index 72% rename from src/plugins/vis_type_timeseries/jest.config.js rename to src/plugins/vis_types/timeseries/jest.config.js index 3d4333675f7d7..d6ddcaa3344b0 100644 --- a/src/plugins/vis_type_timeseries/jest.config.js +++ b/src/plugins/vis_types/timeseries/jest.config.js @@ -8,11 +8,11 @@ module.exports = { preset: '@kbn/test', - rootDir: '../../..', - roots: ['/src/plugins/vis_type_timeseries'], - coverageDirectory: '/target/kibana-coverage/jest/src/plugins/vis_type_timeseries', + rootDir: '../../../..', + roots: ['/src/plugins/vis_types/timeseries'], + coverageDirectory: '/target/kibana-coverage/jest/src/plugins/vis_types/timeseries', coverageReporters: ['text', 'html'], collectCoverageFrom: [ - '/src/plugins/vis_type_timeseries/{common,public,server}/**/*.{js,ts,tsx}', + '/src/plugins/vis_types/timeseries/{common,public,server}/**/*.{js,ts,tsx}', ], }; diff --git a/src/plugins/vis_type_timeseries/kibana.json b/src/plugins/vis_types/timeseries/kibana.json similarity index 100% rename from src/plugins/vis_type_timeseries/kibana.json rename to src/plugins/vis_types/timeseries/kibana.json diff --git a/src/plugins/vis_type_timeseries/public/application/_mixins.scss b/src/plugins/vis_types/timeseries/public/application/_mixins.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/_mixins.scss rename to src/plugins/vis_types/timeseries/public/application/_mixins.scss diff --git a/src/plugins/vis_type_timeseries/public/application/_tvb_editor.scss b/src/plugins/vis_types/timeseries/public/application/_tvb_editor.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/_tvb_editor.scss rename to src/plugins/vis_types/timeseries/public/application/_tvb_editor.scss diff --git a/src/plugins/vis_type_timeseries/public/application/_variables.scss b/src/plugins/vis_types/timeseries/public/application/_variables.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/_variables.scss rename to src/plugins/vis_types/timeseries/public/application/_variables.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_annotations_editor.scss b/src/plugins/vis_types/timeseries/public/application/components/_annotations_editor.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_annotations_editor.scss rename to src/plugins/vis_types/timeseries/public/application/components/_annotations_editor.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_color_picker.scss b/src/plugins/vis_types/timeseries/public/application/components/_color_picker.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_color_picker.scss rename to src/plugins/vis_types/timeseries/public/application/components/_color_picker.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_color_rules.scss b/src/plugins/vis_types/timeseries/public/application/components/_color_rules.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_color_rules.scss rename to src/plugins/vis_types/timeseries/public/application/components/_color_rules.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_error.scss b/src/plugins/vis_types/timeseries/public/application/components/_error.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_error.scss rename to src/plugins/vis_types/timeseries/public/application/components/_error.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_index.scss b/src/plugins/vis_types/timeseries/public/application/components/_index.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_index.scss rename to src/plugins/vis_types/timeseries/public/application/components/_index.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_markdown_editor.scss b/src/plugins/vis_types/timeseries/public/application/components/_markdown_editor.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_markdown_editor.scss rename to src/plugins/vis_types/timeseries/public/application/components/_markdown_editor.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_no_data.scss b/src/plugins/vis_types/timeseries/public/application/components/_no_data.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_no_data.scss rename to src/plugins/vis_types/timeseries/public/application/components/_no_data.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_series_editor.scss b/src/plugins/vis_types/timeseries/public/application/components/_series_editor.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_series_editor.scss rename to src/plugins/vis_types/timeseries/public/application/components/_series_editor.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_vis_editor.scss b/src/plugins/vis_types/timeseries/public/application/components/_vis_editor.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_vis_editor.scss rename to src/plugins/vis_types/timeseries/public/application/components/_vis_editor.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_vis_editor_visualization.scss b/src/plugins/vis_types/timeseries/public/application/components/_vis_editor_visualization.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_vis_editor_visualization.scss rename to src/plugins/vis_types/timeseries/public/application/components/_vis_editor_visualization.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_vis_picker.scss b/src/plugins/vis_types/timeseries/public/application/components/_vis_picker.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_vis_picker.scss rename to src/plugins/vis_types/timeseries/public/application/components/_vis_picker.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/_vis_with_splits.scss b/src/plugins/vis_types/timeseries/public/application/components/_vis_with_splits.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/_vis_with_splits.scss rename to src/plugins/vis_types/timeseries/public/application/components/_vis_with_splits.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/add_delete_buttons.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/add_delete_buttons.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.tsx b/src/plugins/vis_types/timeseries/public/application/components/add_delete_buttons.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.tsx rename to src/plugins/vis_types/timeseries/public/application/components/add_delete_buttons.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/_agg_row.scss b/src/plugins/vis_types/timeseries/public/application/components/aggs/_agg_row.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/_agg_row.scss rename to src/plugins/vis_types/timeseries/public/application/components/aggs/_agg_row.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/_index.scss b/src/plugins/vis_types/timeseries/public/application/components/aggs/_index.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/_index.scss rename to src/plugins/vis_types/timeseries/public/application/components/aggs/_index.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/agg.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/agg.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/agg_row.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/agg_row.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/agg_select.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/agg_select.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/agg_select.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/agg_select.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/aggs.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/aggs.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/aggs.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/aggs.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/calculation.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/calculation.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/cumulative_sum.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/cumulative_sum.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/derivative.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/derivative.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/field_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/field_select.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/field_select.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/field_select.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/filter_ratio.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/filter_ratio.js similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/filter_ratio.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/filter_ratio.js index 6a3f57e502796..59a372ccc1107 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/filter_ratio.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/filter_ratio.js @@ -24,7 +24,7 @@ import { EuiFormRow, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { getSupportedFieldsByMetricType } from '../lib/get_supported_fields_by_metric_type'; import { getDataStart } from '../../../services'; import { QueryBarWrapper } from '../query_bar_wrapper'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/filter_ratio.test.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/filter_ratio.test.js similarity index 97% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/filter_ratio.test.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/filter_ratio.test.js index 5648a8d3e7133..bd9ceeeb74028 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/filter_ratio.test.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/filter_ratio.test.js @@ -11,7 +11,7 @@ import { mountWithIntl } from '@kbn/test/jest'; import { FilterRatioAgg } from './filter_ratio'; import { FIELDS, METRIC, SERIES, PANEL } from '../../../test_utils'; import { EuiComboBox } from '@elastic/eui'; -import { dataPluginMock } from '../../../../../data/public/mocks'; +import { dataPluginMock } from '../../../../../../data/public/mocks'; import { setDataStart } from '../../../services'; jest.mock('../query_bar_wrapper', () => ({ diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/histogram_support.test.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/histogram_support.test.js similarity index 97% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/histogram_support.test.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/histogram_support.test.js index c4a49a393acd6..c131ba2ae804c 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/histogram_support.test.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/histogram_support.test.js @@ -12,7 +12,7 @@ import { Agg } from './agg'; import { FieldSelect } from './field_select'; import { FIELDS, METRIC, SERIES, PANEL } from '../../../test_utils'; import { setDataStart } from '../../../services'; -import { dataPluginMock } from '../../../../../data/public/mocks'; +import { dataPluginMock } from '../../../../../../data/public/mocks'; jest.mock('../query_bar_wrapper', () => ({ QueryBarWrapper: jest.fn(() => null), diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/invalid_agg.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/invalid_agg.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/invalid_agg.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/invalid_agg.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/math.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/math.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/math.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/math.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/metric_select.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/metric_select.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/metric_select.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/metric_select.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/moving_average.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/moving_average.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile.js similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile.js index 94adb37de156b..3e4159cdf42dc 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile.js @@ -23,7 +23,7 @@ import { EuiFormRow, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { Percentiles, newPercentile } from './percentile_ui'; import { PercentileHdr } from './percentile_hdr'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_hdr.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_hdr.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_hdr.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_hdr.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/index.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/index.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/index.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/index.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/multi_value_row.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/multi_value_row.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/multi_value_row.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/multi_value_row.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx index 7f9634ff15844..8b71dec15f17c 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx @@ -26,7 +26,7 @@ import { createNumberHandler } from '../../lib/create_number_handler'; import { AggRow } from '../agg_row'; import { PercentileRankValues } from './percentile_rank_values'; -import { KBN_FIELD_TYPES } from '../../../../../../data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../data/public'; import type { Metric, Panel, SanitizedFieldType, Series } from '../../../../../common/types'; import { TSVB_DEFAULT_COLOR } from '../../../../../common/constants'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_ui.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_ui.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_ui.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_ui.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/positive_only.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/positive_only.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_rate.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/positive_rate.js similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/positive_rate.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/positive_rate.js index 09d9f2f1a62f2..ea3f8542e8595 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_rate.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/positive_rate.js @@ -26,7 +26,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const UNIT_OPTIONS = [ { diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/serial_diff.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/serial_diff.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/series_agg.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/series_agg.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/series_agg.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/series_agg.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/static.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/static.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/static.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/static.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_agg.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/std_agg.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/std_agg.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/std_agg.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_deviation.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/std_deviation.js similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/std_deviation.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/std_deviation.js index d4caa8a94652f..728cda8720268 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_deviation.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/std_deviation.js @@ -25,7 +25,7 @@ import { EuiSpacer, } from '@elastic/eui'; import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; -import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const RESTRICT_FIELDS = KBN_FIELD_TYPES.NUMBER; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/std_sibling.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/std_sibling.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/top_hit.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/top_hit.js similarity index 99% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/top_hit.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/top_hit.js index ade64fc3db8c5..caf601dfab83e 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/top_hit.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/top_hit.js @@ -24,7 +24,7 @@ import { EuiFormRow, } from '@elastic/eui'; import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; -import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { PANEL_TYPES } from '../../../../common/enums'; import { getIndexPatternKey } from '../../../../common/index_patterns_utils'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/vars.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/vars.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/vars.js rename to src/plugins/vis_types/timeseries/public/application/components/aggs/vars.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/annotation_row.tsx b/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx similarity index 99% rename from src/plugins/vis_type_timeseries/public/application/components/annotation_row.tsx rename to src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx index 379c74d0d4bba..734bdfecac673 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/annotation_row.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx @@ -21,7 +21,7 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { getDataStart } from '../../services'; -import { KBN_FIELD_TYPES, Query } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES, Query } from '../../../../../../plugins/data/public'; import { AddDeleteButtons } from './add_delete_buttons'; import { ColorPicker } from './color_picker'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/annotations_editor.tsx b/src/plugins/vis_types/timeseries/public/application/components/annotations_editor.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/annotations_editor.tsx rename to src/plugins/vis_types/timeseries/public/application/components/annotations_editor.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/color_picker.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/color_picker.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/color_picker.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/color_picker.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/color_picker.tsx b/src/plugins/vis_types/timeseries/public/application/components/color_picker.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/color_picker.tsx rename to src/plugins/vis_types/timeseries/public/application/components/color_picker.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/color_rules.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/color_rules.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/color_rules.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/color_rules.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/color_rules.tsx b/src/plugins/vis_types/timeseries/public/application/components/color_rules.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/color_rules.tsx rename to src/plugins/vis_types/timeseries/public/application/components/color_rules.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/data_format_picker.tsx b/src/plugins/vis_types/timeseries/public/application/components/data_format_picker.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/data_format_picker.tsx rename to src/plugins/vis_types/timeseries/public/application/components/data_format_picker.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/error.js b/src/plugins/vis_types/timeseries/public/application/components/error.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/error.js rename to src/plugins/vis_types/timeseries/public/application/components/error.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/icon_select/__snapshots__/icon_select.test.js.snap b/src/plugins/vis_types/timeseries/public/application/components/icon_select/__snapshots__/icon_select.test.js.snap similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/icon_select/__snapshots__/icon_select.test.js.snap rename to src/plugins/vis_types/timeseries/public/application/components/icon_select/__snapshots__/icon_select.test.js.snap diff --git a/src/plugins/vis_type_timeseries/public/application/components/icon_select/icon_select.js b/src/plugins/vis_types/timeseries/public/application/components/icon_select/icon_select.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/icon_select/icon_select.js rename to src/plugins/vis_types/timeseries/public/application/components/icon_select/icon_select.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/icon_select/icon_select.test.js b/src/plugins/vis_types/timeseries/public/application/components/icon_select/icon_select.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/icon_select/icon_select.test.js rename to src/plugins/vis_types/timeseries/public/application/components/icon_select/icon_select.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js b/src/plugins/vis_types/timeseries/public/application/components/index_pattern.js similarity index 99% rename from src/plugins/vis_type_timeseries/public/application/components/index_pattern.js rename to src/plugins/vis_types/timeseries/public/application/components/index_pattern.js index 1810424625022..e5d09c745b522 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js +++ b/src/plugins/vis_types/timeseries/public/application/components/index_pattern.js @@ -26,7 +26,7 @@ import { createTextHandler } from './lib/create_text_handler'; import { IndexPatternSelect } from './lib/index_pattern_select'; import { YesNo } from './yes_no'; import { LastValueModePopover } from './last_value_mode_popover'; -import { KBN_FIELD_TYPES } from '../../../../data/public'; +import { KBN_FIELD_TYPES } from '../../../../../data/public'; import { FormValidationContext } from '../contexts/form_validation_context'; import { isGteInterval, validateReInterval, isAutoInterval } from './lib/get_interval'; import { i18n } from '@kbn/i18n'; @@ -36,7 +36,7 @@ import { AUTO_INTERVAL } from '../../../common/constants'; import { isTimerangeModeEnabled } from '../lib/check_ui_restrictions'; import { VisDataContext } from '../contexts/vis_data_context'; import { getDataStart, getUISettings } from '../../services'; -import { UI_SETTINGS } from '../../../../data/common'; +import { UI_SETTINGS } from '../../../../../data/common'; import { fetchIndexPattern } from '../../../common/index_patterns_utils'; const RESTRICT_FIELDS = [KBN_FIELD_TYPES.DATE]; diff --git a/src/plugins/vis_type_timeseries/public/application/components/last_value_mode_indicator.tsx b/src/plugins/vis_types/timeseries/public/application/components/last_value_mode_indicator.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/last_value_mode_indicator.tsx rename to src/plugins/vis_types/timeseries/public/application/components/last_value_mode_indicator.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/last_value_mode_popover.scss b/src/plugins/vis_types/timeseries/public/application/components/last_value_mode_popover.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/last_value_mode_popover.scss rename to src/plugins/vis_types/timeseries/public/application/components/last_value_mode_popover.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/last_value_mode_popover.tsx b/src/plugins/vis_types/timeseries/public/application/components/last_value_mode_popover.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/last_value_mode_popover.tsx rename to src/plugins/vis_types/timeseries/public/application/components/last_value_mode_popover.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/agg_to_component.js b/src/plugins/vis_types/timeseries/public/application/components/lib/agg_to_component.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/agg_to_component.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/agg_to_component.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/calculate_siblings.js b/src/plugins/vis_types/timeseries/public/application/components/lib/calculate_siblings.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/calculate_siblings.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/calculate_siblings.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/calculate_siblings.test.js b/src/plugins/vis_types/timeseries/public/application/components/lib/calculate_siblings.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/calculate_siblings.test.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/calculate_siblings.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/check_if_numeric_metric.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/check_if_numeric_metric.test.ts similarity index 97% rename from src/plugins/vis_type_timeseries/public/application/components/lib/check_if_numeric_metric.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/check_if_numeric_metric.test.ts index 17827275f86d8..eb6ea561fec84 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/check_if_numeric_metric.test.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/check_if_numeric_metric.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { METRIC_TYPES } from '../../../../../data/common'; +import { METRIC_TYPES } from '../../../../../../data/common'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; import { checkIfNumericMetric } from './check_if_numeric_metric'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/check_if_numeric_metric.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/check_if_numeric_metric.ts similarity index 94% rename from src/plugins/vis_type_timeseries/public/application/components/lib/check_if_numeric_metric.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/check_if_numeric_metric.ts index a70abaeac9f82..139c13d7ddbda 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/check_if_numeric_metric.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/check_if_numeric_metric.ts @@ -8,7 +8,7 @@ import { getIndexPatternKey } from '../../../../common/index_patterns_utils'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; -import { KBN_FIELD_TYPES } from '../../../../../data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../data/public'; import type { Metric, IndexPatternValue } from '../../../../common/types'; import type { VisFields } from '../../lib/fetch_fields'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/check_if_series_have_same_formatters.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/check_if_series_have_same_formatters.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/check_if_series_have_same_formatters.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/check_if_series_have_same_formatters.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/check_if_series_have_same_formatters.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/check_if_series_have_same_formatters.ts similarity index 94% rename from src/plugins/vis_type_timeseries/public/application/components/lib/check_if_series_have_same_formatters.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/check_if_series_have_same_formatters.ts index afa1216406ab0..44715d1262d05 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/check_if_series_have_same_formatters.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/check_if_series_have_same_formatters.ts @@ -9,7 +9,7 @@ import { last, isEqual } from 'lodash'; import { DATA_FORMATTERS } from '../../../../common/enums'; import type { Series } from '../../../../common/types'; -import type { FieldFormatMap } from '../../../../../data/common'; +import type { FieldFormatMap } from '../../../../../../data/common'; export const checkIfSeriesHaveSameFormatters = ( seriesModel: Series[], diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/collection_actions.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/collection_actions.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/collection_actions.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/collection_actions.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/collection_actions.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/collection_actions.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/collection_actions.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/collection_actions.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_datatable.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_datatable.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_vars.js b/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_vars.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_vars.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_vars.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_vars.test.js b/src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_vars.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_vars.test.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/convert_series_to_vars.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_change_handler.js b/src/plugins/vis_types/timeseries/public/application/components/lib/create_change_handler.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_change_handler.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_change_handler.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_field_formatter.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_field_formatter.test.ts similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_field_formatter.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_field_formatter.test.ts index c56c6820fff48..5a6b6a18f67e0 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/create_field_formatter.test.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/create_field_formatter.test.ts @@ -7,7 +7,7 @@ */ import { createFieldFormatter } from './create_field_formatter'; -import { getFieldFormatsRegistry } from '../../../../../data/public/test_utils'; +import { getFieldFormatsRegistry } from '../../../../../../data/public/test_utils'; import { setFieldFormats } from '../../../services'; import { FORMATS_UI_SETTINGS } from 'src/plugins/field_formats/common'; import type { CoreSetup } from 'kibana/public'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_field_formatter.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_field_formatter.ts similarity index 86% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_field_formatter.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_field_formatter.ts index 5cba549220f2c..a7606895e84aa 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/create_field_formatter.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/create_field_formatter.ts @@ -9,9 +9,9 @@ import { isNumber } from 'lodash'; import { getFieldFormats } from '../../../services'; import { isEmptyValue, DISPLAY_EMPTY_VALUE } from '../../../../common/last_value_utils'; -import { FIELD_FORMAT_IDS } from '../../../../../field_formats/common'; -import type { FieldFormatMap } from '../../../../../data/common'; -import type { FieldFormatsContentType } from '../../../../../field_formats/common'; +import { FIELD_FORMAT_IDS } from '../../../../../../field_formats/common'; +import type { FieldFormatMap } from '../../../../../../data/common'; +import type { FieldFormatsContentType } from '../../../../../../field_formats/common'; const DEFAULT_FIELD_FORMAT = { id: 'number' }; diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_interval_based_formatter.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_interval_based_formatter.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_interval_based_formatter.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_interval_based_formatter.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_number_handler.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_number_handler.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_number_handler.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_number_handler.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_number_handler.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_number_handler.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_number_handler.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_number_handler.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_select_handler.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_select_handler.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_select_handler.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_select_handler.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_select_handler.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_select_handler.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_select_handler.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_select_handler.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_text_handler.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_text_handler.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_text_handler.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_text_handler.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/create_text_handler.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/create_text_handler.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/create_text_handler.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/create_text_handler.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/durations.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/durations.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/durations.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/durations.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/durations.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/durations.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/durations.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/durations.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_axis_label_string.js b/src/plugins/vis_types/timeseries/public/application/components/lib/get_axis_label_string.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_axis_label_string.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_axis_label_string.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_axis_label_string.test.js b/src/plugins/vis_types/timeseries/public/application/components/lib/get_axis_label_string.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_axis_label_string.test.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_axis_label_string.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_click_filter_data.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/get_click_filter_data.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_click_filter_data.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_click_filter_data.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_click_filter_data.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/get_click_filter_data.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_click_filter_data.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_click_filter_data.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_default_query_language.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/get_default_query_language.ts similarity index 89% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_default_query_language.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_default_query_language.ts index e6f65e71043c7..3cb7ee0388f94 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/get_default_query_language.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/get_default_query_language.ts @@ -7,7 +7,7 @@ */ import { getUISettings } from '../../../services'; -import { UI_SETTINGS } from '../../../../../data/public'; +import { UI_SETTINGS } from '../../../../../../data/public'; export function getDefaultQueryLanguage() { return getUISettings().get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE); diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_display_name.js b/src/plugins/vis_types/timeseries/public/application/components/lib/get_display_name.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_display_name.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_display_name.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_formatter_type.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/get_formatter_type.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_formatter_type.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_formatter_type.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_formatter_type.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/get_formatter_type.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_formatter_type.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_formatter_type.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_interval.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/get_interval.ts similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_interval.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_interval.ts index 4b232af299a19..ea86ef6dc7ae9 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/get_interval.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/get_interval.ts @@ -9,7 +9,7 @@ import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; -import { search } from '../../../../../../plugins/data/public'; +import { search } from '../../../../../../../plugins/data/public'; import { GTE_INTERVAL_RE } from '../../../../common/interval_regexp'; import { AUTO_INTERVAL } from '../../../../common/constants'; import { isVisTableData } from '../../../../common/vis_data_utils'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_metrics_field.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/get_metrics_field.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_metrics_field.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_metrics_field.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_metrics_field.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/get_metrics_field.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_metrics_field.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_metrics_field.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_supported_fields_by_metric_type.js b/src/plugins/vis_types/timeseries/public/application/components/lib/get_supported_fields_by_metric_type.js similarity index 87% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_supported_fields_by_metric_type.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_supported_fields_by_metric_type.js index 7aa40d48994b8..2909e7804b1bf 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/get_supported_fields_by_metric_type.js +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/get_supported_fields_by_metric_type.js @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; -import { METRIC_TYPES } from '../../../../../data/common'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { METRIC_TYPES } from '../../../../../../data/common'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; export function getSupportedFieldsByMetricType(type) { diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/get_supported_fields_by_metric_type.test.js b/src/plugins/vis_types/timeseries/public/application/components/lib/get_supported_fields_by_metric_type.test.js similarity index 95% rename from src/plugins/vis_type_timeseries/public/application/components/lib/get_supported_fields_by_metric_type.test.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/get_supported_fields_by_metric_type.test.js index c009146abb7bd..878b4f7655f3e 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/get_supported_fields_by_metric_type.test.js +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/get_supported_fields_by_metric_type.test.js @@ -7,7 +7,7 @@ */ import { getSupportedFieldsByMetricType } from './get_supported_fields_by_metric_type'; -import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; describe('getSupportedFieldsByMetricType', () => { const shouldHaveHistogramAndNumbers = (type) => diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx similarity index 97% rename from src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx rename to src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx index 7111a63244c7f..ad60aee290640 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/combo_box_select.tsx @@ -15,7 +15,7 @@ import { SwitchModePopover } from './switch_mode_popover'; import type { SelectIndexComponentProps } from './types'; import type { IndexPatternValue } from '../../../../../common/types'; -import type { IndexPatternsService } from '../../../../../../data/public'; +import type { IndexPatternsService } from '../../../../../../../data/public'; /** @internal **/ type IdsWithTitle = UnwrapPromise>; diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/field_text_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/field_text_select.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/field_text_select.tsx rename to src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/field_text_select.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx rename to src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx index 927b3c608c16c..1029ac67cc43c 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx @@ -19,7 +19,7 @@ import { ComboBoxSelect } from './combo_box_select'; import type { IndexPatternValue, FetchedIndexPattern } from '../../../../../common/types'; import { USE_KIBANA_INDEXES_KEY } from '../../../../../common/constants'; -import { IndexPattern } from '../../../../../../data/common'; +import { IndexPattern } from '../../../../../../../data/common'; export interface IndexPatternSelectProps { indexPatternName: string; diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx similarity index 56% rename from src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx rename to src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx index 5f5506ce4a332..43ef091da251d 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/switch_mode_popover.tsx @@ -17,9 +17,17 @@ import { EuiSpacer, EuiSwitch, EuiText, + EuiLink, } from '@elastic/eui'; import type { PopoverProps } from './types'; +import { getCoreStart, getUISettings } from '../../../../services'; +import { UI_SETTINGS } from '../../../../../common/constants'; + +const allowStringIndicesMessage = i18n.translate( + 'visTypeTimeseries.indexPatternSelect.switchModePopover.allowStringIndices', + { defaultMessage: 'Allow string indices in TSVB' } +); export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverProps) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -30,6 +38,39 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro onModeChange(!useKibanaIndices); }, [onModeChange, useKibanaIndices]); + const { application } = getCoreStart(); + const canEditAdvancedSettings = application.capabilities.advancedSettings.save; + + const handleAllowStringIndicesLinkClick = useCallback( + () => + application.navigateToApp('management', { + path: `/kibana/settings?query=${UI_SETTINGS.ALLOW_STRING_INDICES}`, + }), + [application] + ); + + const stringIndicesAllowed = getUISettings().get(UI_SETTINGS.ALLOW_STRING_INDICES); + const isSwitchDisabled = useKibanaIndices && !stringIndicesAllowed; + + let allowStringIndicesLabel; + if (!stringIndicesAllowed) { + allowStringIndicesLabel = ( + + {allowStringIndicesMessage} + + ) : ( + {allowStringIndicesMessage} + ), + }} + /> + ); + } + return ( } isOpen={isPopoverOpen} closePopover={closePopover} style={{ height: 'auto' }} + initialFocus={false} > -
+
{i18n.translate('visTypeTimeseries.indexPatternSelect.switchModePopover.title', { defaultMessage: 'Index pattern selection mode', @@ -59,7 +104,10 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro @@ -68,10 +116,11 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro label={i18n.translate( 'visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices', { - defaultMessage: 'Use only Kibana index patterns', + defaultMessage: 'Use only index patterns', } )} onChange={switchMode} + disabled={isSwitchDisabled} data-test-subj="switchIndexPatternSelectionMode" />
diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts similarity index 93% rename from src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts index 18288f75d4c90..244e95e8db9dd 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/types.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/types.ts @@ -7,7 +7,7 @@ */ import type { Assign } from '@kbn/utility-types'; import type { FetchedIndexPattern, IndexPatternValue } from '../../../../../common/types'; -import type { IndexPattern } from '../../../../../../data/common'; +import type { IndexPattern } from '../../../../../../../data/common'; /** @internal **/ export interface SelectIndexComponentProps { diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/label_date_formatter.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/label_date_formatter.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/label_date_formatter.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/label_date_formatter.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/label_date_formatter.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/label_date_formatter.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/label_date_formatter.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/label_date_formatter.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/new_metric_agg_fn.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/new_metric_agg_fn.ts similarity index 89% rename from src/plugins/vis_type_timeseries/public/application/components/lib/new_metric_agg_fn.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/new_metric_agg_fn.ts index 28dd4c81510fc..9c7cc1225c5ac 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/new_metric_agg_fn.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/new_metric_agg_fn.ts @@ -7,7 +7,7 @@ */ import uuid from 'uuid'; -import { METRIC_TYPES } from '../../../../../data/common'; +import { METRIC_TYPES } from '../../../../../../data/common'; import type { Metric } from '../../../../common/types'; export const newMetricAggFn = (): Metric => { diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/new_series_fn.js b/src/plugins/vis_types/timeseries/public/application/components/lib/new_series_fn.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/new_series_fn.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/new_series_fn.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/re_id_series.js b/src/plugins/vis_types/timeseries/public/application/components/lib/re_id_series.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/re_id_series.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/re_id_series.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/re_id_series.test.js b/src/plugins/vis_types/timeseries/public/application/components/lib/re_id_series.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/re_id_series.test.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/re_id_series.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/reorder.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/reorder.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/reorder.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/reorder.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.test.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/replace_vars.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.test.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/replace_vars.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/replace_vars.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/replace_vars.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/series_change_handler.js b/src/plugins/vis_types/timeseries/public/application/components/lib/series_change_handler.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/series_change_handler.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/series_change_handler.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/stacked.js b/src/plugins/vis_types/timeseries/public/application/components/lib/stacked.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/stacked.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/stacked.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/tick_formatter.js b/src/plugins/vis_types/timeseries/public/application/components/lib/tick_formatter.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/tick_formatter.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/tick_formatter.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/tick_formatter.test.js b/src/plugins/vis_types/timeseries/public/application/components/lib/tick_formatter.test.js similarity index 93% rename from src/plugins/vis_type_timeseries/public/application/components/lib/tick_formatter.test.js rename to src/plugins/vis_types/timeseries/public/application/components/lib/tick_formatter.test.js index 9b9beae67e44f..8053c066114a3 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/tick_formatter.test.js +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/tick_formatter.test.js @@ -7,10 +7,10 @@ */ import { createTickFormatter } from './tick_formatter'; -import { getFieldFormatsRegistry } from '../../../../../data/public/test_utils'; +import { getFieldFormatsRegistry } from '../../../../../../data/public/test_utils'; import { setFieldFormats } from '../../../services'; -import { UI_SETTINGS } from '../../../../../data/public'; -import { FORMATS_UI_SETTINGS } from '../../../../../field_formats/common'; +import { UI_SETTINGS } from '../../../../../../data/public'; +import { FORMATS_UI_SETTINGS } from '../../../../../../field_formats/common'; const mockUiSettings = { get: (item) => { diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/types.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/lib/types.ts rename to src/plugins/vis_types/timeseries/public/application/components/lib/types.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/markdown_editor.js b/src/plugins/vis_types/timeseries/public/application/components/markdown_editor.js similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/markdown_editor.js rename to src/plugins/vis_types/timeseries/public/application/components/markdown_editor.js index 046b1c5799836..adee297fe0119 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/markdown_editor.js +++ b/src/plugins/vis_types/timeseries/public/application/components/markdown_editor.js @@ -15,7 +15,7 @@ import React, { Component } from 'react'; import { createTickFormatter } from './lib/tick_formatter'; import { convertSeriesToVars } from './lib/convert_series_to_vars'; import _ from 'lodash'; -import { CodeEditor, MarkdownLang } from '../../../../kibana_react/public'; +import { CodeEditor, MarkdownLang } from '../../../../../kibana_react/public'; import { EuiText, EuiCodeBlock, EuiSpacer, EuiTitle } from '@elastic/eui'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/palette_picker.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/palette_picker.test.tsx similarity index 97% rename from src/plugins/vis_type_timeseries/public/application/components/palette_picker.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/palette_picker.test.tsx index ae7fa5c59c73d..81b33943f8b04 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/palette_picker.test.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/palette_picker.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test/jest'; import { ReactWrapper } from 'enzyme'; import { PalettePicker, PalettePickerProps } from './palette_picker'; -import { chartPluginMock } from '../../../../charts/public/mocks'; +import { chartPluginMock } from '../../../../../charts/public/mocks'; import { EuiColorPalettePicker } from '@elastic/eui'; import { PALETTES } from '../../../common/enums'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx b/src/plugins/vis_types/timeseries/public/application/components/palette_picker.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx rename to src/plugins/vis_types/timeseries/public/application/components/palette_picker.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/_index.scss b/src/plugins/vis_types/timeseries/public/application/components/panel_config/_index.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/_index.scss rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/_index.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/_panel_config.scss b/src/plugins/vis_types/timeseries/public/application/components/panel_config/_panel_config.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/_panel_config.scss rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/_panel_config.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/gauge.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/gauge.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/gauge.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/gauge.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/gauge.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/gauge.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/gauge.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/gauge.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/index.ts b/src/plugins/vis_types/timeseries/public/application/components/panel_config/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/index.ts rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/index.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/markdown.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/markdown.tsx similarity index 99% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/markdown.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/markdown.tsx index 7f82f95d250ea..b099209af4348 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/panel_config/markdown.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/panel_config/markdown.tsx @@ -42,7 +42,7 @@ import { getDefaultQueryLanguage } from '../lib/get_default_query_language'; import { VisDataContext } from '../../contexts/vis_data_context'; import { PanelConfigProps, PANEL_CONFIG_TABS } from './types'; import { TimeseriesVisParams } from '../../../types'; -import { CodeEditor, CssLang } from '../../../../../kibana_react/public'; +import { CodeEditor, CssLang } from '../../../../../../kibana_react/public'; const lessC = less(window, { env: 'production' }); diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/metric.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/metric.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/metric.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/metric.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/panel_config.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/panel_config.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/panel_config.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/panel_config.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/table.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/table.tsx similarity index 99% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/table.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/table.tsx index 38cbd57b0b517..ecbd9767f34a6 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/panel_config/table.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/panel_config/table.tsx @@ -42,7 +42,7 @@ import { BUCKET_TYPES } from '../../../../common/enums'; import { PanelConfigProps, PANEL_CONFIG_TABS } from './types'; import { TimeseriesVisParams } from '../../../types'; import { getIndexPatternKey } from '../../../../common/index_patterns_utils'; -import { KBN_FIELD_TYPES } from '../../../../../data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../data/public'; export class TablePanelConfig extends Component< PanelConfigProps, diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/timeseries.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/timeseries.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/timeseries.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/timeseries.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/timeseries.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/timeseries.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/timeseries.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/timeseries.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/top_n.tsx b/src/plugins/vis_types/timeseries/public/application/components/panel_config/top_n.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/top_n.tsx rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/top_n.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/types.ts b/src/plugins/vis_types/timeseries/public/application/components/panel_config/types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/panel_config/types.ts rename to src/plugins/vis_types/timeseries/public/application/components/panel_config/types.ts diff --git a/src/plugins/vis_type_timeseries/public/application/components/query_bar_wrapper.tsx b/src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/query_bar_wrapper.tsx rename to src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx index d3b249f54fe34..e0c66ea8d70a7 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/query_bar_wrapper.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/query_bar_wrapper.tsx @@ -11,7 +11,7 @@ import React, { useContext, useEffect, useState } from 'react'; import { CoreStartContext } from '../contexts/query_input_bar_context'; import type { IndexPatternValue } from '../../../common/types'; -import { QueryStringInput, QueryStringInputProps } from '../../../../../plugins/data/public'; +import { QueryStringInput, QueryStringInputProps } from '../../../../../../plugins/data/public'; import { getDataStart } from '../../services'; import { fetchIndexPattern, isStringTypeIndexPattern } from '../../../common/index_patterns_utils'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/series.js b/src/plugins/vis_types/timeseries/public/application/components/series.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/series.js rename to src/plugins/vis_types/timeseries/public/application/components/series.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/series_config.js b/src/plugins/vis_types/timeseries/public/application/components/series_config.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/series_config.js rename to src/plugins/vis_types/timeseries/public/application/components/series_config.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/series_config_query_bar_with_ignore_global_filter.js b/src/plugins/vis_types/timeseries/public/application/components/series_config_query_bar_with_ignore_global_filter.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/series_config_query_bar_with_ignore_global_filter.js rename to src/plugins/vis_types/timeseries/public/application/components/series_config_query_bar_with_ignore_global_filter.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/series_drag_handler.tsx b/src/plugins/vis_types/timeseries/public/application/components/series_drag_handler.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/series_drag_handler.tsx rename to src/plugins/vis_types/timeseries/public/application/components/series_drag_handler.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/series_editor.js b/src/plugins/vis_types/timeseries/public/application/components/series_editor.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/series_editor.js rename to src/plugins/vis_types/timeseries/public/application/components/series_editor.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/split.js b/src/plugins/vis_types/timeseries/public/application/components/split.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/split.js rename to src/plugins/vis_types/timeseries/public/application/components/split.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/__snapshots__/terms.test.js.snap b/src/plugins/vis_types/timeseries/public/application/components/splits/__snapshots__/terms.test.js.snap similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/splits/__snapshots__/terms.test.js.snap rename to src/plugins/vis_types/timeseries/public/application/components/splits/__snapshots__/terms.test.js.snap diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/everything.js b/src/plugins/vis_types/timeseries/public/application/components/splits/everything.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/splits/everything.js rename to src/plugins/vis_types/timeseries/public/application/components/splits/everything.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/filter.js b/src/plugins/vis_types/timeseries/public/application/components/splits/filter.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/splits/filter.js rename to src/plugins/vis_types/timeseries/public/application/components/splits/filter.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/filter_items.js b/src/plugins/vis_types/timeseries/public/application/components/splits/filter_items.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/splits/filter_items.js rename to src/plugins/vis_types/timeseries/public/application/components/splits/filter_items.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/filters.js b/src/plugins/vis_types/timeseries/public/application/components/splits/filters.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/splits/filters.js rename to src/plugins/vis_types/timeseries/public/application/components/splits/filters.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/group_by_select.js b/src/plugins/vis_types/timeseries/public/application/components/splits/group_by_select.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/splits/group_by_select.js rename to src/plugins/vis_types/timeseries/public/application/components/splits/group_by_select.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/terms.js b/src/plugins/vis_types/timeseries/public/application/components/splits/terms.js similarity index 99% rename from src/plugins/vis_type_timeseries/public/application/components/splits/terms.js rename to src/plugins/vis_types/timeseries/public/application/components/splits/terms.js index a668e5b727b48..b32af037533f7 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/splits/terms.js +++ b/src/plugins/vis_types/timeseries/public/application/components/splits/terms.js @@ -25,7 +25,7 @@ import { EuiFieldText, } from '@elastic/eui'; import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; -import { KBN_FIELD_TYPES } from '../../../../../data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../data/public'; import { STACKED_OPTIONS } from '../../visualizations/constants'; import { getIndexPatternKey } from '../../../../common/index_patterns_utils'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/terms.test.js b/src/plugins/vis_types/timeseries/public/application/components/splits/terms.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/splits/terms.test.js rename to src/plugins/vis_types/timeseries/public/application/components/splits/terms.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/unsupported_split.js b/src/plugins/vis_types/timeseries/public/application/components/splits/unsupported_split.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/splits/unsupported_split.js rename to src/plugins/vis_types/timeseries/public/application/components/splits/unsupported_split.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/svg/bomb_icon.js b/src/plugins/vis_types/timeseries/public/application/components/svg/bomb_icon.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/svg/bomb_icon.js rename to src/plugins/vis_types/timeseries/public/application/components/svg/bomb_icon.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/svg/fire_icon.js b/src/plugins/vis_types/timeseries/public/application/components/svg/fire_icon.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/svg/fire_icon.js rename to src/plugins/vis_types/timeseries/public/application/components/svg/fire_icon.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.scss b/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.scss rename to src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.tsx b/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.tsx rename to src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx index b1722d4098587..a73f9c6a5e092 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/timeseries_visualization.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/timeseries_visualization.tsx @@ -27,7 +27,7 @@ import { LastValueModeIndicator } from './last_value_mode_indicator'; import { getInterval } from './lib/get_interval'; import { AUTO_INTERVAL } from '../../../common/constants'; import { TIME_RANGE_DATA_MODES, PANEL_TYPES } from '../../../common/enums'; -import type { IndexPattern } from '../../../../data/common'; +import type { IndexPattern } from '../../../../../data/common'; interface TimeseriesVisualizationProps { className?: string; diff --git a/src/plugins/vis_type_timeseries/public/application/components/use_index_patter_mode_callout.tsx b/src/plugins/vis_types/timeseries/public/application/components/use_index_patter_mode_callout.tsx similarity index 95% rename from src/plugins/vis_type_timeseries/public/application/components/use_index_patter_mode_callout.tsx rename to src/plugins/vis_types/timeseries/public/application/components/use_index_patter_mode_callout.tsx index 6191df2ecce5b..9684b7b7ff356 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/use_index_patter_mode_callout.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/use_index_patter_mode_callout.tsx @@ -43,7 +43,7 @@ export const UseIndexPatternModeCallout = () => {

diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_editor.tsx b/src/plugins/vis_types/timeseries/public/application/components/vis_editor.tsx similarity index 95% rename from src/plugins/vis_type_timeseries/public/application/components/vis_editor.tsx rename to src/plugins/vis_types/timeseries/public/application/components/vis_editor.tsx index 5e4ff436ff1e6..9e46427e33c2e 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_editor.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_editor.tsx @@ -15,11 +15,11 @@ import type { IUiSettingsClient } from 'kibana/public'; import type { Vis, VisualizeEmbeddableContract, -} from '../../../../../plugins/visualizations/public'; -import { KibanaContextProvider } from '../../../../../plugins/kibana_react/public'; -import { Storage } from '../../../../../plugins/kibana_utils/public'; +} from '../../../../../../plugins/visualizations/public'; +import { KibanaContextProvider } from '../../../../../../plugins/kibana_react/public'; +import { Storage } from '../../../../../../plugins/kibana_utils/public'; -import type { TimeRange } from '../../../../../plugins/data/public'; +import type { TimeRange } from '../../../../../../plugins/data/public'; import type { IndexPatternValue, TimeseriesVisData } from '../../../common/types'; // @ts-expect-error @@ -32,7 +32,7 @@ import { fetchFields, VisFields } from '../lib/fetch_fields'; import { getDataStart, getCoreStart } from '../../services'; import type { TimeseriesVisParams } from '../../types'; import { UseIndexPatternModeCallout } from './use_index_patter_mode_callout'; -import type { EditorRenderProps } from '../../../../visualize/public'; +import type { EditorRenderProps } from '../../../../../visualize/public'; const VIS_STATE_DEBOUNCE_DELAY = 200; const APP_NAME = 'VisEditor'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_editor_lazy.tsx b/src/plugins/vis_types/timeseries/public/application/components/vis_editor_lazy.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_editor_lazy.tsx rename to src/plugins/vis_types/timeseries/public/application/components/vis_editor_lazy.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_editor_visualization.js b/src/plugins/vis_types/timeseries/public/application/components/vis_editor_visualization.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_editor_visualization.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_editor_visualization.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_picker.tsx b/src/plugins/vis_types/timeseries/public/application/components/vis_picker.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_picker.tsx rename to src/plugins/vis_types/timeseries/public/application/components/vis_picker.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/_index.scss b/src/plugins/vis_types/timeseries/public/application/components/vis_types/_index.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/_index.scss rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/_index.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/_vis_types.scss b/src/plugins/vis_types/timeseries/public/application/components/vis_types/_vis_types.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/_vis_types.scss rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/_vis_types.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/gauge/series.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/gauge/series.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/gauge/series.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/gauge/series.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/gauge/series.test.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/gauge/series.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/gauge/series.test.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/gauge/series.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/gauge/vis.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/gauge/vis.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/gauge/vis.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/gauge/vis.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/index.ts b/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts similarity index 96% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/index.ts rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts index b2e40940b8001..653b2985ed1ae 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_types/index.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/index.ts @@ -14,7 +14,7 @@ import { PaletteRegistry } from 'src/plugins/charts/public'; import { TimeseriesVisParams } from '../../../types'; import type { TimeseriesVisData, PanelData } from '../../../../common/types'; -import type { FieldFormatMap } from '../../../../../data/common'; +import type { FieldFormatMap } from '../../../../../../data/common'; /** * Lazy load each visualization type, since the only one is presented on the screen at the same time. diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/markdown/_markdown.scss b/src/plugins/vis_types/timeseries/public/application/components/vis_types/markdown/_markdown.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/markdown/_markdown.scss rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/markdown/_markdown.scss diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/markdown/series.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/markdown/series.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/markdown/series.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/markdown/series.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/markdown/vis.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/markdown/vis.js similarity index 97% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/markdown/vis.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/markdown/vis.js index fc7019bd38293..49fdbcd98501c 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_types/markdown/vis.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/markdown/vis.js @@ -11,7 +11,7 @@ import React from 'react'; import classNames from 'classnames'; import uuid from 'uuid'; import { get } from 'lodash'; -import { Markdown } from '../../../../../../../plugins/kibana_react/public'; +import { Markdown } from '../../../../../../../../plugins/kibana_react/public'; import { ErrorComponent } from '../../error'; import { replaceVars } from '../../lib/replace_vars'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/metric/series.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/metric/series.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/metric/series.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/metric/series.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/metric/series.test.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/metric/series.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/metric/series.test.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/metric/series.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/metric/vis.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/metric/vis.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/metric/vis.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/metric/vis.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/config.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/config.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/table/config.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/table/config.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/is_sortable.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/is_sortable.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/table/is_sortable.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/table/is_sortable.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/series.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/series.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/table/series.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/table/series.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/vis.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/vis.js similarity index 98% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/table/vis.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/table/vis.js index 21d7de9f1d880..7b1db4b362647 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/vis.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/vis.js @@ -10,14 +10,14 @@ import _, { isArray, last, get } from 'lodash'; import React, { Component } from 'react'; import { parse as parseUrl } from 'url'; import PropTypes from 'prop-types'; -import { RedirectAppLinks } from '../../../../../../kibana_react/public'; +import { RedirectAppLinks } from '../../../../../../../kibana_react/public'; import { getMetricsField } from '../../lib/get_metrics_field'; import { createTickFormatter } from '../../lib/tick_formatter'; import { createFieldFormatter } from '../../lib/create_field_formatter'; import { isSortable } from './is_sortable'; import { EuiToolTip, EuiIcon } from '@elastic/eui'; import { replaceVars } from '../../lib/replace_vars'; -import { FIELD_FORMAT_IDS } from '../../../../../../../plugins/field_formats/common'; +import { FIELD_FORMAT_IDS } from '../../../../../../../../plugins/field_formats/common'; import { FormattedMessage } from '@kbn/i18n/react'; import { getFieldFormats, getCoreStart } from '../../../../services'; import { DATA_FORMATTERS } from '../../../../../common/enums'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/config.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/config.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/config.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/config.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/series.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/series.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/series.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/series.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/vis.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.js similarity index 96% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/vis.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.js index fed295fef9d30..b4fe39c522de7 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/vis.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.js @@ -18,7 +18,7 @@ import { createTickFormatter } from '../../lib/tick_formatter'; import { createFieldFormatter } from '../../lib/create_field_formatter'; import { checkIfSeriesHaveSameFormatters } from '../../lib/check_if_series_have_same_formatters'; import { TimeSeries } from '../../../visualizations/views/timeseries'; -import { MarkdownSimple } from '../../../../../../../plugins/kibana_react/public'; +import { MarkdownSimple } from '../../../../../../../../plugins/kibana_react/public'; import { replaceVars } from '../../lib/replace_vars'; import { getInterval } from '../../lib/get_interval'; import { createIntervalBasedFormatter } from '../../lib/create_interval_based_formatter'; @@ -38,6 +38,8 @@ class TimeseriesVisualization extends Component { scaledDataFormat = this.props.getConfig('dateFormat:scaled'); dateFormat = this.props.getConfig('dateFormat'); + yAxisIdGenerator = htmlIdGenerator('yaxis'); + xAxisFormatter = (interval) => { const formatter = createIntervalBasedFormatter( interval, @@ -165,8 +167,7 @@ class TimeseriesVisualization extends Component { } = this.props; const series = get(visData, `${model.id}.series`, []); const interval = getInterval(visData, model); - const yAxisIdGenerator = htmlIdGenerator('yaxis'); - const mainAxisGroupId = yAxisIdGenerator('main_group'); + const mainAxisGroupId = this.yAxisIdGenerator('main_group'); const seriesModel = model.series.filter((s) => !s.hidden).map((s) => cloneDeep(s)); @@ -226,7 +227,7 @@ class TimeseriesVisualization extends Component { TimeseriesVisualization.addYAxis(yAxis, { domain, groupId, - id: yAxisIdGenerator(seriesGroup.id), + id: this.yAxisIdGenerator(seriesGroup.id), position: seriesGroup.axis_position, hide: isStackedWithinSeries, tickFormatter: @@ -241,7 +242,7 @@ class TimeseriesVisualization extends Component { TimeseriesVisualization.addYAxis(yAxis, { tickFormatter, - id: yAxisIdGenerator('main'), + id: this.yAxisIdGenerator('main'), groupId: mainAxisGroupId, position: model.axis_position, domain: mainAxisDomain, diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/vis.test.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.test.js similarity index 96% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/vis.test.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.test.js index d6e7484e903bf..cf4c327df3d77 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/vis.test.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/timeseries/vis.test.js @@ -12,11 +12,11 @@ import { TimeSeries } from '../../../visualizations/views/timeseries'; import TimeseriesVisualization from './vis'; import { setFieldFormats } from '../../../../services'; import { createFieldFormatter } from '../../lib/create_field_formatter'; -import { FORMATS_UI_SETTINGS } from '../../../../../../field_formats/common'; -import { METRIC_TYPES } from '../../../../../../data/common'; -import { getFieldFormatsRegistry } from '../../../../../../data/public/test_utils'; +import { FORMATS_UI_SETTINGS } from '../../../../../../../field_formats/common'; +import { METRIC_TYPES } from '../../../../../../../data/common'; +import { getFieldFormatsRegistry } from '../../../../../../../data/public/test_utils'; -jest.mock('../../../../../../data/public/services', () => ({ +jest.mock('../../../../../../../data/public/services', () => ({ getUiSettings: () => ({ get: jest.fn() }), })); diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/top_n/series.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/top_n/series.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/top_n/series.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/top_n/series.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/top_n/vis.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/top_n/vis.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_types/top_n/vis.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_types/top_n/vis.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_with_splits.js b/src/plugins/vis_types/timeseries/public/application/components/vis_with_splits.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/vis_with_splits.js rename to src/plugins/vis_types/timeseries/public/application/components/vis_with_splits.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/yes_no.test.tsx b/src/plugins/vis_types/timeseries/public/application/components/yes_no.test.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/yes_no.test.tsx rename to src/plugins/vis_types/timeseries/public/application/components/yes_no.test.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/components/yes_no.tsx b/src/plugins/vis_types/timeseries/public/application/components/yes_no.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/components/yes_no.tsx rename to src/plugins/vis_types/timeseries/public/application/components/yes_no.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/contexts/form_validation_context.ts b/src/plugins/vis_types/timeseries/public/application/contexts/form_validation_context.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/contexts/form_validation_context.ts rename to src/plugins/vis_types/timeseries/public/application/contexts/form_validation_context.ts diff --git a/src/plugins/vis_type_timeseries/public/application/contexts/panel_model_context.ts b/src/plugins/vis_types/timeseries/public/application/contexts/panel_model_context.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/contexts/panel_model_context.ts rename to src/plugins/vis_types/timeseries/public/application/contexts/panel_model_context.ts diff --git a/src/plugins/vis_type_timeseries/public/application/contexts/query_input_bar_context.ts b/src/plugins/vis_types/timeseries/public/application/contexts/query_input_bar_context.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/contexts/query_input_bar_context.ts rename to src/plugins/vis_types/timeseries/public/application/contexts/query_input_bar_context.ts diff --git a/src/plugins/vis_type_timeseries/public/application/contexts/vis_data_context.ts b/src/plugins/vis_types/timeseries/public/application/contexts/vis_data_context.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/contexts/vis_data_context.ts rename to src/plugins/vis_types/timeseries/public/application/contexts/vis_data_context.ts diff --git a/src/plugins/vis_type_timeseries/public/application/editor_controller.tsx b/src/plugins/vis_types/timeseries/public/application/editor_controller.tsx similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/editor_controller.tsx rename to src/plugins/vis_types/timeseries/public/application/editor_controller.tsx diff --git a/src/plugins/vis_type_timeseries/public/application/index.scss b/src/plugins/vis_types/timeseries/public/application/index.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/index.scss rename to src/plugins/vis_types/timeseries/public/application/index.scss diff --git a/src/plugins/vis_type_timeseries/public/application/lib/check_ui_restrictions.js b/src/plugins/vis_types/timeseries/public/application/lib/check_ui_restrictions.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/check_ui_restrictions.js rename to src/plugins/vis_types/timeseries/public/application/lib/check_ui_restrictions.js diff --git a/src/plugins/vis_type_timeseries/public/application/lib/compute_gradient_final_color.test.ts b/src/plugins/vis_types/timeseries/public/application/lib/compute_gradient_final_color.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/compute_gradient_final_color.test.ts rename to src/plugins/vis_types/timeseries/public/application/lib/compute_gradient_final_color.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/lib/compute_gradient_final_color.ts b/src/plugins/vis_types/timeseries/public/application/lib/compute_gradient_final_color.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/compute_gradient_final_color.ts rename to src/plugins/vis_types/timeseries/public/application/lib/compute_gradient_final_color.ts diff --git a/src/plugins/vis_type_timeseries/public/application/lib/fetch_fields.ts b/src/plugins/vis_types/timeseries/public/application/lib/fetch_fields.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/fetch_fields.ts rename to src/plugins/vis_types/timeseries/public/application/lib/fetch_fields.ts diff --git a/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.test.ts b/src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.test.ts similarity index 97% rename from src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.test.ts rename to src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.test.ts index 0a78e525796ff..c447acb74dc37 100644 --- a/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.test.ts +++ b/src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.test.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { chartPluginMock } from '../../../../charts/public/mocks'; +import { chartPluginMock } from '../../../../../charts/public/mocks'; import { getSplitByTermsColor, SplitByTermsColorProps } from './get_split_by_terms_color'; const chartsRegistry = chartPluginMock.createPaletteRegistry(); diff --git a/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts b/src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts rename to src/plugins/vis_types/timeseries/public/application/lib/get_split_by_terms_color.ts diff --git a/src/plugins/vis_type_timeseries/public/application/lib/get_timezone.ts b/src/plugins/vis_types/timeseries/public/application/lib/get_timezone.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/get_timezone.ts rename to src/plugins/vis_types/timeseries/public/application/lib/get_timezone.ts diff --git a/src/plugins/vis_type_timeseries/public/application/lib/index.ts b/src/plugins/vis_types/timeseries/public/application/lib/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/index.ts rename to src/plugins/vis_types/timeseries/public/application/lib/index.ts diff --git a/src/plugins/vis_type_timeseries/public/application/lib/rainbow_colors.ts b/src/plugins/vis_types/timeseries/public/application/lib/rainbow_colors.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/rainbow_colors.ts rename to src/plugins/vis_types/timeseries/public/application/lib/rainbow_colors.ts diff --git a/src/plugins/vis_type_timeseries/public/application/lib/set_is_reversed.js b/src/plugins/vis_types/timeseries/public/application/lib/set_is_reversed.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/lib/set_is_reversed.js rename to src/plugins/vis_types/timeseries/public/application/lib/set_is_reversed.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/constants/chart.ts b/src/plugins/vis_types/timeseries/public/application/visualizations/constants/chart.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/constants/chart.ts rename to src/plugins/vis_types/timeseries/public/application/visualizations/constants/chart.ts diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/constants/icons.ts b/src/plugins/vis_types/timeseries/public/application/visualizations/constants/icons.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/constants/icons.ts rename to src/plugins/vis_types/timeseries/public/application/visualizations/constants/icons.ts diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/constants/index.ts b/src/plugins/vis_types/timeseries/public/application/visualizations/constants/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/constants/index.ts rename to src/plugins/vis_types/timeseries/public/application/visualizations/constants/index.ts diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/lib/calc_dimensions.js b/src/plugins/vis_types/timeseries/public/application/visualizations/lib/calc_dimensions.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/lib/calc_dimensions.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/lib/calc_dimensions.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/lib/calculate_coordinates.js b/src/plugins/vis_types/timeseries/public/application/visualizations/lib/calculate_coordinates.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/lib/calculate_coordinates.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/lib/calculate_coordinates.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/lib/get_value_by.js b/src/plugins/vis_types/timeseries/public/application/visualizations/lib/get_value_by.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/lib/get_value_by.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/lib/get_value_by.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/_annotation.scss b/src/plugins/vis_types/timeseries/public/application/visualizations/views/_annotation.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/_annotation.scss rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/_annotation.scss diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/_gauge.scss b/src/plugins/vis_types/timeseries/public/application/visualizations/views/_gauge.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/_gauge.scss rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/_gauge.scss diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/_index.scss b/src/plugins/vis_types/timeseries/public/application/visualizations/views/_index.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/_index.scss rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/_index.scss diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/_metric.scss b/src/plugins/vis_types/timeseries/public/application/visualizations/views/_metric.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/_metric.scss rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/_metric.scss diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/_top_n.scss b/src/plugins/vis_types/timeseries/public/application/visualizations/views/_top_n.scss similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/_top_n.scss rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/_top_n.scss diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/annotation.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/annotation.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/annotation.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/annotation.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/gauge.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/gauge.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/gauge.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/gauge.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/gauge_vis.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/gauge_vis.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/gauge_vis.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/gauge_vis.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/metric.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/metric.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/metric.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/metric.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/bar_decorator.test.js.snap b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/bar_decorator.test.js.snap similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/bar_decorator.test.js.snap rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/bar_decorator.test.js.snap diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/area_decorator.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/area_decorator.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/area_decorator.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/area_decorator.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/area_decorator.test.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/area_decorator.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/area_decorator.test.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/area_decorator.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/bar_decorator.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/bar_decorator.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/bar_decorator.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/bar_decorator.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/bar_decorator.test.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/bar_decorator.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/decorators/bar_decorator.test.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/bar_decorator.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js similarity index 99% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js index 1edaf38ef403c..6f6ddbbb7c414 100644 --- a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/index.js @@ -32,7 +32,7 @@ import { getBaseTheme, getChartClasses } from './utils/theme'; import { TOOLTIP_MODES } from '../../../../../common/enums'; import { getValueOrEmpty } from '../../../../../common/empty_label'; import { getSplitByTermsColor } from '../../../lib/get_split_by_terms_color'; -import { renderEndzoneTooltip, useActiveCursor } from '../../../../../../charts/public'; +import { renderEndzoneTooltip, useActiveCursor } from '../../../../../../../charts/public'; import { getAxisLabelString } from '../../../components/lib/get_axis_label_string'; import { calculateDomainForSeries } from './utils/series_domain_calculation'; diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/model/__snapshots__/charts.test.js.snap b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/model/__snapshots__/charts.test.js.snap similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/model/__snapshots__/charts.test.js.snap rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/model/__snapshots__/charts.test.js.snap diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/model/charts.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/model/charts.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/model/charts.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/model/charts.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/model/charts.test.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/model/charts.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/model/charts.test.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/model/charts.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculation.ts b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculation.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculation.ts rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculation.ts diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculations.test.ts b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculations.test.ts similarity index 93% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculations.test.ts rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculations.test.ts index 5b502636003f0..53157286328e2 100644 --- a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculations.test.ts +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_domain_calculations.test.ts @@ -7,7 +7,7 @@ */ import { calculateDomainForSeries } from './series_domain_calculation'; -import { PanelData } from 'src/plugins/vis_type_timeseries/common/types'; +import { PanelData } from 'src/plugins/vis_types/timeseries/common/types'; describe('calculateDomainForSeries', () => { it('should return 0 for domainStart and 3 for domainEnd', () => { diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_styles.test.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/series_styles.test.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/stack_format.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/stack_format.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/stack_format.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/stack_format.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/stack_format.test.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/stack_format.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/stack_format.test.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/stack_format.test.js diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/theme.test.ts b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/theme.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/theme.test.ts rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/theme.test.ts diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/theme.ts b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/theme.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/utils/theme.ts rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/theme.ts diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/top_n.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/top_n.js similarity index 100% rename from src/plugins/vis_type_timeseries/public/application/visualizations/views/top_n.js rename to src/plugins/vis_types/timeseries/public/application/visualizations/views/top_n.js diff --git a/src/plugins/vis_type_timeseries/public/index.ts b/src/plugins/vis_types/timeseries/public/index.ts similarity index 88% rename from src/plugins/vis_type_timeseries/public/index.ts rename to src/plugins/vis_types/timeseries/public/index.ts index 0ab10581c48c2..a3180678b53a0 100644 --- a/src/plugins/vis_type_timeseries/public/index.ts +++ b/src/plugins/vis_types/timeseries/public/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PluginInitializerContext } from '../../../core/public'; +import { PluginInitializerContext } from '../../../../core/public'; import { MetricsPlugin as Plugin } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { diff --git a/src/plugins/vis_type_timeseries/public/metrics_fn.ts b/src/plugins/vis_types/timeseries/public/metrics_fn.ts similarity index 93% rename from src/plugins/vis_type_timeseries/public/metrics_fn.ts rename to src/plugins/vis_types/timeseries/public/metrics_fn.ts index fe1c4722762ae..23c196ebe1149 100644 --- a/src/plugins/vis_type_timeseries/public/metrics_fn.ts +++ b/src/plugins/vis_types/timeseries/public/metrics_fn.ts @@ -7,8 +7,8 @@ */ import { i18n } from '@kbn/i18n'; -import { KibanaContext } from '../../data/public'; -import { ExpressionFunctionDefinition, Render } from '../../expressions/public'; +import { KibanaContext } from '../../../data/public'; +import { ExpressionFunctionDefinition, Render } from '../../../expressions/public'; import type { TimeseriesVisData } from '../common/types'; import { metricsRequestHandler } from './request_handler'; diff --git a/src/plugins/vis_type_timeseries/public/metrics_type.ts b/src/plugins/vis_types/timeseries/public/metrics_type.ts similarity index 98% rename from src/plugins/vis_type_timeseries/public/metrics_type.ts rename to src/plugins/vis_types/timeseries/public/metrics_type.ts index 5d4a61c1edb82..64970d9730eee 100644 --- a/src/plugins/vis_type_timeseries/public/metrics_type.ts +++ b/src/plugins/vis_types/timeseries/public/metrics_type.ts @@ -19,7 +19,7 @@ import { VisGroups, VisParams, VisTypeDefinition, -} from '../../visualizations/public'; +} from '../../../visualizations/public'; import { getDataStart } from './services'; import type { TimeseriesVisDefaultParams, TimeseriesVisParams } from './types'; diff --git a/src/plugins/vis_type_timeseries/public/plugin.ts b/src/plugins/vis_types/timeseries/public/plugin.ts similarity index 86% rename from src/plugins/vis_type_timeseries/public/plugin.ts rename to src/plugins/vis_types/timeseries/public/plugin.ts index 3cd090c7da829..d6d83caa6eb0f 100644 --- a/src/plugins/vis_type_timeseries/public/plugin.ts +++ b/src/plugins/vis_types/timeseries/public/plugin.ts @@ -7,9 +7,9 @@ */ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; -import { VisualizationsSetup } from '../../visualizations/public'; -import { VisualizePluginSetup } from '../../visualize/public'; +import { Plugin as ExpressionsPublicPlugin } from '../../../expressions/public'; +import { VisualizationsSetup } from '../../../visualizations/public'; +import { VisualizePluginSetup } from '../../../visualize/public'; import { EditorController, TSVB_EDITOR_NAME } from './application/editor_controller'; import { createMetricsFn } from './metrics_fn'; @@ -22,8 +22,8 @@ import { setDataStart, setCharts, } from './services'; -import { DataPublicPluginStart } from '../../data/public'; -import { ChartsPluginStart } from '../../charts/public'; +import { DataPublicPluginStart } from '../../../data/public'; +import { ChartsPluginStart } from '../../../charts/public'; import { getTimeseriesVisRenderer } from './timeseries_vis_renderer'; /** @internal */ diff --git a/src/plugins/vis_type_timeseries/public/request_handler.ts b/src/plugins/vis_types/timeseries/public/request_handler.ts similarity index 97% rename from src/plugins/vis_type_timeseries/public/request_handler.ts rename to src/plugins/vis_types/timeseries/public/request_handler.ts index 0a110dd65d5e9..e9037c0b84a5e 100644 --- a/src/plugins/vis_type_timeseries/public/request_handler.ts +++ b/src/plugins/vis_types/timeseries/public/request_handler.ts @@ -12,7 +12,7 @@ import { ROUTES } from '../common/constants'; import type { TimeseriesVisParams } from './types'; import type { TimeseriesVisData } from '../common/types'; -import type { KibanaContext } from '../../data/public'; +import type { KibanaContext } from '../../../data/public'; interface MetricsRequestHandlerParams { input: KibanaContext | null; diff --git a/src/plugins/vis_type_timeseries/public/services.ts b/src/plugins/vis_types/timeseries/public/services.ts similarity index 84% rename from src/plugins/vis_type_timeseries/public/services.ts rename to src/plugins/vis_types/timeseries/public/services.ts index ba7ab4a25c8a2..f76a9ed7c6389 100644 --- a/src/plugins/vis_type_timeseries/public/services.ts +++ b/src/plugins/vis_types/timeseries/public/services.ts @@ -7,9 +7,9 @@ */ import { I18nStart, IUiSettingsClient, CoreStart } from 'src/core/public'; -import { createGetterSetter } from '../../kibana_utils/public'; -import { ChartsPluginStart } from '../../charts/public'; -import { DataPublicPluginStart } from '../../data/public'; +import { createGetterSetter } from '../../../kibana_utils/public'; +import { ChartsPluginStart } from '../../../charts/public'; +import { DataPublicPluginStart } from '../../../data/public'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); diff --git a/src/plugins/vis_type_timeseries/public/test_utils/index.ts b/src/plugins/vis_types/timeseries/public/test_utils/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/test_utils/index.ts rename to src/plugins/vis_types/timeseries/public/test_utils/index.ts diff --git a/src/plugins/vis_type_timeseries/public/timeseries_vis_renderer.tsx b/src/plugins/vis_types/timeseries/public/timeseries_vis_renderer.tsx similarity index 94% rename from src/plugins/vis_type_timeseries/public/timeseries_vis_renderer.tsx rename to src/plugins/vis_types/timeseries/public/timeseries_vis_renderer.tsx index 9a19ddc285ebb..34cc1dc347ef8 100644 --- a/src/plugins/vis_type_timeseries/public/timeseries_vis_renderer.tsx +++ b/src/plugins/vis_types/timeseries/public/timeseries_vis_renderer.tsx @@ -14,14 +14,14 @@ import { I18nProvider } from '@kbn/i18n/react'; import { IUiSettingsClient } from 'kibana/public'; import { fetchIndexPattern } from '../common/index_patterns_utils'; -import { VisualizationContainer, PersistedState } from '../../visualizations/public'; +import { VisualizationContainer, PersistedState } from '../../../visualizations/public'; import type { TimeseriesVisData } from '../common/types'; import { isVisTableData } from '../common/vis_data_utils'; import { getCharts, getDataStart } from './services'; import type { TimeseriesVisParams } from './types'; -import type { ExpressionRenderDefinition } from '../../expressions/common'; +import type { ExpressionRenderDefinition } from '../../../expressions/common'; import type { TimeseriesRenderValue } from './metrics_fn'; const TimeseriesVisualization = lazy( diff --git a/src/plugins/vis_type_timeseries/public/to_ast.ts b/src/plugins/vis_types/timeseries/public/to_ast.ts similarity index 91% rename from src/plugins/vis_type_timeseries/public/to_ast.ts rename to src/plugins/vis_types/timeseries/public/to_ast.ts index c0c0a5b1546a9..91fc7465f122f 100644 --- a/src/plugins/vis_type_timeseries/public/to_ast.ts +++ b/src/plugins/vis_types/timeseries/public/to_ast.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { buildExpression, buildExpressionFunction } from '../../expressions/public'; -import type { Vis } from '../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../../expressions/public'; +import type { Vis } from '../../../visualizations/public'; import type { TimeseriesExpressionFunctionDefinition } from './metrics_fn'; import type { TimeseriesVisParams } from './types'; diff --git a/src/plugins/vis_type_timeseries/public/types.ts b/src/plugins/vis_types/timeseries/public/types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/public/types.ts rename to src/plugins/vis_types/timeseries/public/types.ts diff --git a/src/plugins/vis_type_timeseries/server/config.ts b/src/plugins/vis_types/timeseries/server/config.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/config.ts rename to src/plugins/vis_types/timeseries/server/config.ts diff --git a/src/plugins/vis_type_timeseries/server/index.ts b/src/plugins/vis_types/timeseries/server/index.ts similarity index 61% rename from src/plugins/vis_type_timeseries/server/index.ts rename to src/plugins/vis_types/timeseries/server/index.ts index a78ddade30965..7a10740a53d32 100644 --- a/src/plugins/vis_type_timeseries/server/index.ts +++ b/src/plugins/vis_types/timeseries/server/index.ts @@ -13,20 +13,6 @@ import { VisTypeTimeseriesPlugin } from './plugin'; export { VisTypeTimeseriesSetup } from './plugin'; export const config: PluginConfigDescriptor = { - deprecations: ({ unused, renameFromRoot }) => [ - // In Kibana v7.8 plugin id was renamed from 'metrics' to 'vis_type_timeseries': - renameFromRoot('metrics.enabled', 'vis_type_timeseries.enabled', { silent: true }), - renameFromRoot('metrics.chartResolution', 'vis_type_timeseries.chartResolution', { - silent: true, - }), - renameFromRoot('metrics.minimumBucketSize', 'vis_type_timeseries.minimumBucketSize', { - silent: true, - }), - - // Unused properties which should be removed after releasing Kibana v8.0: - unused('chartResolution'), - unused('minimumBucketSize'), - ], schema: configSchema, }; diff --git a/src/plugins/vis_type_timeseries/server/lib/get_fields.ts b/src/plugins/vis_types/timeseries/server/lib/get_fields.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/get_fields.ts rename to src/plugins/vis_types/timeseries/server/lib/get_fields.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts b/src/plugins/vis_types/timeseries/server/lib/get_vis_data.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts rename to src/plugins/vis_types/timeseries/server/lib/get_vis_data.ts index bc4fbf9159a00..a76132e0fbd21 100644 --- a/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts +++ b/src/plugins/vis_types/timeseries/server/lib/get_vis_data.ts @@ -20,8 +20,8 @@ import { getSeriesData } from './vis_data/get_series_data'; import { getTableData } from './vis_data/get_table_data'; import { getEsQueryConfig } from './vis_data/helpers/get_es_query_uisettings'; import { getCachedIndexPatternFetcher } from './search_strategies/lib/cached_index_pattern_fetcher'; -import { MAX_BUCKETS_SETTING } from '../../common/constants'; import { getIntervalAndTimefield } from './vis_data/get_interval_and_timefield'; +import { UI_SETTINGS } from '../../common/constants'; export async function getVisData( requestContext: VisTypeTimeseriesRequestHandlerContext, @@ -57,7 +57,7 @@ export async function getVisData( index = await cachedIndexPatternFetcher(index.indexPatternString, true); } - const maxBuckets = await uiSettings.get(MAX_BUCKETS_SETTING); + const maxBuckets = await uiSettings.get(UI_SETTINGS.MAX_BUCKETS_SETTING); const { min, max } = request.body.timerange; return getIntervalAndTimefield( diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.test.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/default_search_capabilities.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.test.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/capabilities/rollup_search_capabilities.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/index.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/index.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/index.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts index 5f989a50ca639..2a3738878c97a 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts @@ -8,7 +8,7 @@ import { getIndexPatternKey, fetchIndexPattern } from '../../../../common/index_patterns_utils'; -import type { IndexPatternsService } from '../../../../../data/server'; +import type { IndexPatternsService } from '../../../../../../data/server'; import type { IndexPatternValue, FetchedIndexPattern } from '../../../../common/types'; export const getCachedIndexPatternFetcher = ( diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts index 9563a8fbece23..cf7bc42fc6db3 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/fields_fetcher.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/fields_fetcher.ts @@ -10,7 +10,7 @@ import { getIndexPatternKey } from '../../../../common/index_patterns_utils'; import type { VisTypeTimeseriesVisDataRequest } from '../../../types'; import type { SearchStrategy, SearchCapabilities } from '../index'; -import type { IndexPatternsService } from '../../../../../data/common'; +import type { IndexPatternsService } from '../../../../../../data/common'; import type { CachedIndexPatternFetcher } from './cached_index_pattern_fetcher'; import type { IndexPatternValue } from '../../../../common/types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/interval_helper.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/interval_helper.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/interval_helper.test.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/interval_helper.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/interval_helper.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/interval_helper.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/interval_helper.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/lib/interval_helper.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_registry.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/search_strategies_registry.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategies_registry.test.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/search_strategies_registry.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategy_registry.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/search_strategy_registry.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/search_strategy_registry.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/search_strategy_registry.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts index 0a9b3d0047c80..6216bce00fc7d 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ -import { IndexPatternsService } from '../../../../../data/common'; +import { IndexPatternsService } from '../../../../../../data/common'; import { from } from 'rxjs'; import { AbstractSearchStrategy } from './abstract_search_strategy'; -import type { FieldSpec } from '../../../../../data/common'; +import type { FieldSpec } from '../../../../../../data/common'; import type { CachedIndexPatternFetcher } from '../lib/cached_index_pattern_fetcher'; import type { VisTypeTimeseriesRequestHandlerContext, diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts similarity index 96% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts index 26c3a6c7c8bf7..bce07d2cdb300 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { IndexPatternsService } from '../../../../../data/server'; +import { IndexPatternsService } from '../../../../../../data/server'; import { toSanitizedFieldType } from '../../../../common/fields_utils'; import type { FetchedIndexPattern } from '../../../../common/types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts similarity index 86% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts index 34892ec797c0b..ff1c3c0ac71ee 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/default_search_strategy.ts @@ -9,13 +9,13 @@ import { AbstractSearchStrategy } from './abstract_search_strategy'; import { DefaultSearchCapabilities } from '../capabilities/default_search_capabilities'; -import type { IndexPatternsService } from '../../../../../data/server'; +import type { IndexPatternsService } from '../../../../../../data/server'; import type { FetchedIndexPattern } from '../../../../common/types'; import type { VisTypeTimeseriesRequestHandlerContext, VisTypeTimeseriesRequest, } from '../../../types'; -import { MAX_BUCKETS_SETTING } from '../../../../common/constants'; +import { UI_SETTINGS } from '../../../../common/constants'; export class DefaultSearchStrategy extends AbstractSearchStrategy { async checkForViability( @@ -29,7 +29,7 @@ export class DefaultSearchStrategy extends AbstractSearchStrategy { capabilities: new DefaultSearchCapabilities({ panel: req.body.panels ? req.body.panels[0] : null, timezone: req.body.timerange?.timezone, - maxBucketsLimit: await uiSettings.get(MAX_BUCKETS_SETTING), + maxBucketsLimit: await uiSettings.get(UI_SETTINGS.MAX_BUCKETS_SETTING), }), }; } diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/index.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/index.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/index.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts similarity index 98% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts index 85b8bcdf57b93..4d2608e3519ed 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.test.ts @@ -8,7 +8,7 @@ import { RollupSearchStrategy } from './rollup_search_strategy'; -import type { IndexPatternsService } from '../../../../../data/common'; +import type { IndexPatternsService } from '../../../../../../data/common'; import type { CachedIndexPatternFetcher } from '../lib/cached_index_pattern_fetcher'; import type { VisTypeTimeseriesRequestHandlerContext, diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts similarity index 92% rename from src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts rename to src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts index f68c877cf7a3f..e3ede57774224 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts @@ -6,7 +6,10 @@ * Side Public License, v 1. */ -import { getCapabilitiesForRollupIndices, IndexPatternsService } from '../../../../../data/server'; +import { + getCapabilitiesForRollupIndices, + IndexPatternsService, +} from '../../../../../../data/server'; import { AbstractSearchStrategy } from './abstract_search_strategy'; import { RollupSearchCapabilities } from '../capabilities/rollup_search_capabilities'; @@ -17,7 +20,7 @@ import type { VisTypeTimeseriesRequestHandlerContext, VisTypeTimeseriesVisDataRequest, } from '../../../types'; -import { MAX_BUCKETS_SETTING } from '../../../../common/constants'; +import { UI_SETTINGS } from '../../../../common/constants'; const getRollupIndices = (rollupData: { [key: string]: any }) => Object.keys(rollupData); const isIndexPatternContainsWildcard = (indexPattern: string) => indexPattern.includes('*'); @@ -72,7 +75,7 @@ export class RollupSearchStrategy extends AbstractSearchStrategy { capabilities = new RollupSearchCapabilities( { - maxBucketsLimit: await uiSettings.get(MAX_BUCKETS_SETTING), + maxBucketsLimit: await uiSettings.get(UI_SETTINGS.MAX_BUCKETS_SETTING), panel: req.body.panels ? req.body.panels[0] : null, }, fieldsCapabilities, diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/annotations/build_request_body.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/annotations/build_request_body.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/annotations/build_request_body.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/annotations/build_request_body.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/annotations/get_request_params.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/annotations/get_request_params.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/annotations/get_request_params.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/annotations/get_request_params.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/build_processor_function.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/build_processor_function.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/build_processor_function.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/build_processor_function.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/build_processor_function.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/get_annotations.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_annotations.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/get_annotations.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/get_annotations.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_interval_and_timefield.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/get_interval_and_timefield.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_interval_and_timefield.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/get_interval_and_timefield.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/get_interval_and_timefield.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/get_series_data.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/get_series_data.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/get_table_data.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/get_table_data.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/handle_error_response.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/handle_error_response.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/handle_error_response.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/handle_error_response.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/handle_error_response.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/handle_error_response.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/handle_error_response.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/handle_error_response.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/bucket_transform.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/bucket_transform.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/bucket_transform.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/bucket_transform.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/bucket_transform.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/check_aggs.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/check_aggs.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/check_aggs.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/check_aggs.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/format_key.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/format_key.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/format_key.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/format_key.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_active_series.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_active_series.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_active_series.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_active_series.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_agg_value.js similarity index 97% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_agg_value.js index 6756a8f7fc85a..eac2c4af65291 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_agg_value.js @@ -8,7 +8,7 @@ import { get, max, min, sum, noop } from 'lodash'; import { toPercentileNumber } from '../../../../common/to_percentile_number'; -import { METRIC_TYPES } from '../../../../../data/common'; +import { METRIC_TYPES } from '../../../../../../data/common'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; import { getAggByPredicate } from '../../../../common/agg_utils'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_agg_value.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_agg_value.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_agg_value.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.ts similarity index 98% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.ts index 7f5874c0763f5..e02b403c8ba13 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_bucket_size.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_bucket_size.ts @@ -15,7 +15,7 @@ import { } from './unit_to_seconds'; import { getTimerange } from './get_timerange'; import { INTERVAL_STRING_RE, GTE_INTERVAL_RE } from '../../../../common/interval_regexp'; -import { search } from '../../../../../data/server'; +import { search } from '../../../../../../data/server'; import type { SearchCapabilities } from '../../search_strategies'; import type { VisTypeTimeseriesVisDataRequest } from '../../../types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_buckets_path.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_buckets_path.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_buckets_path.ts similarity index 96% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_buckets_path.ts index be8755584e2c7..06df19ab73856 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_buckets_path.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_buckets_path.ts @@ -8,7 +8,7 @@ import { startsWith } from 'lodash'; import { toPercentileNumber } from '../../../../common/to_percentile_number'; -import { METRIC_TYPES } from '../../../../../data/common'; +import { METRIC_TYPES } from '../../../../../../data/common'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; import type { Metric } from '../../../../common/types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_default_decoration.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_default_decoration.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_default_decoration.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.ts similarity index 93% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.ts index c5ceac5cd7dd5..07b030782d6d7 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_es_query_uisettings.ts @@ -7,7 +7,7 @@ */ import { IUiSettingsClient } from 'kibana/server'; -import { UI_SETTINGS } from '../../../../../data/server'; +import { UI_SETTINGS } from '../../../../../../data/server'; export async function getEsQueryConfig(uiSettings: IUiSettingsClient) { const allowLeadingWildcards = await uiSettings.get(UI_SETTINGS.QUERY_ALLOW_LEADING_WILDCARDS); diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_last_metric.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_last_metric.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_last_metric.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_last_metric.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_last_metric.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_sibling_agg_value.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_splits.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_splits.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_splits.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_splits.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_timerange.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_timerange.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_timerange.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_timerange.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange_mode.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_timerange_mode.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_timerange_mode.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/get_timerange_mode.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/index.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/index.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/index.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_empty_to_zero.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/map_empty_to_zero.test.ts similarity index 96% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_empty_to_zero.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/map_empty_to_zero.test.ts index d52b6b38a7bd7..fd061cd363695 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_empty_to_zero.test.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/map_empty_to_zero.test.ts @@ -7,7 +7,7 @@ */ import { mapEmptyToZero } from './map_empty_to_zero'; -import { METRIC_TYPES } from '../../../../../data/common'; +import { METRIC_TYPES } from '../../../../../../data/common'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; describe('mapEmptyToZero(metric, buckets)', () => { diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_empty_to_zero.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/map_empty_to_zero.ts similarity index 94% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_empty_to_zero.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/map_empty_to_zero.ts index a035d566d130e..26014b229bae9 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/map_empty_to_zero.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/map_empty_to_zero.ts @@ -8,7 +8,7 @@ // @ts-expect-error not typed yet import { getAggValue } from './get_agg_value'; -import { METRIC_TYPES } from '../../../../../data/common'; +import { METRIC_TYPES } from '../../../../../../data/common'; import type { Metric } from '../../../../common/types'; import type { PanelDataArray } from '../../../../common/types/vis_data'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/moving_fn_scripts.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/moving_fn_scripts.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/overwrite.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/overwrite.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/overwrite.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/overwrite.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_interval.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/parse_interval.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/parse_interval.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/parse_interval.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/timestamp.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/timestamp.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/timestamp.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/timestamp.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/timestamp.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/unit_to_seconds.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/helpers/unit_to_seconds.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/offset_time.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/offset_time.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/offset_time.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/offset_time.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/offset_time.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/offset_time.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/offset_time.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/offset_time.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.ts index 258dc2d541376..a52e15eb90fee 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.ts @@ -10,7 +10,7 @@ import { overwrite } from '../../helpers'; import { getBucketSize, getTimerange } from '../../helpers'; import { validateField } from '../../../../../common/fields_utils'; -import { search, UI_SETTINGS } from '../../../../../../../plugins/data/server'; +import { search, UI_SETTINGS } from '../../../../../../../../plugins/data/server'; import type { AnnotationsRequestProcessorsFunction } from './types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/index.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/index.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/index.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.ts similarity index 97% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.ts index 53fe51329acb3..f1b11a780fec8 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/query.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.ts @@ -8,7 +8,7 @@ import { getBucketSize, getTimerange, overwrite } from '../../helpers'; import { validateField } from '../../../../../common/fields_utils'; -import { esQuery, UI_SETTINGS } from '../../../../../../data/server'; +import { esQuery, UI_SETTINGS } from '../../../../../../../data/server'; import type { AnnotationsRequestProcessorsFunction } from './types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/top_hits.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/top_hits.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/top_hits.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/top_hits.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/types.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/types.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/types.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/date_histogram.js similarity index 97% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/date_histogram.js index 6349a75993aa8..696bea7d6421b 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/date_histogram.js @@ -10,7 +10,7 @@ import { overwrite } from '../../helpers'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { offsetTime } from '../../offset_time'; import { isLastValueTimerangeMode } from '../../helpers/get_timerange_mode'; -import { search, UI_SETTINGS } from '../../../../../../../plugins/data/server'; +import { search, UI_SETTINGS } from '../../../../../../../../plugins/data/server'; import { AGG_TYPE, getAggsByType } from '../../../../../common/agg_utils'; import { TSVB_METRIC_TYPES } from '../../../../../common/enums'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js similarity index 99% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js index b09b2c28d77e3..6a7f09a49f26a 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/date_histogram.test.js @@ -9,7 +9,7 @@ import { DefaultSearchCapabilities } from '../../../search_strategies/capabilities/default_search_capabilities'; import { dateHistogram } from './date_histogram'; import { getIntervalAndTimefield } from '../../get_interval_and_timefield'; -import { UI_SETTINGS } from '../../../../../../data/common'; +import { UI_SETTINGS } from '../../../../../../../data/common'; describe('dateHistogram(req, panel, series)', () => { let panel; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js similarity index 97% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js index d45943f6f21ac..32e9a1ea0aa90 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/filter_ratios.js @@ -8,7 +8,7 @@ import { bucketTransform } from '../../helpers/bucket_transform'; import { overwrite } from '../../helpers'; -import { esQuery } from '../../../../../../data/server'; +import { esQuery } from '../../../../../../../data/server'; const filter = (metric) => metric.type === 'filter_ratio'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/filter_ratios.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/index.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/index.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/index.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/metric_buckets.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/metric_buckets.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/normalize_query.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/normalize_query.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/normalize_query.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/positive_rate.js similarity index 97% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/positive_rate.js index 91016384794c4..86c5311f51dcb 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/positive_rate.js @@ -9,7 +9,7 @@ import { getBucketSize } from '../../helpers/get_bucket_size'; import { bucketTransform } from '../../helpers/bucket_transform'; import { overwrite } from '../../helpers'; -import { UI_SETTINGS } from '../../../../../../data/common'; +import { UI_SETTINGS } from '../../../../../../../data/common'; export const filter = (metric) => metric.type === 'positive_rate'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/positive_rate.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/positive_rate.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/positive_rate.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/query.js similarity index 96% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/query.js index 5031a0f2ec185..f745a7bf7ad74 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/query.js @@ -7,7 +7,7 @@ */ import { offsetTime } from '../../offset_time'; -import { esQuery } from '../../../../../../data/server'; +import { esQuery } from '../../../../../../../data/server'; export function query( req, diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/query.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/query.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/query.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/sibling_buckets.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_everything.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_everything.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js similarity index 92% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js index 01e1b9f8d1dce..b7e7754d05f81 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filter.js @@ -7,7 +7,7 @@ */ import { overwrite } from '../../helpers'; -import { esQuery } from '../../../../../../data/server'; +import { esQuery } from '../../../../../../../data/server'; export function splitByFilter(req, panel, series, esQueryConfig, seriesIndex) { return (next) => (doc) => { diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filter.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js similarity index 93% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js index 77b9ccc5880fe..5e8def5db771e 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filters.js @@ -7,7 +7,7 @@ */ import { overwrite } from '../../helpers'; -import { esQuery } from '../../../../../../data/server'; +import { esQuery } from '../../../../../../../data/server'; export function splitByFilters(req, panel, series, esQueryConfig, seriesIndex) { return (next) => (doc) => { diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_filters.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_terms.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/series/split_by_terms.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/calculate_agg_root.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/date_histogram.ts similarity index 97% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/date_histogram.ts index 5dee812dd4c56..c02f661c3aedc 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/date_histogram.ts @@ -8,7 +8,7 @@ import { overwrite, getBucketSize, isLastValueTimerangeMode, getTimerange } from '../../helpers'; import { calculateAggRoot } from './calculate_agg_root'; -import { search, UI_SETTINGS } from '../../../../../../../plugins/data/server'; +import { search, UI_SETTINGS } from '../../../../../../../../plugins/data/server'; import { AGG_TYPE, getAggsByType } from '../../../../../common/agg_utils'; import { TSVB_METRIC_TYPES } from '../../../../../common/enums'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/filter_ratios.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/filter_ratios.ts similarity index 97% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/filter_ratios.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/filter_ratios.ts index e8fb684ef4b6c..b6036a03ba464 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/filter_ratios.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/filter_ratios.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { esQuery } from '../../../../../../data/server'; +import { esQuery } from '../../../../../../../data/server'; import { overwrite, bucketTransform } from '../../helpers'; import { calculateAggRoot } from './calculate_agg_root'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/index.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/index.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/metric_buckets.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/metric_buckets.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/metric_buckets.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/metric_buckets.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/normalize_query.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/normalize_query.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/normalize_query.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/normalize_query.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/pivot.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/pivot.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/pivot.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/pivot.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/positive_rate.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/positive_rate.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/positive_rate.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/positive_rate.ts index 85a817e124aa1..e03a65ffebbd1 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/positive_rate.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/positive_rate.ts @@ -8,7 +8,7 @@ import { getBucketSize } from '../../helpers/get_bucket_size'; import { calculateAggRoot } from './calculate_agg_root'; -import { UI_SETTINGS } from '../../../../../../data/common'; +import { UI_SETTINGS } from '../../../../../../../data/common'; import type { TableRequestProcessorsFunction } from './types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.ts similarity index 96% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.ts index 5ddf83e1134b3..76c4649ee5738 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/query.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.ts @@ -7,7 +7,7 @@ */ import { getTimerange, overwrite } from '../../helpers'; -import { esQuery } from '../../../../../../data/server'; +import { esQuery } from '../../../../../../../data/server'; import type { TableRequestProcessorsFunction } from './types'; export const query: TableRequestProcessorsFunction = diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/sibling_buckets.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/split_by_everything.ts similarity index 94% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/split_by_everything.ts index cca86a1960fcd..e0e1485f6a8ff 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_everything.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/split_by_everything.ts @@ -7,7 +7,7 @@ */ import { overwrite } from '../../helpers'; -import { esQuery } from '../../../../../../data/server'; +import { esQuery } from '../../../../../../../data/server'; import type { TableRequestProcessorsFunction } from './types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/split_by_terms.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/split_by_terms.ts index 35b0ba50a05b9..1a4e0f6ceb1b5 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/split_by_terms.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/split_by_terms.ts @@ -7,7 +7,7 @@ */ import { overwrite } from '../../helpers'; -import { esQuery } from '../../../../../../data/server'; +import { esQuery } from '../../../../../../../data/server'; import type { TableRequestProcessorsFunction } from './types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts index d47d3fe34c9b1..6bb4dfa55426a 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/types.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/types.ts @@ -8,7 +8,7 @@ import type { IUiSettingsClient } from 'kibana/server'; import type { FetchedIndexPattern, Panel } from '../../../../../common/types'; -import type { EsQueryConfig } from '../../../../../../data/common'; +import type { EsQueryConfig } from '../../../../../../../data/common'; import type { SearchCapabilities } from '../../../search_strategies'; import type { VisTypeTimeseriesVisDataRequest } from '../../../../types'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/types.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/types.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/types.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/buckets.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/annotations/buckets.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/buckets.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/annotations/buckets.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/annotations/filter.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/annotations/filter.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/annotations/filter.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/filter.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/annotations/filter.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/index.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/annotations/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/annotations/index.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/annotations/index.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/_series_agg.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/_series_agg.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/_series_agg.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/drop_last_bucket.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/format_label.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/format_label.ts similarity index 96% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/format_label.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/format_label.ts index 7908cbccb9845..6d824c1c7f43e 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/format_label.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/format_label.ts @@ -9,7 +9,7 @@ import { KBN_FIELD_TYPES } from '@kbn/field-types'; import { BUCKET_TYPES, PANEL_TYPES } from '../../../../../common/enums'; import type { Panel, PanelData, Series } from '../../../../../common/types'; -import type { FieldFormatsRegistry } from '../../../../../../field_formats/common'; +import type { FieldFormatsRegistry } from '../../../../../../../field_formats/common'; import type { createFieldsFetcher } from '../../../search_strategies/lib/fields_fetcher'; import type { CachedIndexPatternFetcher } from '../../../search_strategies/lib/cached_index_pattern_fetcher'; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/index.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/index.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/index.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/index.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/math.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/math.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/math.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/math.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/percentile.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/percentile.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/percentile.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/percentile.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/percentile_rank.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/percentile_rank.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/percentile_rank.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/percentile_rank.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/series_agg.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/series_agg.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/series_agg.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_deviation_bands.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_deviation_sibling.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_metric.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_metric.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_metric.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_sibling.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_sibling.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/std_sibling.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/time_shift.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/time_shift.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/series/time_shift.test.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/_series_agg.js b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/_series_agg.js similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/_series_agg.js rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/_series_agg.js diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/drop_last_bucket.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/index.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/index.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/index.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/math.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/math.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/percentile.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/percentile.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile_rank.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/percentile_rank.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/percentile_rank.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/percentile_rank.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/series_agg.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/series_agg.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/series_agg.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/series_agg.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_metric.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/std_metric.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_metric.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/std_metric.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_sibling.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/std_sibling.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/std_sibling.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/std_sibling.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/types.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/types.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/types.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/response_processors/table/types.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/series/build_request_body.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/series/build_request_body.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/series/build_request_body.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/series/build_request_body.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/series/build_request_body.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/series/get_request_params.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/series/get_request_params.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/series/get_request_params.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/series/get_request_params.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/series/handle_response_body.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/series/handle_response_body.ts similarity index 96% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/series/handle_response_body.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/series/handle_response_body.ts index 78e9f971a61dd..415844abeedaf 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/series/handle_response_body.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/series/handle_response_body.ts @@ -17,7 +17,7 @@ import { FieldsFetcherServices, } from '../../search_strategies/lib/fields_fetcher'; import { VisTypeTimeseriesVisDataRequest } from '../../../types'; -import type { FieldFormatsRegistry } from '../../../../../field_formats/common'; +import type { FieldFormatsRegistry } from '../../../../../../field_formats/common'; export function handleResponseBody( panel: Panel, diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/table/build_request_body.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/table/build_request_body.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/table/build_request_body.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/table/build_request_body.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/table/build_response_body.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/table/build_response_body.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/table/build_response_body.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/table/build_response_body.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/table/process_bucket.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/table/process_bucket.test.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/table/process_bucket.test.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/table/process_bucket.test.ts diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/table/process_bucket.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/table/process_bucket.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/lib/vis_data/table/process_bucket.ts rename to src/plugins/vis_types/timeseries/server/lib/vis_data/table/process_bucket.ts diff --git a/src/plugins/vis_type_timeseries/server/plugin.ts b/src/plugins/vis_types/timeseries/server/plugin.ts similarity index 94% rename from src/plugins/vis_type_timeseries/server/plugin.ts rename to src/plugins/vis_types/timeseries/server/plugin.ts index d2ecb07c0273d..5347d9ab7bfbc 100644 --- a/src/plugins/vis_type_timeseries/server/plugin.ts +++ b/src/plugins/vis_types/timeseries/server/plugin.ts @@ -20,9 +20,9 @@ import { Server } from '@hapi/hapi'; import { first, map } from 'rxjs/operators'; import { VisTypeTimeseriesConfig } from './config'; import { getVisData } from './lib/get_vis_data'; -import { UsageCollectionSetup } from '../../usage_collection/server'; -import { PluginStart } from '../../data/server'; -import { IndexPatternsService } from '../../data/common'; +import { UsageCollectionSetup } from '../../../usage_collection/server'; +import { PluginStart } from '../../../data/server'; +import { IndexPatternsService } from '../../../data/common'; import { visDataRoutes } from './routes/vis'; import { fieldsRoutes } from './routes/fields'; import { getUiSettings } from './ui_settings'; @@ -30,7 +30,7 @@ import type { VisTypeTimeseriesRequestHandlerContext, VisTypeTimeseriesVisDataRequest, } from './types'; -import type { FieldFormatsRegistry } from '../../field_formats/common'; +import type { FieldFormatsRegistry } from '../../../field_formats/common'; import { SearchStrategyRegistry, diff --git a/src/plugins/vis_type_timeseries/server/routes/fields.ts b/src/plugins/vis_types/timeseries/server/routes/fields.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/routes/fields.ts rename to src/plugins/vis_types/timeseries/server/routes/fields.ts diff --git a/src/plugins/vis_type_timeseries/server/routes/vis.ts b/src/plugins/vis_types/timeseries/server/routes/vis.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/routes/vis.ts rename to src/plugins/vis_types/timeseries/server/routes/vis.ts diff --git a/src/plugins/vis_type_timeseries/server/types.ts b/src/plugins/vis_types/timeseries/server/types.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/types.ts rename to src/plugins/vis_types/timeseries/server/types.ts index 40ced72933012..ab01f09c75f1e 100644 --- a/src/plugins/vis_type_timeseries/server/types.ts +++ b/src/plugins/vis_types/timeseries/server/types.ts @@ -10,8 +10,8 @@ import { Observable } from 'rxjs'; import { EsQueryConfig } from '@kbn/es-query'; import { SharedGlobalConfig } from 'kibana/server'; import type { IRouter, IUiSettingsClient, KibanaRequest } from 'src/core/server'; -import type { DataRequestHandlerContext, IndexPatternsService } from '../../data/server'; -import type { FieldFormatsRegistry } from '../../field_formats/common'; +import type { DataRequestHandlerContext, IndexPatternsService } from '../../../data/server'; +import type { FieldFormatsRegistry } from '../../../field_formats/common'; import type { Series, VisPayload } from '../common/types'; import type { SearchStrategyRegistry } from './lib/search_strategies'; import type { CachedIndexPatternFetcher } from './lib/search_strategies/lib/cached_index_pattern_fetcher'; diff --git a/src/plugins/vis_type_timeseries/server/ui_settings.ts b/src/plugins/vis_types/timeseries/server/ui_settings.ts similarity index 61% rename from src/plugins/vis_type_timeseries/server/ui_settings.ts rename to src/plugins/vis_types/timeseries/server/ui_settings.ts index e61635058cee0..2adbc31482f04 100644 --- a/src/plugins/vis_type_timeseries/server/ui_settings.ts +++ b/src/plugins/vis_types/timeseries/server/ui_settings.ts @@ -10,11 +10,10 @@ import { i18n } from '@kbn/i18n'; import { schema } from '@kbn/config-schema'; import { UiSettingsParams } from 'kibana/server'; - -import { MAX_BUCKETS_SETTING } from '../common/constants'; +import { UI_SETTINGS } from '../common/constants'; export const getUiSettings: () => Record = () => ({ - [MAX_BUCKETS_SETTING]: { + [UI_SETTINGS.MAX_BUCKETS_SETTING]: { name: i18n.translate('visTypeTimeseries.advancedSettings.maxBucketsTitle', { defaultMessage: 'TSVB buckets limit', }), @@ -25,4 +24,16 @@ export const getUiSettings: () => Record = () => ({ }), schema: schema.number(), }, + [UI_SETTINGS.ALLOW_STRING_INDICES]: { + name: i18n.translate('visTypeTimeseries.advancedSettings.allowStringIndicesTitle', { + defaultMessage: 'Allow string indices in TSVB', + }), + value: false, + requiresPageReload: true, + description: i18n.translate('visTypeTimeseries.advancedSettings.allowStringIndicesText', { + defaultMessage: + 'Enables you to use index patterns and Elasticsearch indices in TSVB visualizations.', + }), + schema: schema.boolean(), + }, }); diff --git a/src/plugins/vis_type_timeseries/server/usage_collector/get_usage_collector.mock.ts b/src/plugins/vis_types/timeseries/server/usage_collector/get_usage_collector.mock.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/usage_collector/get_usage_collector.mock.ts rename to src/plugins/vis_types/timeseries/server/usage_collector/get_usage_collector.mock.ts diff --git a/src/plugins/vis_type_timeseries/server/usage_collector/get_usage_collector.test.ts b/src/plugins/vis_types/timeseries/server/usage_collector/get_usage_collector.test.ts similarity index 95% rename from src/plugins/vis_type_timeseries/server/usage_collector/get_usage_collector.test.ts rename to src/plugins/vis_types/timeseries/server/usage_collector/get_usage_collector.test.ts index 91daf09121f18..aac6d879f48fd 100644 --- a/src/plugins/vis_type_timeseries/server/usage_collector/get_usage_collector.test.ts +++ b/src/plugins/vis_types/timeseries/server/usage_collector/get_usage_collector.test.ts @@ -7,8 +7,11 @@ */ import { getStats } from './get_usage_collector'; -import { createCollectorFetchContextMock } from '../../../usage_collection/server/mocks'; -import type { SavedObjectsClientContract, SavedObjectsFindResponse } from '../../../../core/server'; +import { createCollectorFetchContextMock } from '../../../../usage_collection/server/mocks'; +import type { + SavedObjectsClientContract, + SavedObjectsFindResponse, +} from '../../../../../core/server'; import { TIME_RANGE_DATA_MODES } from '../../common/enums'; const mockedSavedObject = { diff --git a/src/plugins/vis_type_timeseries/server/usage_collector/get_usage_collector.ts b/src/plugins/vis_types/timeseries/server/usage_collector/get_usage_collector.ts similarity index 93% rename from src/plugins/vis_type_timeseries/server/usage_collector/get_usage_collector.ts rename to src/plugins/vis_types/timeseries/server/usage_collector/get_usage_collector.ts index a8d64afaf8cee..8309d51a9d56d 100644 --- a/src/plugins/vis_type_timeseries/server/usage_collector/get_usage_collector.ts +++ b/src/plugins/vis_types/timeseries/server/usage_collector/get_usage_collector.ts @@ -7,14 +7,14 @@ */ import { TIME_RANGE_DATA_MODES } from '../../common/enums'; -import { findByValueEmbeddables } from '../../../dashboard/server'; +import { findByValueEmbeddables } from '../../../../dashboard/server'; import type { SavedObjectsClientContract, ISavedObjectsRepository, SavedObjectsFindResult, -} from '../../../../core/server'; -import type { SavedVisState } from '../../../visualizations/common'; +} from '../../../../../core/server'; +import type { SavedVisState } from '../../../../visualizations/common'; export interface TimeseriesUsage { timeseries_use_last_value_mode_total: number; diff --git a/src/plugins/vis_type_timeseries/server/usage_collector/index.ts b/src/plugins/vis_types/timeseries/server/usage_collector/index.ts similarity index 100% rename from src/plugins/vis_type_timeseries/server/usage_collector/index.ts rename to src/plugins/vis_types/timeseries/server/usage_collector/index.ts diff --git a/src/plugins/vis_type_timeseries/server/usage_collector/register_timeseries_collector.test.ts b/src/plugins/vis_types/timeseries/server/usage_collector/register_timeseries_collector.test.ts similarity index 92% rename from src/plugins/vis_type_timeseries/server/usage_collector/register_timeseries_collector.test.ts rename to src/plugins/vis_types/timeseries/server/usage_collector/register_timeseries_collector.test.ts index 0dfe5ae5f9351..26a74821fe5ae 100644 --- a/src/plugins/vis_type_timeseries/server/usage_collector/register_timeseries_collector.test.ts +++ b/src/plugins/vis_types/timeseries/server/usage_collector/register_timeseries_collector.test.ts @@ -7,8 +7,8 @@ */ import { mockStats, mockGetStats } from './get_usage_collector.mock'; -import { createUsageCollectionSetupMock } from '../../../usage_collection/server/mocks'; -import { createCollectorFetchContextMock } from '../../../usage_collection/server/mocks'; +import { createUsageCollectionSetupMock } from '../../../../usage_collection/server/mocks'; +import { createCollectorFetchContextMock } from '../../../../usage_collection/server/mocks'; import { registerTimeseriesUsageCollector } from './register_timeseries_collector'; describe('registerTimeseriesUsageCollector', () => { diff --git a/src/plugins/vis_type_timeseries/server/usage_collector/register_timeseries_collector.ts b/src/plugins/vis_types/timeseries/server/usage_collector/register_timeseries_collector.ts similarity index 92% rename from src/plugins/vis_type_timeseries/server/usage_collector/register_timeseries_collector.ts rename to src/plugins/vis_types/timeseries/server/usage_collector/register_timeseries_collector.ts index 7e9294f03ba1c..6fccd7ef30171 100644 --- a/src/plugins/vis_type_timeseries/server/usage_collector/register_timeseries_collector.ts +++ b/src/plugins/vis_types/timeseries/server/usage_collector/register_timeseries_collector.ts @@ -7,7 +7,7 @@ */ import { getStats, TimeseriesUsage } from './get_usage_collector'; -import type { UsageCollectionSetup } from '../../../usage_collection/server'; +import type { UsageCollectionSetup } from '../../../../usage_collection/server'; export function registerTimeseriesUsageCollector(collectorSet: UsageCollectionSetup) { const collector = collectorSet.makeUsageCollector({ diff --git a/src/plugins/vis_types/timeseries/tsconfig.json b/src/plugins/vis_types/timeseries/tsconfig.json new file mode 100644 index 0000000000000..f336a467e0c81 --- /dev/null +++ b/src/plugins/vis_types/timeseries/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + "*.ts" + ], + "references": [ + { "path": "../../../core/tsconfig.json" }, + { "path": "../../charts/tsconfig.json" }, + { "path": "../../data/tsconfig.json" }, + { "path": "../../expressions/tsconfig.json" }, + { "path": "../../visualizations/tsconfig.json" }, + { "path": "../../visualize/tsconfig.json" }, + { "path": "../../kibana_utils/tsconfig.json" }, + { "path": "../../kibana_react/tsconfig.json" }, + { "path": "../../usage_collection/tsconfig.json" }, + ] +} diff --git a/src/plugins/vis_types/vega/public/components/deprecated_interval_info.test.tsx b/src/plugins/vis_types/vega/public/components/deprecated_interval_info.test.tsx new file mode 100644 index 0000000000000..d88cf279881b3 --- /dev/null +++ b/src/plugins/vis_types/vega/public/components/deprecated_interval_info.test.tsx @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { shouldShowDeprecatedHistogramIntervalInfo } from './deprecated_interval_info'; + +describe('shouldShowDeprecatedHistogramIntervalInfo', () => { + test('should show deprecated histogram interval', () => { + expect( + shouldShowDeprecatedHistogramIntervalInfo({ + data: { + url: { + body: { + aggs: { + test: { + date_histogram: { + interval: 'day', + }, + }, + }, + }, + }, + }, + }) + ).toBeTruthy(); + + expect( + shouldShowDeprecatedHistogramIntervalInfo({ + data: [ + { + url: { + body: { + aggs: { + test: { + date_histogram: { + interval: 'day', + }, + }, + }, + }, + }, + }, + { + url: { + body: { + aggs: { + test: { + date_histogram: { + calendar_interval: 'day', + }, + }, + }, + }, + }, + }, + ], + }) + ).toBeTruthy(); + }); + + test('should not show deprecated histogram interval', () => { + expect( + shouldShowDeprecatedHistogramIntervalInfo({ + data: { + url: { + body: { + aggs: { + test: { + date_histogram: { + interval: { '%autointerval%': true }, + }, + }, + }, + }, + }, + }, + }) + ).toBeFalsy(); + + expect( + shouldShowDeprecatedHistogramIntervalInfo({ + data: { + url: { + body: { + aggs: { + test: { + auto_date_histogram: { + field: 'bytes', + }, + }, + }, + }, + }, + }, + }) + ).toBeFalsy(); + + expect( + shouldShowDeprecatedHistogramIntervalInfo({ + data: [ + { + url: { + body: { + aggs: { + test: { + date_histogram: { + calendar_interval: 'week', + }, + }, + }, + }, + }, + }, + { + url: { + body: { + aggs: { + test: { + date_histogram: { + fixed_interval: '23d', + }, + }, + }, + }, + }, + }, + ], + }) + ).toBeFalsy(); + }); +}); diff --git a/src/plugins/vis_types/vega/public/components/deprecated_interval_info.tsx b/src/plugins/vis_types/vega/public/components/deprecated_interval_info.tsx new file mode 100644 index 0000000000000..23144a4c2084d --- /dev/null +++ b/src/plugins/vis_types/vega/public/components/deprecated_interval_info.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { EuiCallOut, EuiButtonIcon } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { VegaSpec } from '../data_model/types'; +import { getDocLinks } from '../services'; + +import { BUCKET_TYPES } from '../../../../data/public'; + +export const DeprecatedHistogramIntervalInfo = () => ( + + ), + }} + /> + } + iconType="help" + /> +); + +export const shouldShowDeprecatedHistogramIntervalInfo = (spec: VegaSpec) => { + const data = Array.isArray(spec.data) ? spec?.data : [spec.data]; + + return data.some((dataItem = {}) => { + const aggs = dataItem.url?.body?.aggs ?? {}; + + return Object.keys(aggs).some((key) => { + const dateHistogram = aggs[key]?.[BUCKET_TYPES.DATE_HISTOGRAM] || {}; + return 'interval' in dateHistogram && typeof dateHistogram.interval !== 'object'; + }); + }); +}; diff --git a/src/plugins/vis_types/vega/public/components/experimental_map_vis_info.tsx b/src/plugins/vis_types/vega/public/components/experimental_map_vis_info.tsx index 2de6eb490196c..8a1f2c2794974 100644 --- a/src/plugins/vis_types/vega/public/components/experimental_map_vis_info.tsx +++ b/src/plugins/vis_types/vega/public/components/experimental_map_vis_info.tsx @@ -6,55 +6,37 @@ * Side Public License, v 1. */ -import { parse } from 'hjson'; import React from 'react'; import { EuiCallOut, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Vis } from '../../../../visualizations/public'; -function ExperimentalMapLayerInfo() { - const title = ( - - GitHub - - ), - }} - /> - ); - - return ( - - ); -} +import type { VegaSpec } from '../data_model/types'; -export const getInfoMessage = (vis: Vis) => { - if (vis.params.spec) { - try { - const spec = parse(vis.params.spec, { legacyRoot: false, keepWsc: true }); - - if (spec.config?.kibana?.type === 'map') { - return ; - } - } catch (e) { - // spec is invalid +export const ExperimentalMapLayerInfo = () => ( + + GitHub + + ), + }} + /> } - } + iconType="beaker" + /> +); - return null; -}; +export const shouldShowMapLayerInfo = (spec: VegaSpec) => spec.config?.kibana?.type === 'map'; diff --git a/src/plugins/vis_types/vega/public/components/vega_info_message.tsx b/src/plugins/vis_types/vega/public/components/vega_info_message.tsx new file mode 100644 index 0000000000000..265613ef1e6ce --- /dev/null +++ b/src/plugins/vis_types/vega/public/components/vega_info_message.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { useMemo } from 'react'; +import { parse } from 'hjson'; +import { ExperimentalMapLayerInfo, shouldShowMapLayerInfo } from './experimental_map_vis_info'; +import { + DeprecatedHistogramIntervalInfo, + shouldShowDeprecatedHistogramIntervalInfo, +} from './deprecated_interval_info'; + +import type { Vis } from '../../../../visualizations/public'; +import type { VegaSpec } from '../data_model/types'; + +const parseSpec = (spec: string) => { + if (spec) { + try { + return parse(spec, { legacyRoot: false, keepWsc: true }); + } catch (e) { + // spec is invalid + } + } +}; + +const InfoMessage = ({ spec }: { spec: string }) => { + const vegaSpec: VegaSpec = useMemo(() => parseSpec(spec), [spec]); + + if (!vegaSpec) { + return null; + } + + return ( + <> + {shouldShowMapLayerInfo(vegaSpec) && } + {shouldShowDeprecatedHistogramIntervalInfo(vegaSpec) && } + + ); +}; + +export const getInfoMessage = (vis: Vis) => ; diff --git a/src/plugins/vis_types/vega/public/data_model/es_query_parser.test.js b/src/plugins/vis_types/vega/public/data_model/es_query_parser.test.js index 27ed5aa18a96d..bb3c0276f4cf9 100644 --- a/src/plugins/vis_types/vega/public/data_model/es_query_parser.test.js +++ b/src/plugins/vis_types/vega/public/data_model/es_query_parser.test.js @@ -178,11 +178,11 @@ describe(`EsQueryParser.injectQueryContextVars`, () => { ); test( `%autointerval% = true`, - check({ interval: { '%autointerval%': true } }, { interval: `1h` }, ctxObj) + check({ interval: { '%autointerval%': true } }, { calendar_interval: `1h` }, ctxObj) ); test( `%autointerval% = 10`, - check({ interval: { '%autointerval%': 10 } }, { interval: `3h` }, ctxObj) + check({ interval: { '%autointerval%': 10 } }, { fixed_interval: `3h` }, ctxObj) ); test(`%timefilter% = min`, check({ a: { '%timefilter%': 'min' } }, { a: rangeStart })); test(`%timefilter% = max`, check({ a: { '%timefilter%': 'max' } }, { a: rangeEnd })); diff --git a/src/plugins/vis_types/vega/public/data_model/es_query_parser.ts b/src/plugins/vis_types/vega/public/data_model/es_query_parser.ts index d0c63b8f2a6a0..134e82d676763 100644 --- a/src/plugins/vis_types/vega/public/data_model/es_query_parser.ts +++ b/src/plugins/vis_types/vega/public/data_model/es_query_parser.ts @@ -10,6 +10,7 @@ import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { cloneDeep, isPlainObject } from 'lodash'; import type { estypes } from '@elastic/elasticsearch'; +import { Assign } from 'utility-types'; import { TimeCache } from './time_cache'; import { SearchAPI } from './search_api'; import { @@ -22,6 +23,7 @@ import { Query, ContextVarsObject, } from './types'; +import { dateHistogramInterval } from '../../../../data/common'; const TIMEFILTER: string = '%timefilter%'; const AUTOINTERVAL: string = '%autointerval%'; @@ -226,7 +228,15 @@ export class EsQueryParser { * @param {*} obj * @param {boolean} isQuery - if true, the `obj` belongs to the req's query portion */ - _injectContextVars(obj: Query | estypes.SearchRequest['body']['aggs'], isQuery: boolean) { + _injectContextVars( + obj: Assign< + Query | estypes.SearchRequest['body']['aggs'], + { + interval?: { '%autointerval%': true | number } | string; + } + >, + isQuery: boolean + ) { if (obj && typeof obj === 'object') { if (Array.isArray(obj)) { // For arrays, replace MUST_CLAUSE and MUST_NOT_CLAUSE string elements @@ -270,27 +280,33 @@ export class EsQueryParser { const subObj = (obj as ContextVarsObject)[prop]; if (!subObj || typeof obj !== 'object') continue; - // replace "interval": { "%autointerval%": true|integer } with - // auto-generated range based on the timepicker - if (prop === 'interval' && subObj[AUTOINTERVAL]) { - let size = subObj[AUTOINTERVAL]; - if (size === true) { - size = 50; // by default, try to get ~80 values - } else if (typeof size !== 'number') { - throw new Error( - i18n.translate('visTypeVega.esQueryParser.autointervalValueTypeErrorMessage', { - defaultMessage: '{autointerval} must be either {trueValue} or a number', - values: { - autointerval: `"${AUTOINTERVAL}"`, - trueValue: 'true', - }, - }) - ); + // replace "interval" with ES acceptable fixed_interval / calendar_interval + if (prop === 'interval') { + let intervalString: string; + + if (typeof subObj === 'string') { + intervalString = subObj; + } else if (subObj[AUTOINTERVAL]) { + let size = subObj[AUTOINTERVAL]; + if (size === true) { + size = 50; // by default, try to get ~80 values + } else if (typeof size !== 'number') { + throw new Error( + i18n.translate('visTypeVega.esQueryParser.autointervalValueTypeErrorMessage', { + defaultMessage: '{autointerval} must be either {trueValue} or a number', + values: { + autointerval: `"${AUTOINTERVAL}"`, + trueValue: 'true', + }, + }) + ); + } + const { max, min } = this._timeCache.getTimeBounds(); + intervalString = EsQueryParser._roundInterval((max - min) / size); } - const bounds = this._timeCache.getTimeBounds(); - (obj as ContextVarsObject).interval = EsQueryParser._roundInterval( - (bounds.max - bounds.min) / size - ); + + Object.assign(obj, dateHistogramInterval(intervalString)); + delete obj.interval; continue; } diff --git a/src/plugins/vis_types/vega/public/data_model/search_api.ts b/src/plugins/vis_types/vega/public/data_model/search_api.ts index e00cf647930a8..11302ad65d56b 100644 --- a/src/plugins/vis_types/vega/public/data_model/search_api.ts +++ b/src/plugins/vis_types/vega/public/data_model/search_api.ts @@ -95,7 +95,16 @@ export class SearchAPI { } ) .pipe( - tap((data) => this.inspectSearchResult(data, requestResponders[requestId])), + tap( + (data) => this.inspectSearchResult(data, requestResponders[requestId]), + (err) => + this.inspectSearchResult( + { + rawResponse: err?.err, + }, + requestResponders[requestId] + ) + ), map((data) => ({ name: requestId, rawResponse: data.rawResponse, diff --git a/src/plugins/vis_types/vega/public/data_model/types.ts b/src/plugins/vis_types/vega/public/data_model/types.ts index 75b1132176d67..d1568bba6c98c 100644 --- a/src/plugins/vis_types/vega/public/data_model/types.ts +++ b/src/plugins/vis_types/vega/public/data_model/types.ts @@ -192,7 +192,6 @@ export type EmsQueryRequest = Requests & { export interface ContextVarsObject { [index: string]: any; prop: ContextVarsObjectProps; - interval: string; } export interface TooltipConfig { diff --git a/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js b/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js index be356ea4e05ce..cfeed174307ac 100644 --- a/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js +++ b/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js @@ -5,8 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - import { cloneDeep } from 'lodash'; +import 'jest-canvas-mock'; import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; import { VegaParser } from './vega_parser'; import { bypassExternalUrlCheck } from '../vega_view/vega_base_view'; diff --git a/src/plugins/vis_types/vega/public/vega_type.ts b/src/plugins/vis_types/vega/public/vega_type.ts index 74899f5cfb3a4..23f0e385d2b33 100644 --- a/src/plugins/vis_types/vega/public/vega_type.ts +++ b/src/plugins/vis_types/vega/public/vega_type.ts @@ -16,7 +16,7 @@ import { getDefaultSpec } from './default_spec'; import { extractIndexPatternsFromSpec } from './lib/extract_index_pattern'; import { createInspectorAdapters } from './vega_inspector'; import { toExpressionAst } from './to_ast'; -import { getInfoMessage } from './components/experimental_map_vis_info'; +import { getInfoMessage } from './components/vega_info_message'; import { VegaVisEditorComponent } from './components/vega_vis_editor_lazy'; import type { VisParams } from './vega_fn'; diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/map_service_settings.ts b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/map_service_settings.ts index 3399d0628ad65..9772e693358b6 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/map_service_settings.ts +++ b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/map_service_settings.ts @@ -66,6 +66,11 @@ export class MapServiceSettings { tileApiUrl: this.config.emsTileApiUrl, landingPageUrl: this.config.emsLandingPageUrl, }); + + // Allow zooms > 10 for Vega Maps + // any kibana user, regardless of distribution, should get all zoom levels + // use `sspl` license to indicate this + this.emsClient.addQueryParams({ license: 'sspl' }); } public async getTmsService(tmsTileLayer: string) { diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.test.ts b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.test.ts index d3d0b6cb0411e..8ca2b2bd26eed 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.test.ts +++ b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.test.ts @@ -124,6 +124,8 @@ describe('vega_map_view/view', () => { } as unknown as VegaViewParams); } + let mockedConsoleLog: jest.SpyInstance; + beforeEach(() => { vegaParser = new VegaParser( JSON.stringify(vegaMap), @@ -137,10 +139,13 @@ describe('vega_map_view/view', () => { {}, mockGetServiceSettings ); + mockedConsoleLog = jest.spyOn(console, 'log'); // mocked console.log to avoid messages in the console when running tests + mockedConsoleLog.mockImplementation(() => {}); // comment this line when console logging for debugging }); afterEach(() => { jest.clearAllMocks(); + mockedConsoleLog.mockRestore(); }); test('should be added TmsRasterLayer and do not use tmsService if mapStyle is "user_configured"', async () => { diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts index cf5bf15d15051..777806d90d9a6 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts +++ b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts @@ -72,7 +72,7 @@ export class VegaMapView extends VegaBaseView { const { zoom, maxZoom, minZoom } = validateZoomSettings( this._parser.mapConfig, defaults, - this.onWarn + this.onWarn.bind(this) ); const { signals } = this._vegaStateRestorer.restore() || {}; diff --git a/src/plugins/vis_types/vega/public/vega_visualization.test.js b/src/plugins/vis_types/vega/public/vega_visualization.test.js index 05a88880822ca..dd76e2d470004 100644 --- a/src/plugins/vis_types/vega/public/vega_visualization.test.js +++ b/src/plugins/vis_types/vega/public/vega_visualization.test.js @@ -81,7 +81,11 @@ describe('VegaVisualizations', () => { mockWidth.mockRestore(); mockHeight.mockRestore(); }); + test('should show vegalite graph and update on resize (may fail in dev env)', async () => { + const mockedConsoleLog = jest.spyOn(console, 'log'); // mocked console.log to avoid messages in the console when running tests + mockedConsoleLog.mockImplementation(() => {}); // comment this line when console logging for debugging comment this line + let vegaVis; try { vegaVis = new VegaVisualization(domNode, jest.fn()); @@ -111,6 +115,8 @@ describe('VegaVisualizations', () => { } finally { vegaVis.destroy(); } + expect(console.log).toBeCalledTimes(2); + mockedConsoleLog.mockRestore(); }); test('should show vega graph (may fail in dev env)', async () => { @@ -130,7 +136,6 @@ describe('VegaVisualizations', () => { mockGetServiceSettings ); await vegaParser.parseAsync(); - await vegaVis.render(vegaParser); expect(domNode.innerHTML).toMatchSnapshot(); } finally { diff --git a/src/plugins/vis_types/vega/server/index.ts b/src/plugins/vis_types/vega/server/index.ts index 156dec027372a..9c448f6c618d3 100644 --- a/src/plugins/vis_types/vega/server/index.ts +++ b/src/plugins/vis_types/vega/server/index.ts @@ -16,10 +16,6 @@ export const config: PluginConfigDescriptor = { enableExternalUrls: true, }, schema: configSchema, - deprecations: ({ renameFromRoot }) => [ - renameFromRoot('vega.enableExternalUrls', 'vis_type_vega.enableExternalUrls'), - renameFromRoot('vega.enabled', 'vis_type_vega.enabled'), - ], }; export function plugin(initializerContext: PluginInitializerContext) { diff --git a/src/plugins/vis_types/xy/config.ts b/src/plugins/vis_types/xy/config.ts new file mode 100644 index 0000000000000..b831d26854c30 --- /dev/null +++ b/src/plugins/vis_types/xy/config.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +export const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), +}); + +export type ConfigSchema = TypeOf; diff --git a/src/plugins/vis_types/xy/kibana.json b/src/plugins/vis_types/xy/kibana.json index 1666a346e3482..1606af5944ad3 100644 --- a/src/plugins/vis_types/xy/kibana.json +++ b/src/plugins/vis_types/xy/kibana.json @@ -2,7 +2,7 @@ "id": "visTypeXy", "version": "kibana", "ui": true, - "server": false, + "server": true, "requiredPlugins": ["charts", "data", "expressions", "visualizations", "usageCollection"], "requiredBundles": ["kibanaUtils", "visDefaultEditor"], "extraPublicDirs": ["common/index"], diff --git a/src/plugins/vis_types/xy/public/utils/accessors.test.ts b/src/plugins/vis_types/xy/public/utils/accessors.test.ts index 61d175fa8ff7d..06920ceebe980 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.test.ts +++ b/src/plugins/vis_types/xy/public/utils/accessors.test.ts @@ -6,7 +6,11 @@ * Side Public License, v 1. */ -import { COMPLEX_SPLIT_ACCESSOR, getComplexAccessor } from './accessors'; +import { + COMPLEX_SPLIT_ACCESSOR, + getComplexAccessor, + isPercentileIdEqualToSeriesId, +} from './accessors'; import { BUCKET_TYPES } from '../../../../data/common'; import { AccessorFn, Datum } from '@elastic/charts'; @@ -99,3 +103,37 @@ describe('XY chart datum accessors', () => { expect(accessor).toBeUndefined(); }); }); + +describe('isPercentileIdEqualToSeriesId', () => { + it('should be equal for plain column ids', () => { + const seriesColumnId = 'col-0-1'; + const columnId = `${seriesColumnId}`; + + const isEqual = isPercentileIdEqualToSeriesId(columnId, seriesColumnId); + expect(isEqual).toBeTruthy(); + }); + + it('should be equal for column with percentile', () => { + const seriesColumnId = '1'; + const columnId = `${seriesColumnId}.95`; + + const isEqual = isPercentileIdEqualToSeriesId(columnId, seriesColumnId); + expect(isEqual).toBeTruthy(); + }); + + it('should not be equal for column with percentile equal to seriesColumnId', () => { + const seriesColumnId = '1'; + const columnId = `2.1`; + + const isEqual = isPercentileIdEqualToSeriesId(columnId, seriesColumnId); + expect(isEqual).toBeFalsy(); + }); + + it('should not be equal for column with percentile, where columnId contains seriesColumnId', () => { + const seriesColumnId = '1'; + const columnId = `${seriesColumnId}2.1`; + + const isEqual = isPercentileIdEqualToSeriesId(columnId, seriesColumnId); + expect(isEqual).toBeFalsy(); + }); +}); diff --git a/src/plugins/vis_types/xy/public/utils/accessors.tsx b/src/plugins/vis_types/xy/public/utils/accessors.tsx index 9566f819ba145..2b552c9f3f9cf 100644 --- a/src/plugins/vis_types/xy/public/utils/accessors.tsx +++ b/src/plugins/vis_types/xy/public/utils/accessors.tsx @@ -9,7 +9,7 @@ import { AccessorFn, Accessor } from '@elastic/charts'; import { BUCKET_TYPES } from '../../../../data/public'; import { FakeParams } from '../../../../visualizations/public'; -import { Aspect } from '../types'; +import type { Aspect } from '../types'; export const COMPLEX_X_ACCESSOR = '__customXAccessor__'; export const COMPLEX_SPLIT_ACCESSOR = '__complexSplitAccessor__'; @@ -77,3 +77,11 @@ export const getSplitSeriesAccessorFnMap = ( return m; }; + +// For percentile, the aggregation id is coming in the form %s.%d, where %s is agg_id and %d - percents +export const isPercentileIdEqualToSeriesId = (columnId: number | string, seriesColumnId: string) => + columnId.toString().split('.')[0] === seriesColumnId; + +export const isValidSeriesForDimension = (seriesColumnId: string, { aggId, accessor }: Aspect) => + (aggId === seriesColumnId || isPercentileIdEqualToSeriesId(aggId ?? '', seriesColumnId)) && + accessor !== null; diff --git a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx index f8ca1d059ae4f..c248b3b86e42a 100644 --- a/src/plugins/vis_types/xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_types/xy/public/utils/render_all_series.tsx @@ -22,10 +22,10 @@ import { } from '@elastic/charts'; import { DatatableRow } from '../../../../expressions/public'; -import { METRIC_TYPES } from '../../../../data/public'; import { ChartType } from '../../common'; import { SeriesParam, VisConfig } from '../types'; +import { isValidSeriesForDimension } from './accessors'; /** * Matches vislib curve to elastic charts @@ -82,17 +82,7 @@ export const renderAllSeries = ( interpolate, type, }) => { - const yAspects = aspects.y.filter(({ aggId, aggType, accessor }) => { - if ( - aggType === METRIC_TYPES.PERCENTILES || - aggType === METRIC_TYPES.PERCENTILE_RANKS || - aggType === METRIC_TYPES.STD_DEV - ) { - return aggId?.includes(paramId) && accessor !== null; - } else { - return aggId === paramId && accessor !== null; - } - }); + const yAspects = aspects.y.filter((aspect) => isValidSeriesForDimension(paramId, aspect)); if (!show || !yAspects.length) { return null; } diff --git a/src/plugins/vis_types/xy/server/index.ts b/src/plugins/vis_types/xy/server/index.ts new file mode 100644 index 0000000000000..9dfa405ee27b8 --- /dev/null +++ b/src/plugins/vis_types/xy/server/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginConfigDescriptor } from 'src/core/server'; +import { configSchema, ConfigSchema } from '../config'; +import { VisTypeXYServerPlugin } from './plugin'; + +export const config: PluginConfigDescriptor = { + schema: configSchema, +}; + +export const plugin = () => new VisTypeXYServerPlugin(); diff --git a/src/plugins/data/common/data_views/lib/is_default.ts b/src/plugins/vis_types/xy/server/plugin.ts similarity index 65% rename from src/plugins/data/common/data_views/lib/is_default.ts rename to src/plugins/vis_types/xy/server/plugin.ts index 5a50d2862c58b..5cb0687cf1889 100644 --- a/src/plugins/data/common/data_views/lib/is_default.ts +++ b/src/plugins/vis_types/xy/server/plugin.ts @@ -6,9 +6,14 @@ * Side Public License, v 1. */ -import { IIndexPattern } from '../..'; +import { Plugin } from 'src/core/server'; -export const isDefault = (indexPattern: IIndexPattern) => { - // Default index patterns don't have `type` defined. - return !indexPattern.type; -}; +export class VisTypeXYServerPlugin implements Plugin { + public setup() { + return {}; + } + + public start() { + return {}; + } +} diff --git a/src/plugins/vis_types/xy/tsconfig.json b/src/plugins/vis_types/xy/tsconfig.json index f1f65b6218e82..ab3f3d1252ed8 100644 --- a/src/plugins/vis_types/xy/tsconfig.json +++ b/src/plugins/vis_types/xy/tsconfig.json @@ -9,7 +9,8 @@ "include": [ "common/**/*", "public/**/*", - "server/**/*" + "server/**/*", + "*.ts" ], "references": [ { "path": "../../../core/tsconfig.json" }, diff --git a/src/plugins/visualizations/server/saved_objects/visualization.ts b/src/plugins/visualizations/server/saved_objects/visualization.ts index 880e277294fc3..53027d5d5046c 100644 --- a/src/plugins/visualizations/server/saved_objects/visualization.ts +++ b/src/plugins/visualizations/server/saved_objects/visualization.ts @@ -20,9 +20,6 @@ export const visualizationSavedObjectType: SavedObjectsType = { getTitle(obj) { return obj.attributes.title; }, - getEditUrl(obj) { - return `/management/kibana/objects/savedVisualizations/${encodeURIComponent(obj.id)}`; - }, getInAppUrl(obj) { return { path: `/app/visualize#/edit/${encodeURIComponent(obj.id)}`, diff --git a/src/plugins/visualize/public/application/components/visualize_no_match.tsx b/src/plugins/visualize/public/application/components/visualize_no_match.tsx index 3b735eb23671c..ad993af430086 100644 --- a/src/plugins/visualize/public/application/components/visualize_no_match.tsx +++ b/src/plugins/visualize/public/application/components/visualize_no_match.tsx @@ -24,7 +24,7 @@ export const VisualizeNoMatch = () => { services.restorePreviousUrl(); const { navigated } = services.urlForwarding.navigateToLegacyKibanaUrl( - services.history.location.pathname + services.history.location.pathname + services.history.location.search ); if (!navigated) { diff --git a/src/plugins/visualize/public/application/utils/get_table_columns.tsx b/src/plugins/visualize/public/application/utils/get_table_columns.tsx index 8c8ecaf9a448a..69383005deb07 100644 --- a/src/plugins/visualize/public/application/utils/get_table_columns.tsx +++ b/src/plugins/visualize/public/application/utils/get_table_columns.tsx @@ -8,7 +8,15 @@ import React from 'react'; import { METRIC_TYPE } from '@kbn/analytics'; -import { EuiBetaBadge, EuiButton, EuiEmptyPrompt, EuiIcon, EuiLink, EuiBadge } from '@elastic/eui'; +import { + EuiBetaBadge, + EuiButton, + EuiEmptyPrompt, + EuiIcon, + EuiLink, + EuiBadge, + EuiBasicTableColumn, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ApplicationStart } from 'kibana/public'; @@ -86,61 +94,62 @@ export const getTableColumns = ( application: ApplicationStart, kbnUrlStateStorage: IKbnUrlStateStorage, taggingApi?: SavedObjectsTaggingApi -) => [ - { - field: 'title', - name: i18n.translate('visualize.listing.table.titleColumnName', { - defaultMessage: 'Title', - }), - sortable: true, - render: (field: string, { editApp, editUrl, title, error, type }: VisualizationListItem) => - // In case an error occurs i.e. the vis has wrong type, we render the vis but without the link - !error ? ( - - {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} - { - doTelemetryForAddEvent(typeof type === 'string' ? type : type?.name); - }} - data-test-subj={`visListingTitleLink-${title.split(' ').join('-')}`} - > - {field} - - - ) : ( - field - ), - }, - { - field: 'typeTitle', - name: i18n.translate('visualize.listing.table.typeColumnName', { - defaultMessage: 'Type', - }), - sortable: true, - render: (field: string, record: VisualizationListItem) => - !record.error ? ( - - {renderItemTypeIcon(record)} - {record.typeTitle} - {getBadge(record)} - - ) : ( - - {record.error} - - ), - }, - { - field: 'description', - name: i18n.translate('visualize.listing.table.descriptionColumnName', { - defaultMessage: 'Description', - }), - sortable: true, - render: (field: string, record: VisualizationListItem) => {record.description}, - }, - ...(taggingApi ? [taggingApi.ui.getTableColumnDefinition()] : []), -]; +) => + [ + { + field: 'title', + name: i18n.translate('visualize.listing.table.titleColumnName', { + defaultMessage: 'Title', + }), + sortable: true, + render: (field: string, { editApp, editUrl, title, error, type }: VisualizationListItem) => + // In case an error occurs i.e. the vis has wrong type, we render the vis but without the link + !error ? ( + + {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} + { + doTelemetryForAddEvent(typeof type === 'string' ? type : type?.name); + }} + data-test-subj={`visListingTitleLink-${title.split(' ').join('-')}`} + > + {field} + + + ) : ( + field + ), + }, + { + field: 'typeTitle', + name: i18n.translate('visualize.listing.table.typeColumnName', { + defaultMessage: 'Type', + }), + sortable: true, + render: (field: string, record: VisualizationListItem) => + !record.error ? ( + + {renderItemTypeIcon(record)} + {record.typeTitle} + {getBadge(record)} + + ) : ( + + {record.error} + + ), + }, + { + field: 'description', + name: i18n.translate('visualize.listing.table.descriptionColumnName', { + defaultMessage: 'Description', + }), + sortable: true, + render: (field: string, record: VisualizationListItem) => {record.description}, + }, + ...(taggingApi ? [taggingApi.ui.getTableColumnDefinition()] : []), + ] as unknown as Array>>; export const getNoItemsMessage = (createItem: () => void) => ( { + describe.skip('Dashboard', () => { const dashboardName = 'Dashboard Listing A11y'; const clonedDashboardName = 'Dashboard Listing A11y Copy'; diff --git a/test/api_integration/apis/custom_integration/index.ts b/test/api_integration/apis/custom_integration/index.ts new file mode 100644 index 0000000000000..d3d34fc3ccfce --- /dev/null +++ b/test/api_integration/apis/custom_integration/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('custom integrations', () => { + loadTestFile(require.resolve('./integrations')); + }); +} diff --git a/test/api_integration/apis/custom_integration/integrations.ts b/test/api_integration/apis/custom_integration/integrations.ts new file mode 100644 index 0000000000000..d8f098fdc1fcf --- /dev/null +++ b/test/api_integration/apis/custom_integration/integrations.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('get list of append integrations', () => { + it('should return list of custom integrations that can be appended', async () => { + const resp = await supertest + .get(`/api/customIntegrations/appendCustomIntegrations`) + .set('kbn-xsrf', 'kibana') + .expect(200); + + expect(resp.body).to.be.an('array'); + expect(resp.body.length).to.be.above(0); + }); + }); +} diff --git a/test/api_integration/apis/index.ts b/test/api_integration/apis/index.ts index 998c0b834d224..a6b8b746f68cf 100644 --- a/test/api_integration/apis/index.ts +++ b/test/api_integration/apis/index.ts @@ -12,6 +12,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('apis', () => { loadTestFile(require.resolve('./console')); loadTestFile(require.resolve('./core')); + loadTestFile(require.resolve('./custom_integration')); loadTestFile(require.resolve('./general')); loadTestFile(require.resolve('./home')); loadTestFile(require.resolve('./index_pattern_field_editor')); diff --git a/test/api_integration/apis/saved_objects_management/find.ts b/test/api_integration/apis/saved_objects_management/find.ts index f3f4b56cdccf5..9a5f94f9d8b9d 100644 --- a/test/api_integration/apis/saved_objects_management/find.ts +++ b/test/api_integration/apis/saved_objects_management/find.ts @@ -180,8 +180,6 @@ export default function ({ getService }: FtrProviderContext) { icon: 'discoverApp', title: 'OneRecord', hiddenType: false, - editUrl: - '/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'discover.show', @@ -200,8 +198,6 @@ export default function ({ getService }: FtrProviderContext) { icon: 'dashboardApp', title: 'Dashboard', hiddenType: false, - editUrl: - '/management/kibana/objects/savedDashboards/b70c7ae0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'dashboard.show', @@ -220,8 +216,6 @@ export default function ({ getService }: FtrProviderContext) { icon: 'visualizeApp', title: 'VisualizationFromSavedSearch', hiddenType: false, - editUrl: - '/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', @@ -232,8 +226,6 @@ export default function ({ getService }: FtrProviderContext) { icon: 'visualizeApp', title: 'Visualization', hiddenType: false, - editUrl: - '/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', diff --git a/test/api_integration/apis/saved_objects_management/relationships.ts b/test/api_integration/apis/saved_objects_management/relationships.ts index 5fbd5cad8ec84..8ee5005348bcd 100644 --- a/test/api_integration/apis/saved_objects_management/relationships.ts +++ b/test/api_integration/apis/saved_objects_management/relationships.ts @@ -21,7 +21,7 @@ export default function ({ getService }: FtrProviderContext) { meta: schema.object({ title: schema.string(), icon: schema.string(), - editUrl: schema.string(), + editUrl: schema.maybe(schema.string()), inAppUrl: schema.object({ path: schema.string(), uiCapabilitiesPath: schema.string(), @@ -103,8 +103,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { title: 'VisualizationFromSavedSearch', icon: 'visualizeApp', - editUrl: - '/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', @@ -147,8 +145,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'visualizeApp', title: 'VisualizationFromSavedSearch', - editUrl: - '/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', @@ -192,8 +188,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'visualizeApp', title: 'Visualization', - editUrl: - '/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', @@ -209,8 +203,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'visualizeApp', title: 'VisualizationFromSavedSearch', - editUrl: - '/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', @@ -234,8 +226,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'visualizeApp', title: 'Visualization', - editUrl: - '/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', @@ -251,8 +241,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'visualizeApp', title: 'VisualizationFromSavedSearch', - editUrl: - '/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', @@ -296,8 +284,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'discoverApp', title: 'OneRecord', - editUrl: - '/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'discover.show', @@ -313,8 +299,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'dashboardApp', title: 'Dashboard', - editUrl: - '/management/kibana/objects/savedDashboards/b70c7ae0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'dashboard.show', @@ -340,8 +324,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'discoverApp', title: 'OneRecord', - editUrl: - '/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'discover.show', @@ -385,8 +367,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'discoverApp', title: 'OneRecord', - editUrl: - '/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'discover.show', @@ -402,8 +382,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'visualizeApp', title: 'Visualization', - editUrl: - '/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'visualize.show', @@ -429,8 +407,6 @@ export default function ({ getService }: FtrProviderContext) { meta: { icon: 'discoverApp', title: 'OneRecord', - editUrl: - '/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357', inAppUrl: { path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357', uiCapabilitiesPath: 'discover.show', @@ -475,8 +451,6 @@ export default function ({ getService }: FtrProviderContext) { { id: 'add810b0-3224-11e8-a572-ffca06da1357', meta: { - editUrl: - '/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357', icon: 'visualizeApp', inAppUrl: { path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357', diff --git a/test/examples/config.js b/test/examples/config.js index ee0c3b63b55c1..c2930068b631f 100644 --- a/test/examples/config.js +++ b/test/examples/config.js @@ -32,6 +32,7 @@ export default async function ({ readConfigFile }) { require.resolve('./expressions_explorer'), require.resolve('./index_pattern_field_editor_example'), require.resolve('./field_formats'), + require.resolve('./partial_results'), ], services: { ...functionalConfig.get('services'), diff --git a/test/examples/partial_results/index.ts b/test/examples/partial_results/index.ts new file mode 100644 index 0000000000000..8fb2824163024 --- /dev/null +++ b/test/examples/partial_results/index.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from 'test/functional/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common']); + + describe('Partial Results Example', function () { + before(async () => { + this.tags('ciGroup2'); + await PageObjects.common.navigateToApp('partialResultsExample'); + + const element = await testSubjects.find('example-help'); + + await element.click(); + await element.click(); + await element.click(); + }); + + it('should trace mouse events', async () => { + const events = await Promise.all( + ( + await testSubjects.findAll('example-column-event') + ).map((wrapper) => wrapper.getVisibleText()) + ); + expect(events).to.eql(['mousedown', 'mouseup', 'click']); + }); + + it('should keep track of the events number', async () => { + const counters = await Promise.all( + ( + await testSubjects.findAll('example-column-count') + ).map((wrapper) => wrapper.getVisibleText()) + ); + expect(counters).to.eql(['3', '3', '3']); + }); + }); +} diff --git a/test/functional/apps/dashboard/bwc_shared_urls.ts b/test/functional/apps/dashboard/bwc_shared_urls.ts index d40cf03327fd3..569cd8e2a67d5 100644 --- a/test/functional/apps/dashboard/bwc_shared_urls.ts +++ b/test/functional/apps/dashboard/bwc_shared_urls.ts @@ -86,6 +86,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('6.0 urls', () => { + let savedDashboardId: string; + it('loads an unsaved dashboard', async function () { const url = `${kibanaLegacyBaseUrl}#/dashboard?${urlQuery}`; log.debug(`Navigating to ${url}`); @@ -106,8 +108,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { storeTimeWithDashboard: true, }); - const id = await PageObjects.dashboard.getDashboardIdFromCurrentUrl(); - const url = `${kibanaLegacyBaseUrl}#/dashboard/${id}`; + savedDashboardId = await PageObjects.dashboard.getDashboardIdFromCurrentUrl(); + const url = `${kibanaLegacyBaseUrl}#/dashboard/${savedDashboardId}`; log.debug(`Navigating to ${url}`); await browser.get(url, true); await PageObjects.header.waitUntilLoadingHasFinished(); @@ -121,6 +123,22 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardExpect.selectedLegendColorCount('#F9D9F9', 5); }); + it('loads a saved dashboard with query via dashboard_no_match', async function () { + await PageObjects.dashboard.gotoDashboardLandingPage(); + const currentUrl = await browser.getCurrentUrl(); + const dashboardBaseUrl = currentUrl.substring(0, currentUrl.indexOf('/app/dashboards')); + const url = `${dashboardBaseUrl}/app/dashboards#/dashboard/${savedDashboardId}?_a=(query:(language:kuery,query:'boop'))`; + log.debug(`Navigating to ${url}`); + await browser.get(url); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const query = await queryBar.getQueryString(); + expect(query).to.equal('boop'); + + await dashboardExpect.panelCount(2); + await PageObjects.dashboard.waitForRenderComplete(); + }); + it('uiState in url takes precedence over saved dashboard state', async function () { const id = await PageObjects.dashboard.getDashboardIdFromCurrentUrl(); const updatedQuery = urlQuery.replace(/F9D9F9/g, '000000'); diff --git a/test/functional/apps/dashboard/dashboard_unsaved_state.ts b/test/functional/apps/dashboard/dashboard_unsaved_state.ts index 6b71dd34b76f8..c2da82a96cd0c 100644 --- a/test/functional/apps/dashboard/dashboard_unsaved_state.ts +++ b/test/functional/apps/dashboard/dashboard_unsaved_state.ts @@ -12,6 +12,9 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['dashboard', 'header', 'visualize', 'settings', 'common']); + const browser = getService('browser'); + const queryBar = getService('queryBar'); + const filterBar = getService('filterBar'); const esArchiver = getService('esArchiver'); const testSubjects = getService('testSubjects'); const kibanaServer = getService('kibanaServer'); @@ -19,9 +22,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { let originalPanelCount = 0; let unsavedPanelCount = 0; + const testQuery = 'Test Query'; - // FLAKY: https://github.com/elastic/kibana/issues/91191 - describe.skip('dashboard unsaved panels', () => { + // FLAKY https://github.com/elastic/kibana/issues/112812 + describe.skip('dashboard unsaved state', () => { before(async () => { await esArchiver.load('test/functional/fixtures/es_archiver/dashboard/current/kibana'); await kibanaServer.uiSettings.replace({ @@ -31,79 +35,123 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.preserveCrossAppState(); await PageObjects.dashboard.loadSavedDashboard('few panels'); await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); originalPanelCount = await PageObjects.dashboard.getPanelCount(); }); - it('does not show unsaved changes badge when there are no unsaved changes', async () => { - await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); - }); + describe('view mode state', () => { + before(async () => { + await queryBar.setQuery(testQuery); + await filterBar.addFilter('bytes', 'exists'); + await queryBar.submitQuery(); + }); - it('shows the unsaved changes badge after adding panels', async () => { - await PageObjects.dashboard.switchToEditMode(); - // add an area chart by value - await dashboardAddPanel.clickEditorMenuButton(); - await dashboardAddPanel.clickAggBasedVisualizations(); - await PageObjects.visualize.clickAreaChart(); - await PageObjects.visualize.clickNewSearch(); - await PageObjects.visualize.saveVisualizationAndReturn(); + const validateQueryAndFilter = async () => { + const query = await queryBar.getQueryString(); + expect(query).to.eql(testQuery); + const filterCount = await filterBar.getFilterCount(); + expect(filterCount).to.eql(1); + }; + + it('persists after navigating to the listing page and back', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.loadSavedDashboard('few panels'); + await PageObjects.dashboard.waitForRenderComplete(); + await validateQueryAndFilter(); + }); - // add a metric by reference - await dashboardAddPanel.addVisualization('Rendering-Test: metric'); + it('persists after navigating to Visualize and back', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.visualize.gotoVisualizationLandingPage(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.common.navigateToApp('dashboards'); + await PageObjects.dashboard.loadSavedDashboard('few panels'); + await PageObjects.dashboard.waitForRenderComplete(); + await validateQueryAndFilter(); + }); - await PageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.existOrFail('dashboardUnsavedChangesBadge'); - }); + it('persists after a hard refresh', async () => { + await browser.refresh(); + const alert = await browser.getAlert(); + await alert?.accept(); + await PageObjects.dashboard.waitForRenderComplete(); + await validateQueryAndFilter(); + }); - it('has correct number of panels', async () => { - unsavedPanelCount = await PageObjects.dashboard.getPanelCount(); - expect(unsavedPanelCount).to.eql(originalPanelCount + 2); + after(async () => { + // discard changes made in view mode + await PageObjects.dashboard.switchToEditMode(); + await PageObjects.dashboard.clickCancelOutOfEditMode(); + }); }); - it('retains unsaved panel count after navigating to listing page and back', async () => { - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.dashboard.gotoDashboardLandingPage(); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.dashboard.loadSavedDashboard('few panels'); - await PageObjects.dashboard.switchToEditMode(); - const currentPanelCount = await PageObjects.dashboard.getPanelCount(); - expect(currentPanelCount).to.eql(unsavedPanelCount); - }); + describe('edit mode state', () => { + const addPanels = async () => { + // add an area chart by value + await dashboardAddPanel.clickEditorMenuButton(); + await dashboardAddPanel.clickAggBasedVisualizations(); + await PageObjects.visualize.clickAreaChart(); + await PageObjects.visualize.clickNewSearch(); + await PageObjects.visualize.saveVisualizationAndReturn(); + + // add a metric by reference + await dashboardAddPanel.addVisualization('Rendering-Test: metric'); + }; + + it('does not show unsaved changes badge when there are no unsaved changes', async () => { + await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); + }); - it('retains unsaved panel count after navigating to another app and back', async () => { - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.gotoVisualizationLandingPage(); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.common.navigateToApp('dashboards'); - await PageObjects.dashboard.loadSavedDashboard('few panels'); - await PageObjects.dashboard.switchToEditMode(); - const currentPanelCount = await PageObjects.dashboard.getPanelCount(); - expect(currentPanelCount).to.eql(unsavedPanelCount); - }); + it('shows the unsaved changes badge after adding panels', async () => { + await PageObjects.dashboard.switchToEditMode(); + await addPanels(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.existOrFail('dashboardUnsavedChangesBadge'); + }); - it('resets to original panel count upon entering view mode', async () => { - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.dashboard.clickCancelOutOfEditMode(); - await PageObjects.header.waitUntilLoadingHasFinished(); - const currentPanelCount = await PageObjects.dashboard.getPanelCount(); - expect(currentPanelCount).to.eql(originalPanelCount); - }); + it('has correct number of panels', async () => { + unsavedPanelCount = await PageObjects.dashboard.getPanelCount(); + expect(unsavedPanelCount).to.eql(originalPanelCount + 2); + }); - it('shows unsaved changes badge in view mode if changes have not been discarded', async () => { - await testSubjects.existOrFail('dashboardUnsavedChangesBadge'); - }); + it('retains unsaved panel count after navigating to listing page and back', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.loadSavedDashboard('few panels'); + const currentPanelCount = await PageObjects.dashboard.getPanelCount(); + expect(currentPanelCount).to.eql(unsavedPanelCount); + }); - it('retains unsaved panel count after returning to edit mode', async () => { - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.dashboard.switchToEditMode(); - await PageObjects.header.waitUntilLoadingHasFinished(); - const currentPanelCount = await PageObjects.dashboard.getPanelCount(); - expect(currentPanelCount).to.eql(unsavedPanelCount); - }); + it('retains unsaved panel count after navigating to another app and back', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.visualize.gotoVisualizationLandingPage(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.common.navigateToApp('dashboards'); + await PageObjects.dashboard.loadSavedDashboard('few panels'); + const currentPanelCount = await PageObjects.dashboard.getPanelCount(); + expect(currentPanelCount).to.eql(unsavedPanelCount); + }); - it('does not show unsaved changes badge after saving', async () => { - await PageObjects.dashboard.saveDashboard('Unsaved State Test'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); + it('resets to original panel count after discarding changes', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.clickCancelOutOfEditMode(); + await PageObjects.header.waitUntilLoadingHasFinished(); + const currentPanelCount = await PageObjects.dashboard.getPanelCount(); + expect(currentPanelCount).to.eql(originalPanelCount); + expect(PageObjects.dashboard.getIsInViewMode()).to.eql(true); + }); + + it('does not show unsaved changes badge after saving', async () => { + await PageObjects.dashboard.switchToEditMode(); + await addPanels(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.saveDashboard('Unsaved State Test'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); + }); }); }); } diff --git a/test/functional/apps/dashboard/saved_search_embeddable.ts b/test/functional/apps/dashboard/saved_search_embeddable.ts index 5bcec338aad1e..ce1033fa02075 100644 --- a/test/functional/apps/dashboard/saved_search_embeddable.ts +++ b/test/functional/apps/dashboard/saved_search_embeddable.ts @@ -5,12 +5,13 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const dashboardAddPanel = getService('dashboardAddPanel'); + const dashboardPanelActions = getService('dashboardPanelActions'); + const testSubjects = getService('testSubjects'); const filterBar = getService('filterBar'); const find = getService('find'); const esArchiver = getService('esArchiver'); @@ -61,5 +62,33 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { .map((mark) => $(mark).text()); expect(marks.length).to.be(0); }); + + it('view action leads to a saved search', async function () { + await filterBar.removeAllFilters(); + await PageObjects.dashboard.saveDashboard('Dashboard With Saved Search'); + await PageObjects.dashboard.clickCancelOutOfEditMode(false); + const inViewMode = await PageObjects.dashboard.getIsInViewMode(); + expect(inViewMode).to.equal(true); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + + await dashboardPanelActions.openContextMenu(); + const actionExists = await testSubjects.exists( + 'embeddablePanelAction-ACTION_VIEW_SAVED_SEARCH' + ); + if (!actionExists) { + await dashboardPanelActions.clickContextMenuMoreItem(); + } + const actionElement = await testSubjects.find( + 'embeddablePanelAction-ACTION_VIEW_SAVED_SEARCH' + ); + await actionElement.click(); + + await PageObjects.discover.waitForDiscoverAppOnScreen(); + expect(await PageObjects.discover.getSavedSearchTitle()).to.equal( + 'Rendering Test: saved search' + ); + }); }); } diff --git a/test/functional/apps/discover/_runtime_fields_editor.ts b/test/functional/apps/discover/_runtime_fields_editor.ts index 642743d3a0377..4757807cb7ac1 100644 --- a/test/functional/apps/discover/_runtime_fields_editor.ts +++ b/test/functional/apps/discover/_runtime_fields_editor.ts @@ -31,7 +31,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await fieldEditor.save(); }; - describe('discover integration with runtime fields editor', function describeIndexTests() { + // Failing: https://github.com/elastic/kibana/issues/111922 + describe.skip('discover integration with runtime fields editor', function describeIndexTests() { before(async function () { await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); diff --git a/test/functional/apps/management/_test_huge_fields.js b/test/functional/apps/management/_test_huge_fields.js index c8710a79e4fc8..7b75683940928 100644 --- a/test/functional/apps/management/_test_huge_fields.js +++ b/test/functional/apps/management/_test_huge_fields.js @@ -14,7 +14,7 @@ export default function ({ getService, getPageObjects }) { const PageObjects = getPageObjects(['common', 'home', 'settings']); // FLAKY: https://github.com/elastic/kibana/issues/89031 - describe.skip('test large number of fields', function () { + describe('test large number of fields', function () { this.tags(['skipCloud']); const EXPECTED_FIELD_COUNT = '10006'; diff --git a/test/functional/apps/saved_objects_management/edit_saved_object.ts b/test/functional/apps/saved_objects_management/edit_saved_object.ts deleted file mode 100644 index f4bf45c0b7f70..0000000000000 --- a/test/functional/apps/saved_objects_management/edit_saved_object.ts +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const testSubjects = getService('testSubjects'); - const PageObjects = getPageObjects(['common', 'settings', 'savedObjects']); - const browser = getService('browser'); - const find = getService('find'); - - const setFieldValue = async (fieldName: string, value: string) => { - return testSubjects.setValue(`savedObjects-editField-${fieldName}`, value); - }; - - const getFieldValue = async (fieldName: string) => { - return testSubjects.getAttribute(`savedObjects-editField-${fieldName}`, 'value'); - }; - - const setAceEditorFieldValue = async (fieldName: string, fieldValue: string) => { - const editorId = `savedObjects-editField-${fieldName}-aceEditor`; - await find.clickByCssSelector(`#${editorId}`); - return browser.execute( - (editor: string, value: string) => { - return (window as any).ace.edit(editor).setValue(value); - }, - editorId, - fieldValue - ); - }; - - const getAceEditorFieldValue = async (fieldName: string) => { - const editorId = `savedObjects-editField-${fieldName}-aceEditor`; - await find.clickByCssSelector(`#${editorId}`); - return browser.execute((editor: string) => { - return (window as any).ace.edit(editor).getValue() as string; - }, editorId); - }; - - const focusAndClickButton = async (buttonSubject: string) => { - const button = await testSubjects.find(buttonSubject); - await button.scrollIntoViewIfNecessary(); - await delay(10); - await button.focus(); - await delay(10); - await button.click(); - // Allow some time for the transition/animations to occur before assuming the click is done - await delay(10); - }; - - describe('saved objects edition page', () => { - beforeEach(async () => { - await esArchiver.load( - 'test/functional/fixtures/es_archiver/saved_objects_management/edit_saved_object' - ); - }); - - afterEach(async () => { - await esArchiver.unload( - 'test/functional/fixtures/es_archiver/saved_objects_management/edit_saved_object' - ); - }); - - it('allows to update the saved object when submitting', async () => { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaSavedObjects(); - - let objects = await PageObjects.savedObjects.getRowTitles(); - expect(objects.includes('A Dashboard')).to.be(true); - - await PageObjects.common.navigateToUrl( - 'management', - 'kibana/objects/savedDashboards/i-exist', - { - shouldUseHashForSubUrl: false, - } - ); - - await testSubjects.existOrFail('savedObjectEditSave'); - - expect(await getFieldValue('title')).to.eql('A Dashboard'); - - await setFieldValue('title', 'Edited Dashboard'); - await setFieldValue('description', 'Some description'); - - await focusAndClickButton('savedObjectEditSave'); - - objects = await PageObjects.savedObjects.getRowTitles(); - expect(objects.includes('A Dashboard')).to.be(false); - expect(objects.includes('Edited Dashboard')).to.be(true); - - await PageObjects.common.navigateToUrl( - 'management', - 'kibana/objects/savedDashboards/i-exist', - { - shouldUseHashForSubUrl: false, - } - ); - - expect(await getFieldValue('title')).to.eql('Edited Dashboard'); - expect(await getFieldValue('description')).to.eql('Some description'); - }); - - it('allows to delete a saved object', async () => { - await PageObjects.common.navigateToUrl( - 'management', - 'kibana/objects/savedDashboards/i-exist', - { - shouldUseHashForSubUrl: false, - } - ); - - await focusAndClickButton('savedObjectEditDelete'); - await PageObjects.common.clickConfirmOnModal(); - - const objects = await PageObjects.savedObjects.getRowTitles(); - expect(objects.includes('A Dashboard')).to.be(false); - }); - - it('preserves the object references when saving', async () => { - const testVisualizationUrl = - 'kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed'; - const visualizationRefs = [ - { - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - id: 'logstash-*', - }, - ]; - - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaSavedObjects(); - - const objects = await PageObjects.savedObjects.getRowTitles(); - expect(objects.includes('A Pie')).to.be(true); - - await PageObjects.common.navigateToUrl('management', testVisualizationUrl, { - shouldUseHashForSubUrl: false, - }); - - await testSubjects.existOrFail('savedObjectEditSave'); - - let displayedReferencesValue = await getAceEditorFieldValue('references'); - - expect(JSON.parse(displayedReferencesValue)).to.eql(visualizationRefs); - - await focusAndClickButton('savedObjectEditSave'); - - await PageObjects.savedObjects.getRowTitles(); - - await PageObjects.common.navigateToUrl('management', testVisualizationUrl, { - shouldUseHashForSubUrl: false, - }); - - // Parsing to avoid random keys ordering issues in raw string comparison - expect(JSON.parse(await getAceEditorFieldValue('references'))).to.eql(visualizationRefs); - - await setAceEditorFieldValue('references', JSON.stringify([], undefined, 2)); - - await focusAndClickButton('savedObjectEditSave'); - - await PageObjects.savedObjects.getRowTitles(); - - await PageObjects.common.navigateToUrl('management', testVisualizationUrl, { - shouldUseHashForSubUrl: false, - }); - - displayedReferencesValue = await getAceEditorFieldValue('references'); - - expect(JSON.parse(displayedReferencesValue)).to.eql([]); - }); - }); -} diff --git a/test/functional/apps/saved_objects_management/index.ts b/test/functional/apps/saved_objects_management/index.ts index 0b367b284e741..12e0cc8863f12 100644 --- a/test/functional/apps/saved_objects_management/index.ts +++ b/test/functional/apps/saved_objects_management/index.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function savedObjectsManagementApp({ loadTestFile }: FtrProviderContext) { describe('saved objects management', function savedObjectsManagementAppTestSuite() { this.tags('ciGroup7'); - loadTestFile(require.resolve('./edit_saved_object')); + loadTestFile(require.resolve('./inspect_saved_objects')); loadTestFile(require.resolve('./show_relationships')); }); } diff --git a/test/functional/apps/saved_objects_management/inspect_saved_objects.ts b/test/functional/apps/saved_objects_management/inspect_saved_objects.ts new file mode 100644 index 0000000000000..839c262acffa0 --- /dev/null +++ b/test/functional/apps/saved_objects_management/inspect_saved_objects.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common', 'settings', 'savedObjects']); + const find = getService('find'); + + const focusAndClickButton = async (buttonSubject: string) => { + const button = await testSubjects.find(buttonSubject); + await button.scrollIntoViewIfNecessary(); + await delay(10); + await button.focus(); + await delay(10); + await button.click(); + // Allow some time for the transition/animations to occur before assuming the click is done + await delay(10); + }; + const textIncludesAll = (text: string, items: string[]) => { + const bools = items.map((item) => !!text.includes(item)); + return bools.every((currBool) => currBool === true); + }; + + describe('saved objects edition page', () => { + beforeEach(async () => { + await esArchiver.load( + 'test/functional/fixtures/es_archiver/saved_objects_management/edit_saved_object' + ); + }); + + afterEach(async () => { + await esArchiver.unload( + 'test/functional/fixtures/es_archiver/saved_objects_management/edit_saved_object' + ); + }); + + it('allows to view the saved object', async () => { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaSavedObjects(); + const objects = await PageObjects.savedObjects.getRowTitles(); + expect(objects.includes('A Dashboard')).to.be(true); + await PageObjects.common.navigateToUrl('management', 'kibana/objects/dashboard/i-exist', { + shouldUseHashForSubUrl: false, + }); + const inspectContainer = await find.byClassName('kibanaCodeEditor'); + const visibleContainerText = await inspectContainer.getVisibleText(); + // ensure that something renders visibly + expect( + textIncludesAll(visibleContainerText, [ + 'A Dashboard', + 'title', + 'id', + 'type', + 'attributes', + 'references', + ]) + ).to.be(true); + }); + + it('allows to delete a saved object', async () => { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaSavedObjects(); + let objects = await PageObjects.savedObjects.getRowTitles(); + expect(objects.includes('A Dashboard')).to.be(true); + await PageObjects.savedObjects.clickInspectByTitle('A Dashboard'); + await PageObjects.common.navigateToUrl('management', 'kibana/objects/dashboard/i-exist', { + shouldUseHashForSubUrl: false, + }); + await focusAndClickButton('savedObjectEditDelete'); + await PageObjects.common.clickConfirmOnModal(); + + objects = await PageObjects.savedObjects.getRowTitles(); + expect(objects.includes('A Dashboard')).to.be(false); + }); + }); +} diff --git a/test/functional/apps/visualize/_timelion.ts b/test/functional/apps/visualize/_timelion.ts index ea8cb8b13ba49..bb85b6821df31 100644 --- a/test/functional/apps/visualize/_timelion.ts +++ b/test/functional/apps/visualize/_timelion.ts @@ -18,6 +18,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'timelion', 'common', ]); + const security = getService('security'); const monacoEditor = getService('monacoEditor'); const kibanaServer = getService('kibanaServer'); const elasticChart = getService('elasticChart'); @@ -26,6 +27,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('Timelion visualization', () => { before(async () => { + await security.testUser.setRoles([ + 'kibana_admin', + 'long_window_logstash', + 'test_logstash_reader', + ]); await kibanaServer.uiSettings.update({ 'timelion:legacyChartsLibrary': false, }); @@ -277,17 +283,20 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('should show field suggestions for split argument when index pattern set', async () => { await monacoEditor.setCodeEditorValue(''); await monacoEditor.typeCodeEditorValue( - '.es(index=logstash-*, timefield=@timestamp ,split=', + '.es(index=logstash-*, timefield=@timestamp, split=', 'timelionCodeEditor' ); + // wait for split fields to load + await common.sleep(300); const suggestions = await timelion.getSuggestionItemsText(); + expect(suggestions.length).not.to.eql(0); expect(suggestions[0].includes('@message.raw')).to.eql(true); }); it('should show field suggestions for metric argument when index pattern set', async () => { await monacoEditor.typeCodeEditorValue( - '.es(index=logstash-*, timefield=@timestamp ,metric=avg:', + '.es(index=logstash-*, timefield=@timestamp, metric=avg:', 'timelionCodeEditor' ); const suggestions = await timelion.getSuggestionItemsText(); diff --git a/test/functional/apps/visualize/_tsvb_chart.ts b/test/functional/apps/visualize/_tsvb_chart.ts index 6a5c062268c25..c530b00364fd1 100644 --- a/test/functional/apps/visualize/_tsvb_chart.ts +++ b/test/functional/apps/visualize/_tsvb_chart.ts @@ -16,6 +16,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const inspector = getService('inspector'); const retry = getService('retry'); const security = getService('security'); + const kibanaServer = getService('kibanaServer'); const { timePicker, visChart, visualBuilder, visualize, settings } = getPageObjects([ 'timePicker', @@ -95,6 +96,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visualBuilder.setFieldForAggregation('machine.ram'); const kibanaIndexPatternModeValue = await visualBuilder.getMetricValue(); + await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': true }); + await browser.refresh(); await visualBuilder.clickPanelOptions('metric'); await visualBuilder.switchIndexPatternSelectionMode(false); const stringIndexPatternModeValue = await visualBuilder.getMetricValue(); diff --git a/test/functional/apps/visualize/_tsvb_time_series.ts b/test/functional/apps/visualize/_tsvb_time_series.ts index 21bee2d16442f..009e4a07cd42a 100644 --- a/test/functional/apps/visualize/_tsvb_time_series.ts +++ b/test/functional/apps/visualize/_tsvb_time_series.ts @@ -17,6 +17,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'timeToVisualize', 'dashboard', ]); + const security = getService('security'); const testSubjects = getService('testSubjects'); const retry = getService('retry'); const filterBar = getService('filterBar'); @@ -27,6 +28,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('visual builder', function describeIndexTests() { before(async () => { + await security.testUser.setRoles([ + 'kibana_admin', + 'long_window_logstash', + 'test_logstash_reader', + ]); await visualize.initTests(); }); beforeEach(async () => { @@ -433,6 +439,49 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => await visualBuilder.toggleNewChartsLibraryWithDebug(false)); }); + + describe('index pattern selection mode', () => { + it('should disable switch for Kibana index patterns mode by default', async () => { + await visualBuilder.clickPanelOptions('timeSeries'); + const isEnabled = await visualBuilder.checkIndexPatternSelectionModeSwitchIsEnabled(); + expect(isEnabled).to.be(false); + }); + + describe('metrics:allowStringIndices = true', () => { + before(async () => { + await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': true }); + await browser.refresh(); + }); + + beforeEach(async () => await visualBuilder.clickPanelOptions('timeSeries')); + + it('should not disable switch for Kibana index patterns mode', async () => { + await visualBuilder.switchIndexPatternSelectionMode(true); + + const isEnabled = await visualBuilder.checkIndexPatternSelectionModeSwitchIsEnabled(); + expect(isEnabled).to.be(true); + }); + + it('should disable switch after selecting Kibana index patterns mode and metrics:allowStringIndices = false', async () => { + await visualBuilder.switchIndexPatternSelectionMode(false); + await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': false }); + await browser.refresh(); + await visualBuilder.clickPanelOptions('timeSeries'); + + let isEnabled = await visualBuilder.checkIndexPatternSelectionModeSwitchIsEnabled(); + expect(isEnabled).to.be(true); + + await visualBuilder.switchIndexPatternSelectionMode(true); + isEnabled = await visualBuilder.checkIndexPatternSelectionModeSwitchIsEnabled(); + expect(isEnabled).to.be(false); + }); + + after( + async () => + await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': false }) + ); + }); + }); }); }); } diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index c52b0e0f8451f..b2692c2a00d78 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -41,8 +41,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const retry = getService('retry'); const browser = getService('browser'); - // SKIPPED: https://github.com/elastic/kibana/issues/106352 - describe.skip('vega chart in visualize app', () => { + describe('vega chart in visualize app', () => { before(async () => { await PageObjects.visualize.initTests(); log.debug('navigateToApp visualize'); diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index 878c7b88341af..3bc4da0163909 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -85,11 +85,16 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_add_to_dashboard.ts')); }); + describe('visualize ciGroup8', function () { + this.tags('ciGroup8'); + + loadTestFile(require.resolve('./_tsvb_chart')); + }); + describe('visualize ciGroup11', function () { this.tags('ciGroup11'); loadTestFile(require.resolve('./_tag_cloud')); - loadTestFile(require.resolve('./_tsvb_chart')); loadTestFile(require.resolve('./_tsvb_time_series')); loadTestFile(require.resolve('./_tsvb_markdown')); loadTestFile(require.resolve('./_tsvb_table')); diff --git a/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/data.json b/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/data.json new file mode 100644 index 0000000000000..236d7bbff7215 --- /dev/null +++ b/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/data.json @@ -0,0 +1,20 @@ +{ + "type": "doc", + "value": { + "id": "test-not-visible-in-management:vim-1", + "index": ".kibana", + "source": { + "coreMigrationVersion": "7.14.0", + "references": [ + ], + "test-not-visible-in-management": { + "enabled": true, + "title": "vim-1" + }, + "type": "test-not-visible-in-management", + "updated_at": "2018-12-21T00:43:07.096Z" + }, + "type": "_doc" + } +} + diff --git a/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/mappings.json b/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/mappings.json new file mode 100644 index 0000000000000..3c0a975a30be0 --- /dev/null +++ b/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/mappings.json @@ -0,0 +1,477 @@ +{ + "type": "index", + "value": { + "aliases": { + ".kibana_$KIBANA_PACKAGE_VERSION": {}, + ".kibana": {} + }, + "index": ".kibana_$KIBANA_PACKAGE_VERSION_001", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "application_usage_daily": "43b8830d5d0df85a6823d290885fc9fd", + "application_usage_totals": "3d1b76c39bfb2cc8296b024d73854724", + "application_usage_transactional": "3d1b76c39bfb2cc8296b024d73854724", + "config": "c63748b75f39d0c54de12d12c1ccbc20", + "core-usage-stats": "3d1b76c39bfb2cc8296b024d73854724", + "coreMigrationVersion": "2f4316de49999235636386fe51dc06c1", + "dashboard": "40554caf09725935e2c02e02563a2d07", + "index-pattern": "45915a1ad866812242df474eb0479052", + "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", + "legacy-url-alias": "6155300fd11a00e23d5cbaa39f0fce0a", + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "originId": "2f4316de49999235636386fe51dc06c1", + "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", + "search": "db2c00e39b36f40930a3b9fc71c823e1", + "search-telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "telemetry": "36a616f7026dfa617d6655df850fe16d", + "type": "2f4316de49999235636386fe51dc06c1", + "ui-counter": "0d409297dc5ebe1e3a1da691c6ee32e3", + "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0", + "url": "c7f66a0df8b1b52f17c28c4adb111105", + "usage-counters": "8cc260bdceffec4ffc3ad165c97dc1b4", + "visualization": "f819cf6636b75c9e76ba733a0c6ef355" + } + }, + "dynamic": "strict", + "properties": { + "apm-telemetry": { + "dynamic": "false", + "type": "object" + }, + "application_usage_daily": { + "dynamic": "false", + "properties": { + "timestamp": { + "type": "date" + } + } + }, + "application_usage_totals": { + "dynamic": "false", + "type": "object" + }, + "application_usage_transactional": { + "dynamic": "false", + "type": "object" + }, + "canvas-workpad": { + "dynamic": "false", + "type": "object" + }, + "config": { + "dynamic": "false", + "properties": { + "buildNum": { + "type": "keyword" + } + } + }, + "core-usage-stats": { + "dynamic": "false", + "type": "object" + }, + "coreMigrationVersion": { + "type": "keyword" + }, + "dashboard": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "optionsJSON": { + "index": false, + "type": "text" + }, + "panelsJSON": { + "index": false, + "type": "text" + }, + "refreshInterval": { + "properties": { + "display": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "pause": { + "doc_values": false, + "index": false, + "type": "boolean" + }, + "section": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "value": { + "doc_values": false, + "index": false, + "type": "integer" + } + } + }, + "timeFrom": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "timeRestore": { + "doc_values": false, + "index": false, + "type": "boolean" + }, + "timeTo": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "graph-workspace": { + "dynamic": "false", + "type": "object" + }, + "index-pattern": { + "dynamic": "false", + "properties": { + "title": { + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "kql-telemetry": { + "properties": { + "optInCount": { + "type": "long" + }, + "optOutCount": { + "type": "long" + } + } + }, + "legacy-url-alias": { + "dynamic": "false", + "properties": { + "disabled": { + "type": "boolean" + }, + "sourceId": { + "type": "keyword" + }, + "targetType": { + "type": "keyword" + } + } + }, + "map": { + "dynamic": "false", + "type": "object" + }, + "migrationVersion": { + "dynamic": "true", + "type": "object" + }, + "namespace": { + "type": "keyword" + }, + "namespaces": { + "type": "keyword" + }, + "originId": { + "type": "keyword" + }, + "query": { + "properties": { + "description": { + "type": "text" + }, + "filters": { + "enabled": false, + "type": "object" + }, + "query": { + "properties": { + "language": { + "type": "keyword" + }, + "query": { + "index": false, + "type": "keyword" + } + } + }, + "timefilter": { + "enabled": false, + "type": "object" + }, + "title": { + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "sample-data-telemetry": { + "properties": { + "installCount": { + "type": "long" + }, + "unInstallCount": { + "type": "long" + } + } + }, + "search": { + "properties": { + "columns": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "description": { + "type": "text" + }, + "grid": { + "enabled": false, + "type": "object" + }, + "hideChart": { + "doc_values": false, + "index": false, + "type": "boolean" + }, + "hits": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "sort": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "search-telemetry": { + "dynamic": "false", + "type": "object" + }, + "server": { + "dynamic": "false", + "type": "object" + }, + "space": { + "dynamic": "false", + "type": "object" + }, + "spaceId": { + "type": "keyword" + }, + "telemetry": { + "properties": { + "allowChangingOptInStatus": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "lastReported": { + "type": "date" + }, + "lastVersionChecked": { + "type": "keyword" + }, + "reportFailureCount": { + "type": "integer" + }, + "reportFailureVersion": { + "type": "keyword" + }, + "sendUsageFrom": { + "type": "keyword" + }, + "userHasSeenNotice": { + "type": "boolean" + } + } + }, + "test-export-add": { + "dynamic": "false", + "type": "object" + }, + "test-export-add-dep": { + "dynamic": "false", + "type": "object" + }, + "test-export-invalid-transform": { + "dynamic": "false", + "type": "object" + }, + "test-export-transform": { + "dynamic": "false", + "type": "object" + }, + "test-export-transform-error": { + "dynamic": "false", + "type": "object" + }, + "test-visible-in-management": { + "dynamic": "false", + "type": "object" + }, + "test-not-visible-in-management": { + "dynamic": "false", + "type": "object" + }, + "type": { + "type": "keyword" + }, + "ui-counter": { + "properties": { + "count": { + "type": "integer" + } + } + }, + "ui-metric": { + "properties": { + "count": { + "type": "integer" + } + } + }, + "updated_at": { + "type": "date" + }, + "url": { + "properties": { + "accessCount": { + "type": "long" + }, + "accessDate": { + "type": "date" + }, + "createDate": { + "type": "date" + }, + "url": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "usage-counters": { + "dynamic": "false", + "properties": { + "domainId": { + "type": "keyword" + } + } + }, + "visualization": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "savedSearchRefName": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "index": false, + "type": "text" + }, + "version": { + "type": "integer" + }, + "visState": { + "index": false, + "type": "text" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "10", + "refresh_interval": "1s", + "routing_partition_size": "1" + } + } + } +} diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index f230dae1d394a..f8af0ef8f883a 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -123,6 +123,11 @@ export class DiscoverPageObject extends FtrService { return await searchLink.isDisplayed(); } + public async getSavedSearchTitle() { + const breadcrumb = await this.find.byCssSelector('[data-test-subj="breadcrumb last"]'); + return await breadcrumb.getVisibleText(); + } + public async loadSavedSearch(searchName: string) { await this.openLoadSavedSearchPanel(); await this.testSubjects.click(`savedObjectTitle${searchName.split(' ').join('-')}`); diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index c324de1231b7d..d793b87f6ea96 100644 --- a/test/functional/page_objects/visual_builder_page.ts +++ b/test/functional/page_objects/visual_builder_page.ts @@ -284,7 +284,8 @@ export class VisualBuilderPageObject extends FtrService { const drilldownEl = await this.testSubjects.find('drilldownUrl'); await drilldownEl.clearValue(); - await drilldownEl.type(value); + await drilldownEl.type(value, { charByChar: true }); + await this.header.waitUntilLoadingHasFinished(); } /** @@ -502,12 +503,32 @@ export class VisualBuilderPageObject extends FtrService { return await annotationTooltipDetails.getVisibleText(); } + public async toggleIndexPatternSelectionModePopover(shouldOpen: boolean) { + const isPopoverOpened = await this.testSubjects.exists( + 'switchIndexPatternSelectionModePopoverContent' + ); + if ((shouldOpen && !isPopoverOpened) || (!shouldOpen && isPopoverOpened)) { + await this.testSubjects.click('switchIndexPatternSelectionModePopoverButton'); + } + } + public async switchIndexPatternSelectionMode(useKibanaIndices: boolean) { - await this.testSubjects.click('switchIndexPatternSelectionModePopover'); + await this.toggleIndexPatternSelectionModePopover(true); await this.testSubjects.setEuiSwitch( 'switchIndexPatternSelectionMode', useKibanaIndices ? 'check' : 'uncheck' ); + await this.toggleIndexPatternSelectionModePopover(false); + } + + public async checkIndexPatternSelectionModeSwitchIsEnabled() { + await this.toggleIndexPatternSelectionModePopover(true); + let isEnabled; + await this.testSubjects.retry.tryForTime(2000, async () => { + isEnabled = await this.testSubjects.isEnabled('switchIndexPatternSelectionMode'); + }); + await this.toggleIndexPatternSelectionModePopover(false); + return isEnabled; } public async setIndexPatternValue(value: string, useKibanaIndices?: boolean) { diff --git a/test/functional/services/saved_query_management_component.ts b/test/functional/services/saved_query_management_component.ts index 37c6a45557f2f..a216f8cb0469e 100644 --- a/test/functional/services/saved_query_management_component.ts +++ b/test/functional/services/saved_query_management_component.ts @@ -166,8 +166,9 @@ export class SavedQueryManagementComponentService extends FtrService { const isOpenAlready = await this.testSubjects.exists('saved-query-management-popover'); if (isOpenAlready) return; + await this.testSubjects.click('saved-query-management-popover-button'); + await this.retry.waitFor('saved query management popover to have any text', async () => { - await this.testSubjects.click('saved-query-management-popover-button'); const queryText = await this.testSubjects.getVisibleText('saved-query-management-popover'); return queryText.length > 0; }); diff --git a/test/interpreter_functional/test_suites/run_pipeline/esaggs_timeshift.ts b/test/interpreter_functional/test_suites/run_pipeline/esaggs_timeshift.ts index 0bc32672d41b9..244d07d2cfc82 100644 --- a/test/interpreter_functional/test_suites/run_pipeline/esaggs_timeshift.ts +++ b/test/interpreter_functional/test_suites/run_pipeline/esaggs_timeshift.ts @@ -37,7 +37,8 @@ export default function ({ }: FtrProviderContext & { updateBaselines: boolean }) { let expectExpression: ExpectExpression; - describe('esaggs timeshift tests', () => { + // FLAKY https://github.com/elastic/kibana/issues/107028 + describe.skip('esaggs timeshift tests', () => { before(() => { expectExpression = expectExpressionProvider({ getService, updateBaselines }); }); diff --git a/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts b/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts index 15afdb229b1fd..0cb6a5ba8eb5d 100644 --- a/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts +++ b/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts @@ -176,6 +176,42 @@ export class SavedObjectExportTransformsPlugin implements Plugin { }, }, }); + + // example of a SO type with `visibleInManagement: false` + savedObjects.registerType<{ enabled: boolean; title: string }>({ + name: 'test-not-visible-in-management', + hidden: false, + namespaceType: 'single', + mappings: { + properties: { + title: { type: 'text' }, + enabled: { type: 'boolean' }, + }, + }, + management: { + defaultSearchField: 'title', + importableAndExportable: true, + visibleInManagement: false, + }, + }); + + // example of a SO type with `visibleInManagement: true` + savedObjects.registerType<{ enabled: boolean; title: string }>({ + name: 'test-visible-in-management', + hidden: false, + namespaceType: 'single', + mappings: { + properties: { + title: { type: 'text' }, + enabled: { type: 'boolean' }, + }, + }, + management: { + defaultSearchField: 'title', + importableAndExportable: true, + visibleInManagement: true, + }, + }); } public start() {} diff --git a/test/plugin_functional/test_suites/saved_objects_management/exports/_import_non_visible_in_management.ndjson b/test/plugin_functional/test_suites/saved_objects_management/exports/_import_non_visible_in_management.ndjson new file mode 100644 index 0000000000000..754848a99d03d --- /dev/null +++ b/test/plugin_functional/test_suites/saved_objects_management/exports/_import_non_visible_in_management.ndjson @@ -0,0 +1 @@ +{"attributes": { "title": "Saved object type that is not visible in management" }, "id":"ff3773b0-9ate-11e7-ahb3-3dcb94193fab", "references":[], "type":"test-not-visible-in-management", "version":1} diff --git a/test/plugin_functional/test_suites/saved_objects_management/index.ts b/test/plugin_functional/test_suites/saved_objects_management/index.ts index 03ac96b9a11f6..b7730a95d3c71 100644 --- a/test/plugin_functional/test_suites/saved_objects_management/index.ts +++ b/test/plugin_functional/test_suites/saved_objects_management/index.ts @@ -16,5 +16,6 @@ export default function ({ loadTestFile }: PluginFunctionalProviderContext) { loadTestFile(require.resolve('./export_transform')); loadTestFile(require.resolve('./import_warnings')); loadTestFile(require.resolve('./hidden_types')); + loadTestFile(require.resolve('./visible_in_management')); }); } diff --git a/test/plugin_functional/test_suites/saved_objects_management/visible_in_management.ts b/test/plugin_functional/test_suites/saved_objects_management/visible_in_management.ts new file mode 100644 index 0000000000000..dd43ba80a8e8e --- /dev/null +++ b/test/plugin_functional/test_suites/saved_objects_management/visible_in_management.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { join } from 'path'; +import expect from '@kbn/expect'; +import type { Response } from 'supertest'; +import type { PluginFunctionalProviderContext } from '../../services'; +import { SavedObject } from '../../../../src/core/types'; + +function parseNdJson(input: string): Array> { + return input.split('\n').map((str) => JSON.parse(str)); +} + +export default function ({ getService }: PluginFunctionalProviderContext) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + describe('types with `visibleInManagement` ', () => { + before(async () => { + await esArchiver.load( + 'test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management' + ); + }); + + after(async () => { + await esArchiver.unload( + 'test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management' + ); + }); + + describe('export', () => { + it('allows to export them directly by id', async () => { + await supertest + .post('/api/saved_objects/_export') + .set('kbn-xsrf', 'true') + .send({ + objects: [ + { + type: 'test-not-visible-in-management', + id: 'vim-1', + }, + ], + excludeExportDetails: true, + }) + .expect(200) + .then((resp) => { + const objects = parseNdJson(resp.text); + expect(objects.map((obj) => obj.id)).to.eql(['vim-1']); + }); + }); + + it('allows to export them directly by type', async () => { + await supertest + .post('/api/saved_objects/_export') + .set('kbn-xsrf', 'true') + .send({ + type: ['test-not-visible-in-management'], + excludeExportDetails: true, + }) + .expect(200) + .then((resp) => { + const objects = parseNdJson(resp.text); + expect(objects.map((obj) => obj.id)).to.eql(['vim-1']); + }); + }); + }); + + describe('import', () => { + it('allows to import them', async () => { + await supertest + .post('/api/saved_objects/_import') + .set('kbn-xsrf', 'true') + .attach('file', join(__dirname, './exports/_import_non_visible_in_management.ndjson')) + .expect(200) + .then((resp) => { + expect(resp.body).to.eql({ + success: true, + successCount: 1, + successResults: [ + { + id: 'ff3773b0-9ate-11e7-ahb3-3dcb94193fab', + meta: { + title: 'Saved object type that is not visible in management', + }, + type: 'test-not-visible-in-management', + }, + ], + warnings: [], + }); + }); + }); + }); + + describe('savedObjects management APIS', () => { + it('GET /api/kibana/management/saved_objects/_allowed_types should only return types that are `visibleInManagement: true`', async () => + await supertest + .get('/api/kibana/management/saved_objects/_allowed_types') + .set('kbn-xsrf', 'true') + .expect(200) + .then((response: Response) => { + const { types } = response.body; + expect(types.includes('test-is-exportable')).to.eql(true); + expect(types.includes('test-visible-in-management')).to.eql(true); + expect(types.includes('test-not-visible-in-management')).to.eql(false); + })); + }); + }); +} diff --git a/test/scripts/jenkins_storybook.sh b/test/scripts/jenkins_storybook.sh index 00cc0d78599dd..17ca46b0097b1 100755 --- a/test/scripts/jenkins_storybook.sh +++ b/test/scripts/jenkins_storybook.sh @@ -20,6 +20,7 @@ yarn storybook --site expression_repeat_image yarn storybook --site expression_reveal_image yarn storybook --site expression_shape yarn storybook --site expression_tagcloud +yarn storybook --site fleet yarn storybook --site infra yarn storybook --site security_solution yarn storybook --site ui_actions_enhanced diff --git a/test/scripts/test/jest_integration.sh b/test/scripts/test/jest_integration.sh index aaffdb2fd9e90..89390657d1b48 100755 --- a/test/scripts/test/jest_integration.sh +++ b/test/scripts/test/jest_integration.sh @@ -3,4 +3,4 @@ source src/dev/ci_setup/setup_env.sh checks-reporter-with-killswitch "Jest Integration Tests" \ - node scripts/jest_integration --ci + node --max-old-space-size=5120 scripts/jest_integration --ci diff --git a/x-pack/plugins/actions/common/index.ts b/x-pack/plugins/actions/common/index.ts index cff876b5995a1..1e51adf3e9d09 100644 --- a/x-pack/plugins/actions/common/index.ts +++ b/x-pack/plugins/actions/common/index.ts @@ -15,3 +15,10 @@ export * from './rewrite_request_case'; export const BASE_ACTION_API_PATH = '/api/actions'; export const INTERNAL_BASE_ACTION_API_PATH = '/internal/actions'; export const ACTIONS_FEATURE_ID = 'actions'; + +// supported values for `service` in addition to nodemailer's list of well-known services +export enum AdditionalEmailServices { + ELASTIC_CLOUD = 'elastic_cloud', + EXCHANGE = 'exchange_server', + OTHER = 'other', +} diff --git a/x-pack/plugins/actions/server/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client.test.ts index a341cdf58b9e2..7549d2ecaab77 100644 --- a/x-pack/plugins/actions/server/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client.test.ts @@ -20,6 +20,7 @@ import { licenseStateMock } from './lib/license_state.mock'; import { licensingMock } from '../../licensing/server/mocks'; import { httpServerMock } from '../../../../src/core/server/mocks'; import { auditServiceMock } from '../../security/server/audit/index.mock'; +import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; import { elasticsearchServiceMock, @@ -28,7 +29,12 @@ import { import { actionExecutorMock } from './lib/action_executor.mock'; import uuid from 'uuid'; import { ActionsAuthorization } from './authorization/actions_authorization'; +import { + getAuthorizationModeBySource, + AuthorizationMode, +} from './authorization/get_authorization_mode_by_source'; import { actionsAuthorizationMock } from './authorization/actions_authorization.mock'; +import { trackLegacyRBACExemption } from './lib/track_legacy_rbac_exemption'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from '../../../../src/core/server/elasticsearch/client/mocks'; @@ -38,6 +44,22 @@ jest.mock('../../../../src/core/server/saved_objects/service/lib/utils', () => ( }, })); +jest.mock('./lib/track_legacy_rbac_exemption', () => ({ + trackLegacyRBACExemption: jest.fn(), +})); + +jest.mock('./authorization/get_authorization_mode_by_source', () => { + return { + getAuthorizationModeBySource: jest.fn(() => { + return 1; + }), + AuthorizationMode: { + Legacy: 0, + RBAC: 1, + }, + }; +}); + const defaultKibanaIndex = '.kibana'; const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); @@ -47,6 +69,8 @@ const executionEnqueuer = jest.fn(); const ephemeralExecutionEnqueuer = jest.fn(); const request = httpServerMock.createKibanaRequest(); const auditLogger = auditServiceMock.create().asScoped(request); +const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); +const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); const mockTaskManager = taskManagerMock.createSetup(); @@ -82,6 +106,7 @@ beforeEach(() => { request, authorization: authorization as unknown as ActionsAuthorization, auditLogger, + usageCounter: mockUsageCounter, }); }); @@ -1640,6 +1665,9 @@ describe('update()', () => { describe('execute()', () => { describe('authorization', () => { test('ensures user is authorised to excecute actions', async () => { + (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + return AuthorizationMode.RBAC; + }); await actionsClient.execute({ actionId: 'action-id', params: { @@ -1650,6 +1678,9 @@ describe('execute()', () => { }); test('throws when user is not authorised to create the type of action', async () => { + (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + return AuthorizationMode.RBAC; + }); authorization.ensureAuthorized.mockRejectedValue( new Error(`Unauthorized to execute all actions`) ); @@ -1665,6 +1696,21 @@ describe('execute()', () => { expect(authorization.ensureAuthorized).toHaveBeenCalledWith('execute'); }); + + test('tracks legacy RBAC', async () => { + (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + return AuthorizationMode.Legacy; + }); + + await actionsClient.execute({ + actionId: 'action-id', + params: { + name: 'my name', + }, + }); + + expect(trackLegacyRBACExemption as jest.Mock).toBeCalledWith('execute', mockUsageCounter); + }); }); test('calls the actionExecutor with the appropriate parameters', async () => { @@ -1756,6 +1802,9 @@ describe('execute()', () => { describe('enqueueExecution()', () => { describe('authorization', () => { test('ensures user is authorised to excecute actions', async () => { + (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + return AuthorizationMode.RBAC; + }); await actionsClient.enqueueExecution({ id: uuid.v4(), params: {}, @@ -1766,6 +1815,9 @@ describe('enqueueExecution()', () => { }); test('throws when user is not authorised to create the type of action', async () => { + (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + return AuthorizationMode.RBAC; + }); authorization.ensureAuthorized.mockRejectedValue( new Error(`Unauthorized to execute all actions`) ); @@ -1781,6 +1833,24 @@ describe('enqueueExecution()', () => { expect(authorization.ensureAuthorized).toHaveBeenCalledWith('execute'); }); + + test('tracks legacy RBAC', async () => { + (getAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + return AuthorizationMode.Legacy; + }); + + await actionsClient.enqueueExecution({ + id: uuid.v4(), + params: {}, + spaceId: 'default', + apiKey: null, + }); + + expect(trackLegacyRBACExemption as jest.Mock).toBeCalledWith( + 'enqueueExecution', + mockUsageCounter + ); + }); }); test('calls the executionEnqueuer with the appropriate parameters', async () => { diff --git a/x-pack/plugins/actions/server/actions_client.ts b/x-pack/plugins/actions/server/actions_client.ts index d6f6037ecd8b8..b391e50283ad1 100644 --- a/x-pack/plugins/actions/server/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client.ts @@ -7,6 +7,7 @@ import Boom from '@hapi/boom'; import type { estypes } from '@elastic/elasticsearch'; +import { UsageCounter } from 'src/plugins/usage_collection/server'; import { i18n } from '@kbn/i18n'; import { omitBy, isUndefined } from 'lodash'; @@ -42,6 +43,7 @@ import { } from './authorization/get_authorization_mode_by_source'; import { connectorAuditEvent, ConnectorAuditAction } from './lib/audit_events'; import { RunNowResult } from '../../task_manager/server'; +import { trackLegacyRBACExemption } from './lib/track_legacy_rbac_exemption'; // We are assuming there won't be many actions. This is why we will load // all the actions in advance and assume the total count to not go over 10000. @@ -74,6 +76,7 @@ interface ConstructorOptions { request: KibanaRequest; authorization: ActionsAuthorization; auditLogger?: AuditLogger; + usageCounter?: UsageCounter; } export interface UpdateOptions { @@ -93,6 +96,7 @@ export class ActionsClient { private readonly executionEnqueuer: ExecutionEnqueuer; private readonly ephemeralExecutionEnqueuer: ExecutionEnqueuer; private readonly auditLogger?: AuditLogger; + private readonly usageCounter?: UsageCounter; constructor({ actionTypeRegistry, @@ -106,6 +110,7 @@ export class ActionsClient { request, authorization, auditLogger, + usageCounter, }: ConstructorOptions) { this.actionTypeRegistry = actionTypeRegistry; this.unsecuredSavedObjectsClient = unsecuredSavedObjectsClient; @@ -118,6 +123,7 @@ export class ActionsClient { this.request = request; this.authorization = authorization; this.auditLogger = auditLogger; + this.usageCounter = usageCounter; } /** @@ -478,6 +484,8 @@ export class ActionsClient { AuthorizationMode.RBAC ) { await this.authorization.ensureAuthorized('execute'); + } else { + trackLegacyRBACExemption('execute', this.usageCounter); } return this.actionExecutor.execute({ actionId, @@ -495,6 +503,8 @@ export class ActionsClient { AuthorizationMode.RBAC ) { await this.authorization.ensureAuthorized('execute'); + } else { + trackLegacyRBACExemption('enqueueExecution', this.usageCounter); } return this.executionEnqueuer(this.unsecuredSavedObjectsClient, options); } @@ -506,6 +516,8 @@ export class ActionsClient { AuthorizationMode.RBAC ) { await this.authorization.ensureAuthorized('execute'); + } else { + trackLegacyRBACExemption('ephemeralEnqueuedExecution', this.usageCounter); } return this.ephemeralExecutionEnqueuer(this.unsecuredSavedObjectsClient, options); } diff --git a/x-pack/plugins/actions/server/builtin_action_types/email.ts b/x-pack/plugins/actions/server/builtin_action_types/email.ts index d10046341b268..fcd003286d5bb 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/email.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/email.ts @@ -17,6 +17,7 @@ import { Logger } from '../../../../../src/core/server'; import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types'; import { ActionsConfigurationUtilities } from '../actions_config'; import { renderMustacheString, renderMustacheObject } from '../lib/mustache_renderer'; +import { AdditionalEmailServices } from '../../common'; export type EmailActionType = ActionType< ActionTypeConfigType, @@ -33,13 +34,6 @@ export type EmailActionTypeExecutorOptions = ActionTypeExecutorOptions< // config definition export type ActionTypeConfigType = TypeOf; -// supported values for `service` in addition to nodemailer's list of well-known services -export enum AdditionalEmailServices { - ELASTIC_CLOUD = 'elastic_cloud', - EXCHANGE = 'exchange_server', - OTHER = 'other', -} - // these values for `service` require users to fill in host/port/secure export const CUSTOM_HOST_PORT_SERVICES: string[] = [AdditionalEmailServices.OTHER]; diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/request_oauth_client_credentials_token.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/request_oauth_client_credentials_token.ts index 09080ee0c0063..b632cdf5f5219 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/request_oauth_client_credentials_token.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/request_oauth_client_credentials_token.ts @@ -7,6 +7,7 @@ import qs from 'query-string'; import axios from 'axios'; +import stringify from 'json-stable-stringify'; import { Logger } from '../../../../../../src/core/server'; import { request } from './axios_utils'; import { ActionsConfigurationUtilities } from '../../actions_config'; @@ -59,7 +60,7 @@ export async function requestOAuthClientCredentialsToken( expiresIn: res.data.expires_in, }; } else { - const errString = JSON.stringify(res.data); + const errString = stringify(res.data); logger.warn( `error thrown getting the access token from ${tokenUrl} for clientID: ${clientId}: ${errString}` ); diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts index ea3c0f91b6a5c..53c70fddc5a09 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts @@ -13,10 +13,10 @@ import { Logger } from '../../../../../../src/core/server'; import { ActionsConfigurationUtilities } from '../../actions_config'; import { CustomHostSettings } from '../../config'; import { getNodeSSLOptions, getSSLSettingsFromConfig } from './get_node_ssl_options'; -import { AdditionalEmailServices } from '../email'; import { sendEmailGraphApi } from './send_email_graph_api'; import { requestOAuthClientCredentialsToken } from './request_oauth_client_credentials_token'; import { ProxySettings } from '../../types'; +import { AdditionalEmailServices } from '../../../common'; // an email "service" which doesn't actually send, just returns what it would send export const JSON_TRANSPORT_SERVICE = '__json'; diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email_graph_api.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email_graph_api.ts index 10e9a3bc8d27c..ea1579095bb97 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email_graph_api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email_graph_api.ts @@ -5,6 +5,8 @@ * 2.0. */ +// @ts-expect-error missing type def +import stringify from 'json-stringify-safe'; import axios, { AxiosResponse } from 'axios'; import { Logger } from '../../../../../../src/core/server'; import { request } from './axios_utils'; @@ -41,9 +43,9 @@ export async function sendEmailGraphApi( validateStatus: () => true, }); if (res.status === 202) { - return res; + return res.data; } - const errString = JSON.stringify(res.data); + const errString = stringify(res.data); logger.warn( `error thrown sending Microsoft Exchange email for clientID: ${sendEmailOptions.options.transport.clientId}: ${errString}` ); diff --git a/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.test.ts b/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.test.ts new file mode 100644 index 0000000000000..ffd8e7f17c11f --- /dev/null +++ b/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.test.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; +import { trackLegacyRBACExemption } from './track_legacy_rbac_exemption'; + +describe('trackLegacyRBACExemption', () => { + it('should call `usageCounter.incrementCounter`', () => { + const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); + const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); + + trackLegacyRBACExemption('test', mockUsageCounter); + expect(mockUsageCounter.incrementCounter).toHaveBeenCalledWith({ + counterName: `source_test`, + counterType: 'legacyRBACExemption', + incrementBy: 1, + }); + }); + + it('should do nothing if no usage counter is provided', () => { + let err; + try { + trackLegacyRBACExemption('test', undefined); + } catch (e) { + err = e; + } + expect(err).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.ts b/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.ts new file mode 100644 index 0000000000000..73c859c4cd21e --- /dev/null +++ b/x-pack/plugins/actions/server/lib/track_legacy_rbac_exemption.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { UsageCounter } from 'src/plugins/usage_collection/server'; + +export function trackLegacyRBACExemption(source: string, usageCounter?: UsageCounter) { + if (usageCounter) { + usageCounter.incrementCounter({ + counterName: `source_${source}`, + counterType: 'legacyRBACExemption', + incrementBy: 1, + }); + } +} diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index fe133ddb6f0ac..d0404a253c0d9 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -6,7 +6,7 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { UsageCollectionSetup, UsageCounter } from 'src/plugins/usage_collection/server'; import { PluginInitializerContext, Plugin, @@ -151,6 +151,7 @@ export class ActionsPlugin implements Plugin(), this.licenseState, - usageCounter + this.usageCounter ); // Cleanup failed execution task definition @@ -367,6 +369,7 @@ export class ActionsPlugin implements Plugin { + const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; + mockEsClient.search.mockReturnValue( + // @ts-expect-error not full search response + elasticsearchClientMock.createSuccessTransportRequestPromise({ + aggregations: { + byActionTypeId: { + value: { + types: { '.index': 1, '.server-log': 1, 'some.type': 1, 'another.type.': 1 }, + }, + }, + }, + hits: { + hits: [ + { + _id: 'action:541efb3d-f82a-4d2c-a5c3-636d1ce49b53', + _index: '.kibana_1', + _score: 0, + _source: { + action: { + actionTypeId: '.index', + config: { + index: 'kibana_sample_data_ecommerce', + refresh: true, + executionTimeField: null, + }, + name: 'test', + secrets: + 'UPyn6cit6zBTPMmldfKh/8S2JWypwaLhhEQWBXp+OyTc6TtLHOnW92wehCqTq1FhIY3vA8hwVsggj+tbIoCcfPArpzP5SO7hh8vd6pY13x5TkiM083UgjjaAxbPvKQ==', + }, + references: [], + type: 'action', + updated_at: '2020-03-26T18:46:44.449Z', + }, + }, + { + _id: 'action:00000000-f82a-4d2c-a5c3-636d1ce49b53', + _index: '.kibana_1', + _score: 0, + _source: { + action: { + actionTypeId: '.server-log', + config: {}, + name: 'test server log', + secrets: '', + }, + references: [], + type: 'action', + updated_at: '2020-03-26T18:46:44.449Z', + }, + }, + { + _id: 'action:00000000-1', + _index: '.kibana_1', + _score: 0, + _source: { + action: { + actionTypeId: 'some.type', + config: {}, + name: 'test type', + secrets: {}, + }, + references: [], + type: 'action', + updated_at: '2020-03-26T18:46:44.449Z', + }, + }, + { + _id: 'action:00000000-2', + _index: '.kibana_1', + _score: 0, + _source: { + action: { + actionTypeId: 'another.type.', + config: {}, + name: 'test another type', + secrets: {}, + }, + references: [], + type: 'action', + updated_at: '2020-03-26T18:46:44.449Z', + }, + }, + ], + }, + }) + ); + const telemetry = await getTotalCount(mockEsClient, 'test', [ + { + id: 'test', + actionTypeId: '.test', + name: 'test', + isPreconfigured: true, + secrets: {}, + }, + { + id: 'anotherServerLog', + actionTypeId: '.server-log', + name: 'test', + isPreconfigured: true, + secrets: {}, + }, + ]); + + expect(mockEsClient.search).toHaveBeenCalledTimes(1); + + expect(telemetry).toMatchInlineSnapshot(` +Object { + "countByType": Object { + "__index": 1, + "__server-log": 2, + "__test": 1, + "another.type__": 1, + "some.type": 1, + }, + "countTotal": 6, +} +`); + }); + + test('getInUseTotalCount() accounts for preconfigured connectors', async () => { + const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; + mockEsClient.search.mockReturnValue( + // @ts-expect-error not full search response + elasticsearchClientMock.createSuccessTransportRequestPromise({ + aggregations: { + refs: { + actionRefIds: { + value: { + connectorIds: { + '1': 'action-0', + '123': 'action-1', + '456': 'action-2', + }, + total: 3, + }, + }, + }, + preconfigured_actions: { + preconfiguredActionRefIds: { + value: { + total: 3, + actionRefs: { + 'preconfigured:preconfigured-alert-history-es-index': { + actionRef: 'preconfigured:preconfigured-alert-history-es-index', + actionTypeId: '.index', + }, + 'preconfigured:cloud_email': { + actionRef: 'preconfigured:cloud_email', + actionTypeId: '.email', + }, + 'preconfigured:cloud_email2': { + actionRef: 'preconfigured:cloud_email2', + actionTypeId: '.email', + }, + }, + }, + }, }, }, }) @@ -208,11 +415,9 @@ Object { }, }, { - id: 'preconfigured-alert-history-es-index', - error: { - statusCode: 404, - error: 'Not Found', - message: 'Saved object [action/preconfigured-alert-history-es-index] not found', + id: '456', + attributes: { + actionTypeId: '.email', }, }, ], @@ -226,10 +431,12 @@ Object { Object { "countByAlertHistoryConnectorType": 1, "countByType": Object { + "__email": 3, + "__index": 1, "__server-log": 1, "__slack": 1, }, - "countTotal": 3, + "countTotal": 6, } `); }); diff --git a/x-pack/plugins/actions/server/usage/actions_telemetry.ts b/x-pack/plugins/actions/server/usage/actions_telemetry.ts index 71516cb4918e7..76e038fb77e7f 100644 --- a/x-pack/plugins/actions/server/usage/actions_telemetry.ts +++ b/x-pack/plugins/actions/server/usage/actions_telemetry.ts @@ -12,9 +12,13 @@ import { SavedObjectsBulkResponse, } from 'kibana/server'; import { AlertHistoryEsIndexConnectorId } from '../../common'; -import { ActionResult } from '../types'; +import { ActionResult, PreConfiguredAction } from '../types'; -export async function getTotalCount(esClient: ElasticsearchClient, kibanaIndex: string) { +export async function getTotalCount( + esClient: ElasticsearchClient, + kibanaIndex: string, + preconfiguredActions?: PreConfiguredAction[] +) { const scriptedMetric = { scripted_metric: { init_script: 'state.types = [:]', @@ -56,20 +60,27 @@ export async function getTotalCount(esClient: ElasticsearchClient, kibanaIndex: }); // @ts-expect-error aggegation type is not specified const aggs = searchResult.aggregations?.byActionTypeId.value?.types; + const countByType = Object.keys(aggs).reduce( + // ES DSL aggregations are returned as `any` by esClient.search + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (obj: any, key: string) => ({ + ...obj, + [replaceFirstAndLastDotSymbols(key)]: aggs[key], + }), + {} + ); + if (preconfiguredActions && preconfiguredActions.length) { + for (const preconfiguredAction of preconfiguredActions) { + const actionTypeId = replaceFirstAndLastDotSymbols(preconfiguredAction.actionTypeId); + countByType[actionTypeId] = countByType[actionTypeId] || 0; + countByType[actionTypeId]++; + } + } return { - countTotal: Object.keys(aggs).reduce( - (total: number, key: string) => parseInt(aggs[key], 0) + total, - 0 - ), - countByType: Object.keys(aggs).reduce( - // ES DSL aggregations are returned as `any` by esClient.search - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (obj: any, key: string) => ({ - ...obj, - [replaceFirstAndLastDotSymbols(key)]: aggs[key], - }), - {} - ), + countTotal: + Object.keys(aggs).reduce((total: number, key: string) => parseInt(aggs[key], 0) + total, 0) + + (preconfiguredActions?.length ?? 0), + countByType, }; } @@ -120,6 +131,44 @@ export async function getInUseTotalCount( }, }; + const preconfiguredActionsScriptedMetric = { + scripted_metric: { + init_script: 'state.actionRefs = new HashMap(); state.total = 0;', + map_script: ` + String actionRef = doc['alert.actions.actionRef'].value; + String actionTypeId = doc['alert.actions.actionTypeId'].value; + if (actionRef.startsWith('preconfigured:') && state.actionRefs[actionRef] === null) { + HashMap map = new HashMap(); + map.actionRef = actionRef; + map.actionTypeId = actionTypeId; + state.actionRefs[actionRef] = map; + state.total++; + } + `, + // Combine script is executed per cluster, but we already have a key-value pair per cluster. + // Despite docs that say this is optional, this script can't be blank. + combine_script: 'return state', + // Reduce script is executed across all clusters, so we need to add up all the total from each cluster + // This also needs to account for having no data + reduce_script: ` + Map actionRefs = [:]; + long total = 0; + for (state in states) { + if (state !== null) { + total += state.total; + for (String k : state.actionRefs.keySet()) { + actionRefs.put(k, state.actionRefs.get(k)); + } + } + } + Map result = new HashMap(); + result.total = total; + result.actionRefs = actionRefs; + return result; + `, + }, + }; + const { body: actionResults } = await esClient.search({ index: kibanaIndex, body: { @@ -127,24 +176,57 @@ export async function getInUseTotalCount( bool: { filter: { bool: { + must_not: { + term: { + type: 'action_task_params', + }, + }, must: { - nested: { - path: 'references', - query: { - bool: { - filter: { - bool: { - must: [ - { - term: { - 'references.type': 'action', + bool: { + should: [ + { + nested: { + path: 'references', + query: { + bool: { + filter: { + bool: { + must: [ + { + term: { + 'references.type': 'action', + }, + }, + ], }, }, - ], + }, }, }, }, - }, + { + nested: { + path: 'alert.actions', + query: { + bool: { + filter: { + bool: { + must: [ + { + prefix: { + 'alert.actions.actionRef': { + value: 'preconfigured:', + }, + }, + }, + ], + }, + }, + }, + }, + }, + }, + ], }, }, }, @@ -160,25 +242,30 @@ export async function getInUseTotalCount( actionRefIds: scriptedMetric, }, }, + preconfigured_actions: { + nested: { + path: 'alert.actions', + }, + aggs: { + preconfiguredActionRefIds: preconfiguredActionsScriptedMetric, + }, + }, }, }, }); // @ts-expect-error aggegation type is not specified const aggs = actionResults.aggregations.refs.actionRefIds.value; + const preconfiguredActionsAggs = + // @ts-expect-error aggegation type is not specified + actionResults.aggregations.preconfigured_actions?.preconfiguredActionRefIds.value; const bulkFilter = Object.entries(aggs.connectorIds).map(([key]) => ({ id: key, type: 'action', fields: ['id', 'actionTypeId'], })); const actions = await actionsBulkGet(bulkFilter); - - // filter out preconfigured connectors, which are not saved objects and return - // an error in the bulk response - const actionsWithActionTypeId = actions.saved_objects.filter( - (action) => action?.attributes?.actionTypeId != null - ); - const countByActionTypeId = actionsWithActionTypeId.reduce( + const countByActionTypeId = actions.saved_objects.reduce( (actionTypeCount: Record, action) => { const alertTypeId = replaceFirstAndLastDotSymbols(action.attributes.actionTypeId); const currentCount = @@ -189,14 +276,24 @@ export async function getInUseTotalCount( {} ); - const preconfiguredAlertHistoryConnector = actions.saved_objects.filter( - (action) => action.id === AlertHistoryEsIndexConnectorId - ); + let preconfiguredAlertHistoryConnectors = 0; + const preconfiguredActionsRefs: Array<{ + actionTypeId: string; + actionRef: string; + }> = preconfiguredActionsAggs ? Object.values(preconfiguredActionsAggs?.actionRefs) : []; + for (const { actionRef, actionTypeId: rawActionTypeId } of preconfiguredActionsRefs) { + const actionTypeId = replaceFirstAndLastDotSymbols(rawActionTypeId); + countByActionTypeId[actionTypeId] = countByActionTypeId[actionTypeId] || 0; + countByActionTypeId[actionTypeId]++; + if (actionRef === `preconfigured:${AlertHistoryEsIndexConnectorId}`) { + preconfiguredAlertHistoryConnectors++; + } + } return { - countTotal: aggs.total, + countTotal: aggs.total + (preconfiguredActionsAggs?.total ?? 0), countByType: countByActionTypeId, - countByAlertHistoryConnectorType: preconfiguredAlertHistoryConnector.length, + countByAlertHistoryConnectorType: preconfiguredAlertHistoryConnectors, }; } diff --git a/x-pack/plugins/actions/server/usage/task.ts b/x-pack/plugins/actions/server/usage/task.ts index 3ba40d92abd7a..f37f830697eb5 100644 --- a/x-pack/plugins/actions/server/usage/task.ts +++ b/x-pack/plugins/actions/server/usage/task.ts @@ -17,7 +17,7 @@ import { TaskManagerSetupContract, TaskManagerStartContract, } from '../../../task_manager/server'; -import { ActionResult } from '../types'; +import { ActionResult, PreConfiguredAction } from '../types'; import { getTotalCount, getInUseTotalCount } from './actions_telemetry'; export const TELEMETRY_TASK_TYPE = 'actions_telemetry'; @@ -28,9 +28,10 @@ export function initializeActionsTelemetry( logger: Logger, taskManager: TaskManagerSetupContract, core: CoreSetup, - kibanaIndex: string + kibanaIndex: string, + preconfiguredActions: PreConfiguredAction[] ) { - registerActionsTelemetryTask(logger, taskManager, core, kibanaIndex); + registerActionsTelemetryTask(logger, taskManager, core, kibanaIndex, preconfiguredActions); } export function scheduleActionsTelemetry(logger: Logger, taskManager: TaskManagerStartContract) { @@ -41,13 +42,14 @@ function registerActionsTelemetryTask( logger: Logger, taskManager: TaskManagerSetupContract, core: CoreSetup, - kibanaIndex: string + kibanaIndex: string, + preconfiguredActions: PreConfiguredAction[] ) { taskManager.registerTaskDefinitions({ [TELEMETRY_TASK_TYPE]: { title: 'Actions usage fetch task', timeout: '5m', - createTaskRunner: telemetryTaskRunner(logger, core, kibanaIndex), + createTaskRunner: telemetryTaskRunner(logger, core, kibanaIndex, preconfiguredActions), }, }); } @@ -65,7 +67,12 @@ async function scheduleTasks(logger: Logger, taskManager: TaskManagerStartContra } } -export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex: string) { +export function telemetryTaskRunner( + logger: Logger, + core: CoreSetup, + kibanaIndex: string, + preconfiguredActions: PreConfiguredAction[] +) { return ({ taskInstance }: RunContext) => { const { state } = taskInstance; const getEsClient = () => @@ -90,7 +97,7 @@ export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex async run() { const esClient = await getEsClient(); return Promise.all([ - getTotalCount(esClient, kibanaIndex), + getTotalCount(esClient, kibanaIndex, preconfiguredActions), getInUseTotalCount(esClient, actionsBulkGet, kibanaIndex), ]) .then(([totalAggegations, totalInUse]) => { diff --git a/x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts b/x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts index 233e605cf7f5b..c8d4372fb72cf 100644 --- a/x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts +++ b/x-pack/plugins/alerting/server/routes/aggregate_rules.test.ts @@ -11,13 +11,21 @@ import { licenseStateMock } from '../lib/license_state.mock'; import { verifyApiAccess } from '../lib/license_api_access'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; +import { trackLegacyTerminology } from './lib/track_legacy_terminology'; +import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; const rulesClient = rulesClientMock.create(); +const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); +const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); jest.mock('../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); +jest.mock('./lib/track_legacy_terminology', () => ({ + trackLegacyTerminology: jest.fn(), +})); + beforeEach(() => { jest.resetAllMocks(); }); @@ -147,4 +155,39 @@ describe('aggregateRulesRoute', () => { expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); }); + + it('should track calls with deprecated param values', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + aggregateRulesRoute(router, licenseState, mockUsageCounter); + const aggregateResult = { + alertExecutionStatus: { + ok: 15, + error: 2, + active: 23, + pending: 1, + unknown: 0, + }, + }; + rulesClient.aggregate.mockResolvedValueOnce(aggregateResult); + const [, handler] = router.get.mock.calls[0]; + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + params: {}, + query: { + search_fields: ['alertTypeId:1', 'message:foo'], + search: 'alertTypeId:2', + }, + }, + ['ok'] + ); + await handler(context, req, res); + expect(trackLegacyTerminology).toHaveBeenCalledTimes(1); + expect((trackLegacyTerminology as jest.Mock).mock.calls[0][0]).toStrictEqual([ + 'alertTypeId:2', + ['alertTypeId:1', 'message:foo'], + ]); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/aggregate_rules.ts b/x-pack/plugins/alerting/server/routes/aggregate_rules.ts index f91231f9ac48a..84c03e21ff36e 100644 --- a/x-pack/plugins/alerting/server/routes/aggregate_rules.ts +++ b/x-pack/plugins/alerting/server/routes/aggregate_rules.ts @@ -7,10 +7,12 @@ import { IRouter } from 'kibana/server'; import { schema } from '@kbn/config-schema'; +import { UsageCounter } from 'src/plugins/usage_collection/server'; import { ILicenseState } from '../lib'; import { AggregateResult, AggregateOptions } from '../rules_client'; import { RewriteResponseCase, RewriteRequestCase, verifyAccessAndContext } from './lib'; import { AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH } from '../types'; +import { trackLegacyTerminology } from './lib/track_legacy_terminology'; // config definition const querySchema = schema.object({ @@ -53,7 +55,8 @@ const rewriteBodyRes: RewriteResponseCase = ({ export const aggregateRulesRoute = ( router: IRouter, - licenseState: ILicenseState + licenseState: ILicenseState, + usageCounter?: UsageCounter ) => { router.get( { @@ -69,6 +72,10 @@ export const aggregateRulesRoute = ( ...req.query, has_reference: req.query.has_reference || undefined, }); + trackLegacyTerminology( + [req.query.search, req.query.search_fields].filter(Boolean) as string[], + usageCounter + ); const aggregateResult = await rulesClient.aggregate({ options }); return res.ok({ body: rewriteBodyRes(aggregateResult), diff --git a/x-pack/plugins/alerting/server/routes/find_rules.test.ts b/x-pack/plugins/alerting/server/routes/find_rules.test.ts index e0da7b0645748..692fdca6c95ae 100644 --- a/x-pack/plugins/alerting/server/routes/find_rules.test.ts +++ b/x-pack/plugins/alerting/server/routes/find_rules.test.ts @@ -4,20 +4,27 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; import { findRulesRoute } from './find_rules'; import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { verifyApiAccess } from '../lib/license_api_access'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; +import { trackLegacyTerminology } from './lib/track_legacy_terminology'; const rulesClient = rulesClientMock.create(); +const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); +const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); jest.mock('../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); +jest.mock('./lib/track_legacy_terminology', () => ({ + trackLegacyTerminology: jest.fn(), +})); + beforeEach(() => { jest.resetAllMocks(); }); @@ -145,4 +152,74 @@ describe('findRulesRoute', () => { expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); }); + + it('should track calls with deprecated param values', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findRulesRoute(router, licenseState, mockUsageCounter); + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + rulesClient.find.mockResolvedValueOnce(findResult); + const [, handler] = router.get.mock.calls[0]; + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + params: {}, + query: { + search_fields: ['alertTypeId:1', 'message:foo'], + search: 'alertTypeId:2', + sort_field: 'alertTypeId', + }, + }, + ['ok'] + ); + await handler(context, req, res); + expect(trackLegacyTerminology).toHaveBeenCalledTimes(1); + expect((trackLegacyTerminology as jest.Mock).mock.calls[0][0]).toStrictEqual([ + 'alertTypeId:2', + ['alertTypeId:1', 'message:foo'], + 'alertTypeId', + ]); + }); + + it('should track calls to deprecated functionality', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findRulesRoute(router, licenseState, mockUsageCounter); + + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + rulesClient.find.mockResolvedValueOnce(findResult); + + const [, handler] = router.get.mock.calls[0]; + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + params: {}, + query: { + fields: ['foo', 'bar'], + per_page: 1, + page: 1, + default_search_operator: 'OR', + }, + }, + ['ok'] + ); + await handler(context, req, res); + expect(mockUsageCounter.incrementCounter).toHaveBeenCalledWith({ + counterName: `alertingFieldsUsage`, + counterType: 'alertingFieldsUsage', + incrementBy: 1, + }); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/find_rules.ts b/x-pack/plugins/alerting/server/routes/find_rules.ts index ef62341290228..a4a066728555d 100644 --- a/x-pack/plugins/alerting/server/routes/find_rules.ts +++ b/x-pack/plugins/alerting/server/routes/find_rules.ts @@ -7,11 +7,13 @@ import { omit } from 'lodash'; import { IRouter } from 'kibana/server'; +import { UsageCounter } from 'src/plugins/usage_collection/server'; import { schema } from '@kbn/config-schema'; import { ILicenseState } from '../lib'; import { FindOptions, FindResult } from '../rules_client'; import { RewriteRequestCase, RewriteResponseCase, verifyAccessAndContext } from './lib'; import { AlertTypeParams, AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; +import { trackLegacyTerminology } from './lib/track_legacy_terminology'; // query definition const querySchema = schema.object({ @@ -107,7 +109,8 @@ const rewriteBodyRes: RewriteResponseCase> = ({ export const findRulesRoute = ( router: IRouter, - licenseState: ILicenseState + licenseState: ILicenseState, + usageCounter?: UsageCounter ) => { router.get( { @@ -120,12 +123,27 @@ export const findRulesRoute = ( verifyAccessAndContext(licenseState, async function (context, req, res) { const rulesClient = context.alerting.getRulesClient(); + trackLegacyTerminology( + [req.query.search, req.query.search_fields, req.query.sort_field].filter( + Boolean + ) as string[], + usageCounter + ); + const options = rewriteQueryReq({ ...req.query, has_reference: req.query.has_reference || undefined, search_fields: searchFieldsAsArray(req.query.search_fields), }); + if (req.query.fields) { + usageCounter?.incrementCounter({ + counterName: `alertingFieldsUsage`, + counterType: 'alertingFieldsUsage', + incrementBy: 1, + }); + } + const findResult = await rulesClient.find({ options }); return res.ok({ body: rewriteBodyRes(findResult), diff --git a/x-pack/plugins/alerting/server/routes/index.ts b/x-pack/plugins/alerting/server/routes/index.ts index c1c7eae45109e..2db52fa2c143d 100644 --- a/x-pack/plugins/alerting/server/routes/index.ts +++ b/x-pack/plugins/alerting/server/routes/index.ts @@ -38,7 +38,7 @@ export interface RouteOptions { } export function defineRoutes(opts: RouteOptions) { - const { router, licenseState, encryptedSavedObjects } = opts; + const { router, licenseState, encryptedSavedObjects, usageCounter } = opts; defineLegacyRoutes(opts); createRuleRoute(opts); @@ -49,7 +49,7 @@ export function defineRoutes(opts: RouteOptions) { aggregateRulesRoute(router, licenseState); disableRuleRoute(router, licenseState); enableRuleRoute(router, licenseState); - findRulesRoute(router, licenseState); + findRulesRoute(router, licenseState, usageCounter); getRuleAlertSummaryRoute(router, licenseState); getRuleStateRoute(router, licenseState); healthRoute(router, licenseState, encryptedSavedObjects); diff --git a/x-pack/plugins/alerting/server/routes/legacy/aggregate.test.ts b/x-pack/plugins/alerting/server/routes/legacy/aggregate.test.ts index d08e970eef69d..cab779a42ce20 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/aggregate.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/aggregate.test.ts @@ -12,6 +12,7 @@ import { verifyApiAccess } from '../../lib/license_api_access'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { trackLegacyTerminology } from '../lib/track_legacy_terminology'; import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; const rulesClient = rulesClientMock.create(); @@ -26,6 +27,10 @@ jest.mock('../../lib/license_api_access.ts', () => ({ verifyApiAccess: jest.fn(), })); +jest.mock('../lib/track_legacy_terminology', () => ({ + trackLegacyTerminology: jest.fn(), +})); + beforeEach(() => { jest.resetAllMocks(); }); @@ -166,4 +171,29 @@ describe('aggregateAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('aggregate', mockUsageCounter); }); + + it('should track calls with deprecated param values', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + aggregateAlertRoute(router, licenseState, mockUsageCounter); + const [, handler] = router.get.mock.calls[0]; + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + params: {}, + query: { + search_fields: ['alertTypeId:1', 'message:foo'], + search: 'alertTypeId:2', + }, + }, + ['ok'] + ); + await handler(context, req, res); + expect(trackLegacyTerminology).toHaveBeenCalledTimes(1); + expect((trackLegacyTerminology as jest.Mock).mock.calls[0][0]).toStrictEqual([ + 'alertTypeId:2', + ['alertTypeId:1', 'message:foo'], + ]); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/aggregate.ts b/x-pack/plugins/alerting/server/routes/legacy/aggregate.ts index d1e8d98a95409..bd4aa7750738c 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/aggregate.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/aggregate.ts @@ -14,6 +14,7 @@ import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; import { renameKeys } from './../lib/rename_keys'; import { FindOptions } from '../../rules_client'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { trackLegacyTerminology } from '../lib/track_legacy_terminology'; // config definition const querySchema = schema.object({ @@ -55,6 +56,10 @@ export const aggregateAlertRoute = ( const rulesClient = context.alerting.getRulesClient(); trackLegacyRouteUsage('aggregate', usageCounter); + trackLegacyTerminology( + [req.query.search, req.query.search_fields].filter(Boolean) as string[], + usageCounter + ); const query = req.query; const renameMap = { diff --git a/x-pack/plugins/alerting/server/routes/legacy/find.test.ts b/x-pack/plugins/alerting/server/routes/legacy/find.test.ts index de12c62f1e4fd..ef346fab1e621 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/find.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.test.ts @@ -12,6 +12,7 @@ import { verifyApiAccess } from '../../lib/license_api_access'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { trackLegacyTerminology } from '../lib/track_legacy_terminology'; const rulesClient = rulesClientMock.create(); @@ -23,6 +24,10 @@ jest.mock('../../lib/track_legacy_route_usage', () => ({ trackLegacyRouteUsage: jest.fn(), })); +jest.mock('../lib/track_legacy_terminology', () => ({ + trackLegacyTerminology: jest.fn(), +})); + beforeEach(() => { jest.resetAllMocks(); }); @@ -160,4 +165,59 @@ describe('findAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('find', mockUsageCounter); }); + + it('should track calls with deprecated param values', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); + const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); + + findAlertRoute(router, licenseState, mockUsageCounter); + const [, handler] = router.get.mock.calls[0]; + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + params: {}, + query: { + search_fields: ['alertTypeId:1', 'message:foo'], + search: 'alertTypeId:2', + sort_field: 'alertTypeId', + }, + }, + ['ok'] + ); + await handler(context, req, res); + expect(trackLegacyTerminology).toHaveBeenCalledTimes(1); + expect((trackLegacyTerminology as jest.Mock).mock.calls[0][0]).toStrictEqual([ + 'alertTypeId:2', + ['alertTypeId:1', 'message:foo'], + 'alertTypeId', + ]); + }); + + it('should track calls to deprecated functionality', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); + const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); + + findAlertRoute(router, licenseState, mockUsageCounter); + const [, handler] = router.get.mock.calls[0]; + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + params: {}, + query: { + fields: ['foo', 'bar'], + }, + }, + ['ok'] + ); + await handler(context, req, res); + expect(mockUsageCounter.incrementCounter).toHaveBeenCalledWith({ + counterName: `legacyAlertingFieldsUsage`, + counterType: 'alertingFieldsUsage', + incrementBy: 1, + }); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/find.ts b/x-pack/plugins/alerting/server/routes/legacy/find.ts index f915f0e15afb6..328fade491642 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/find.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.ts @@ -15,6 +15,7 @@ import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; import { renameKeys } from './../lib/rename_keys'; import { FindOptions } from '../../rules_client'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { trackLegacyTerminology } from '../lib/track_legacy_terminology'; // config definition const querySchema = schema.object({ @@ -59,6 +60,12 @@ export const findAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('find', usageCounter); + trackLegacyTerminology( + [req.query.search, req.query.search_fields, req.query.sort_field].filter( + Boolean + ) as string[], + usageCounter + ); const rulesClient = context.alerting.getRulesClient(); const query = req.query; @@ -82,6 +89,14 @@ export const findAlertRoute = ( : [query.search_fields]; } + if (query.fields) { + usageCounter?.incrementCounter({ + counterName: `legacyAlertingFieldsUsage`, + counterType: 'alertingFieldsUsage', + incrementBy: 1, + }); + } + const findResult = await rulesClient.find({ options }); return res.ok({ body: findResult, diff --git a/x-pack/plugins/alerting/server/routes/lib/track_legacy_terminology.test.ts b/x-pack/plugins/alerting/server/routes/lib/track_legacy_terminology.test.ts new file mode 100644 index 0000000000000..5c6838e144aa2 --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/lib/track_legacy_terminology.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; +import { trackLegacyTerminology, LEGACY_TERMS } from './track_legacy_terminology'; + +describe('trackLegacyTerminology', () => { + it('should call `usageCounter.incrementCounter`', () => { + const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); + const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); + + trackLegacyTerminology( + ['shouldNotMatch', LEGACY_TERMS.map((lt) => `${lt}foo`)], + mockUsageCounter + ); + expect(mockUsageCounter.incrementCounter).toHaveBeenCalledTimes(LEGACY_TERMS.length); + LEGACY_TERMS.forEach((legacyTerm, index) => { + expect((mockUsageCounter.incrementCounter as jest.Mock).mock.calls[index][0]).toStrictEqual({ + counterName: `legacyTerm_${legacyTerm}`, + counterType: 'legacyTerminology', + incrementBy: 1, + }); + }); + }); + + it('should do nothing if no usage counter is provided', () => { + let err; + try { + trackLegacyTerminology(['test'], undefined); + } catch (e) { + err = e; + } + expect(err).toBeUndefined(); + }); + + it('should do nothing if no terms are provided', () => { + let err; + try { + trackLegacyTerminology([], undefined); + } catch (e) { + err = e; + } + expect(err).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/alerting/server/routes/lib/track_legacy_terminology.ts b/x-pack/plugins/alerting/server/routes/lib/track_legacy_terminology.ts new file mode 100644 index 0000000000000..e825cb990fc4d --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/lib/track_legacy_terminology.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { flatten } from 'lodash'; +import { UsageCounter } from 'src/plugins/usage_collection/server'; + +export const LEGACY_TERMS = ['alertTypeId', 'actionTypeId']; + +export function trackLegacyTerminology( + terms: Array, + usageCounter?: UsageCounter +) { + if (!usageCounter) { + return null; + } + + if (!terms || terms.length === 0) { + return null; + } + + for (const legacyTerm of LEGACY_TERMS) { + for (const term of flatten(terms)) { + if (term.includes(legacyTerm)) { + usageCounter.incrementCounter({ + counterName: `legacyTerm_${legacyTerm}`, + counterType: 'legacyTerminology', + incrementBy: 1, + }); + } + } + } +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumHome.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumHome.tsx index 505fd5c1020b3..bbc77bcabca52 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumHome.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumHome.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiTitle, EuiFlexItem } from '@elastic/eui'; import { RumOverview } from '../RumDashboard'; @@ -18,6 +18,7 @@ import { UserPercentile } from './UserPercentile'; import { useBreakpoints } from '../../../hooks/use_breakpoints'; import { KibanaPageTemplateProps } from '../../../../../../../src/plugins/kibana_react/public'; import { useHasRumData } from './hooks/useHasRumData'; +import { EmptyStateLoading } from './empty_state_loading'; export const UX_LABEL = i18n.translate('xpack.apm.ux.title', { defaultMessage: 'Dashboard', @@ -29,7 +30,7 @@ export function RumHome() { const { isSmall, isXXL } = useBreakpoints(); - const { data: rumHasData } = useHasRumData(); + const { data: rumHasData, status } = useHasRumData(); const envStyle = isSmall ? {} : { maxWidth: 500 }; @@ -58,31 +59,38 @@ export function RumHome() { } : undefined; + const isLoading = status === 'loading'; + return ( - - , -

- -
, - , - , - ], - } - : { children: } - } - > - - - + + + , +
+ +
, + , + , + ], + } + : { children: } + } + > + {isLoading && } +
+ +
+
+
+
); } diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts index f1b5b67da21f1..ce42b530b80f5 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts @@ -15,6 +15,7 @@ import { COLOR_MAP_TYPE, FIELD_ORIGIN, LABEL_BORDER_SIZES, + LAYER_TYPE, SOURCE_TYPES, STYLE_TYPE, SYMBOLIZE_AS_TYPES, @@ -154,7 +155,7 @@ export function useLayerList() { maxZoom: 24, alpha: 0.75, visible: true, - type: 'VECTOR', + type: LAYER_TYPE.VECTOR, }; ES_TERM_SOURCE_REGION.whereQuery = getWhereQuery(serviceName!); @@ -178,7 +179,7 @@ export function useLayerList() { maxZoom: 24, alpha: 0.75, visible: true, - type: 'VECTOR', + type: LAYER_TYPE.VECTOR, }; return [ diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/empty_state_loading.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/empty_state_loading.tsx new file mode 100644 index 0000000000000..b02672721ce8e --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/empty_state_loading.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiEmptyPrompt, + EuiLoadingSpinner, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { Fragment } from 'react'; + +export function EmptyStateLoading() { + return ( + + + + +

+ {i18n.translate('xpack.apm.emptyState.loadingMessage', { + defaultMessage: 'Loading…', + })} +

+
+ + } + /> + ); +} diff --git a/x-pack/plugins/apm/public/components/app/correlations/custom_fields.tsx b/x-pack/plugins/apm/public/components/app/correlations/custom_fields.tsx deleted file mode 100644 index 9a13c44602c2d..0000000000000 --- a/x-pack/plugins/apm/public/components/app/correlations/custom_fields.tsx +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiFlexGroup, - EuiFlexItem, - EuiAccordion, - EuiComboBox, - EuiFormRow, - EuiLink, - EuiSelect, - EuiSpacer, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useEffect, useState } from 'react'; -import { useFieldNames } from './use_field_names'; -import { ElasticDocsLink } from '../../shared/Links/ElasticDocsLink'; -import { useUiTracker } from '../../../../../observability/public'; - -interface Props { - fieldNames: string[]; - setFieldNames: (fieldNames: string[]) => void; - setDurationPercentile?: (value: PercentileOption) => void; - showThreshold?: boolean; - durationPercentile?: PercentileOption; -} - -export type PercentileOption = 50 | 75 | 99; -const percentilOptions: PercentileOption[] = [50, 75, 99]; - -export function CustomFields({ - fieldNames, - setFieldNames, - setDurationPercentile = () => {}, - showThreshold = false, - durationPercentile = 75, -}: Props) { - const trackApmEvent = useUiTracker({ app: 'apm' }); - const { defaultFieldNames, getSuggestions } = useFieldNames(); - const [suggestedFieldNames, setSuggestedFieldNames] = useState( - getSuggestions('') - ); - - useEffect(() => { - if (suggestedFieldNames.length) { - return; - } - setSuggestedFieldNames(getSuggestions('')); - }, [getSuggestions, suggestedFieldNames]); - - return ( - - - - {showThreshold && ( - - - ({ - value: percentile, - text: i18n.translate( - 'xpack.apm.correlations.customize.thresholdPercentile', - { - defaultMessage: '{percentile}th percentile', - values: { percentile }, - } - ), - }))} - onChange={(e) => { - setDurationPercentile( - parseInt(e.target.value, 10) as PercentileOption - ); - }} - /> - - - )} - - { - setFieldNames(defaultFieldNames); - }} - > - {i18n.translate( - 'xpack.apm.correlations.customize.fieldHelpTextReset', - { defaultMessage: 'reset' } - )} - - ), - docsLink: ( - - {i18n.translate( - 'xpack.apm.correlations.customize.fieldHelpTextDocsLink', - { - defaultMessage: - 'Learn more about the default fields.', - } - )} - - ), - }} - /> - } - > - ({ label }))} - onChange={(options) => { - const nextFieldNames = options.map((option) => option.label); - setFieldNames(nextFieldNames); - trackApmEvent({ metric: 'customize_correlations_fields' }); - }} - onCreateOption={(term) => { - const nextFieldNames = [...fieldNames, term]; - setFieldNames(nextFieldNames); - }} - onSearchChange={(searchValue) => { - setSuggestedFieldNames(getSuggestions(searchValue)); - }} - options={suggestedFieldNames.map((label) => ({ label }))} - /> - - - - - ); -} diff --git a/x-pack/plugins/apm/public/components/app/correlations/use_field_names.ts b/x-pack/plugins/apm/public/components/app/correlations/use_field_names.ts deleted file mode 100644 index ff88808c51d15..0000000000000 --- a/x-pack/plugins/apm/public/components/app/correlations/use_field_names.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { memoize } from 'lodash'; -import { useEffect, useMemo, useState } from 'react'; -import { isRumAgentName } from '../../../../common/agent_name'; -import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; -import { useDynamicIndexPatternFetcher } from '../../../hooks/use_dynamic_index_pattern'; - -interface IndexPattern { - fields: Array<{ name: string; esTypes: string[] }>; -} - -export function useFieldNames() { - const { agentName } = useApmServiceContext(); - const isRumAgent = isRumAgentName(agentName); - const { indexPattern } = useDynamicIndexPatternFetcher(); - - const [defaultFieldNames, setDefaultFieldNames] = useState( - getDefaultFieldNames(indexPattern, isRumAgent) - ); - - const getSuggestions = useMemo( - () => - memoize((searchValue: string) => - getMatchingFieldNames(indexPattern, searchValue) - ), - [indexPattern] - ); - - useEffect(() => { - setDefaultFieldNames(getDefaultFieldNames(indexPattern, isRumAgent)); - }, [indexPattern, isRumAgent]); - - return { defaultFieldNames, getSuggestions }; -} - -function getMatchingFieldNames( - indexPattern: IndexPattern | undefined, - inputValue: string -) { - if (!indexPattern) { - return []; - } - return indexPattern.fields - .filter( - ({ name, esTypes }) => - name.startsWith(inputValue) && esTypes[0] === 'keyword' // only show fields of type 'keyword' - ) - .map(({ name }) => name); -} - -function getDefaultFieldNames( - indexPattern: IndexPattern | undefined, - isRumAgent: boolean -) { - const labelFields = getMatchingFieldNames(indexPattern, 'labels.').slice( - 0, - 6 - ); - return isRumAgent - ? [ - ...labelFields, - 'user_agent.name', - 'user_agent.os.name', - 'url.original', - ...getMatchingFieldNames(indexPattern, 'user.').slice(0, 6), - ] - : [...labelFields, 'service.version', 'service.node.name', 'host.ip']; -} diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx index e8a159f23ee3d..535fb777166bb 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx @@ -256,6 +256,7 @@ export function TransactionDistributionChart({ /> {data.map((d, i) => ( = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], exposeToBrowser: { serviceMapEnabled: true, ui: true, profilingEnabled: true, }, - schema: schema.object({ - enabled: schema.boolean({ defaultValue: true }), - serviceMapEnabled: schema.boolean({ defaultValue: true }), - serviceMapFingerprintBucketSize: schema.number({ defaultValue: 100 }), - serviceMapTraceIdBucketSize: schema.number({ defaultValue: 65 }), - serviceMapFingerprintGlobalBucketSize: schema.number({ - defaultValue: 1000, - }), - serviceMapTraceIdGlobalBucketSize: schema.number({ defaultValue: 6 }), - serviceMapMaxTracesPerRequest: schema.number({ defaultValue: 50 }), - autocreateApmIndexPattern: schema.boolean({ defaultValue: true }), - ui: schema.object({ - enabled: schema.boolean({ defaultValue: true }), - transactionGroupBucketSize: schema.number({ defaultValue: 1000 }), - maxTraceItems: schema.number({ defaultValue: 1000 }), - }), - searchAggregatedTransactions: schema.oneOf( - [ - schema.literal(SearchAggregatedTransactionSetting.auto), - schema.literal(SearchAggregatedTransactionSetting.always), - schema.literal(SearchAggregatedTransactionSetting.never), - ], - { defaultValue: SearchAggregatedTransactionSetting.auto } - ), - telemetryCollectionEnabled: schema.boolean({ defaultValue: true }), - metricsInterval: schema.number({ defaultValue: 30 }), - maxServiceEnvironments: schema.number({ defaultValue: 100 }), - maxServiceSelection: schema.number({ defaultValue: 50 }), - profilingEnabled: schema.boolean({ defaultValue: false }), - agent: schema.object({ - migrations: schema.object({ - enabled: schema.boolean({ defaultValue: false }), - }), - }), - }), + schema: configSchema, }; -export type APMXPackConfig = TypeOf; +export type APMXPackConfig = TypeOf; export type APMConfig = ReturnType; // plugin config and ui indices settings diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_interval.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_interval.test.ts deleted file mode 100644 index e6cf926d20bd7..0000000000000 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_interval.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { estypes } from '@elastic/elasticsearch'; - -import type { ElasticsearchClient } from 'src/core/server'; -import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; - -import { - fetchTransactionDurationHistogramInterval, - getHistogramIntervalRequest, -} from './query_histogram_interval'; - -const params = { - index: 'apm-*', - start: '2020', - end: '2021', - includeFrozen: false, - environment: ENVIRONMENT_ALL.value, - kuery: '', -}; - -describe('query_histogram_interval', () => { - describe('getHistogramIntervalRequest', () => { - it('returns the request body for the transaction duration ranges aggregation', () => { - const req = getHistogramIntervalRequest(params); - - expect(req).toEqual({ - body: { - aggs: { - transaction_duration_max: { - max: { - field: 'transaction.duration.us', - }, - }, - transaction_duration_min: { - min: { - field: 'transaction.duration.us', - }, - }, - }, - query: { - bool: { - filter: [ - { - term: { - 'processor.event': 'transaction', - }, - }, - { - range: { - '@timestamp': { - format: 'epoch_millis', - gte: 1577836800000, - lte: 1609459200000, - }, - }, - }, - ], - }, - }, - size: 0, - }, - index: params.index, - ignore_throttled: !params.includeFrozen, - ignore_unavailable: true, - }); - }); - }); - - describe('fetchTransactionDurationHistogramInterval', () => { - it('fetches the interval duration for histograms', async () => { - const esClientSearchMock = jest.fn( - ( - req: estypes.SearchRequest - ): { - body: estypes.SearchResponse; - } => { - return { - body: { - aggregations: { - transaction_duration_max: { - value: 10000, - }, - transaction_duration_min: { - value: 10, - }, - }, - } as unknown as estypes.SearchResponse, - }; - } - ); - - const esClientMock = { - search: esClientSearchMock, - } as unknown as ElasticsearchClient; - - const resp = await fetchTransactionDurationHistogramInterval( - esClientMock, - params - ); - - expect(resp).toEqual(10); - expect(esClientSearchMock).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_interval.ts b/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_interval.ts deleted file mode 100644 index 906105003b716..0000000000000 --- a/x-pack/plugins/apm/server/lib/search_strategies/queries/query_histogram_interval.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { estypes } from '@elastic/elasticsearch'; - -import type { ElasticsearchClient } from 'src/core/server'; - -import { TRANSACTION_DURATION } from '../../../../common/elasticsearch_fieldnames'; -import type { SearchStrategyParams } from '../../../../common/search_strategies/types'; - -import { getQueryWithParams } from './get_query_with_params'; -import { getRequestBase } from './get_request_base'; - -const HISTOGRAM_INTERVALS = 1000; - -export const getHistogramIntervalRequest = ( - params: SearchStrategyParams -): estypes.SearchRequest => ({ - ...getRequestBase(params), - body: { - query: getQueryWithParams({ params }), - size: 0, - aggs: { - transaction_duration_min: { min: { field: TRANSACTION_DURATION } }, - transaction_duration_max: { max: { field: TRANSACTION_DURATION } }, - }, - }, -}); - -export const fetchTransactionDurationHistogramInterval = async ( - esClient: ElasticsearchClient, - params: SearchStrategyParams -): Promise => { - const resp = await esClient.search(getHistogramIntervalRequest(params)); - - if (resp.body.aggregations === undefined) { - throw new Error( - 'fetchTransactionDurationHistogramInterval failed, did not return aggregations.' - ); - } - - const transactionDurationDelta = - ( - resp.body.aggregations - .transaction_duration_max as estypes.AggregationsValueAggregate - ).value - - ( - resp.body.aggregations - .transaction_duration_min as estypes.AggregationsValueAggregate - ).value; - - return transactionDurationDelta / (HISTOGRAM_INTERVALS - 1); -}; diff --git a/x-pack/plugins/apm/server/lib/search_strategies/search_strategy_provider.test.ts b/x-pack/plugins/apm/server/lib/search_strategies/search_strategy_provider.test.ts index b56ab83f547ff..6e03c879f9b97 100644 --- a/x-pack/plugins/apm/server/lib/search_strategies/search_strategy_provider.test.ts +++ b/x-pack/plugins/apm/server/lib/search_strategies/search_strategy_provider.test.ts @@ -57,17 +57,6 @@ const clientSearchMock = ( aggregations = { transaction_duration_percentiles: { values: {} } }; } - // fetchTransactionDurationHistogramInterval - if ( - aggs.transaction_duration_min !== undefined && - aggs.transaction_duration_max !== undefined - ) { - aggregations = { - transaction_duration_min: { value: 0 }, - transaction_duration_max: { value: 1234 }, - }; - } - // fetchTransactionDurationCorrelation if (aggs.logspace_ranges !== undefined) { aggregations = { logspace_ranges: { buckets: [] } }; diff --git a/x-pack/plugins/apm/server/routes/correlations.ts b/x-pack/plugins/apm/server/routes/correlations.ts deleted file mode 100644 index 4728aa2e8d3f6..0000000000000 --- a/x-pack/plugins/apm/server/routes/correlations.ts +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import Boom from '@hapi/boom'; -import { i18n } from '@kbn/i18n'; -import * as t from 'io-ts'; -import { isActivePlatinumLicense } from '../../common/license_check'; -import { getCorrelationsForFailedTransactions } from '../lib/correlations/errors/get_correlations_for_failed_transactions'; -import { getOverallErrorTimeseries } from '../lib/correlations/errors/get_overall_error_timeseries'; -import { getCorrelationsForSlowTransactions } from '../lib/correlations/latency/get_correlations_for_slow_transactions'; -import { getOverallLatencyDistribution } from '../lib/correlations/latency/get_overall_latency_distribution'; -import { setupRequest } from '../lib/helpers/setup_request'; -import { createApmServerRoute } from './create_apm_server_route'; -import { createApmServerRouteRepository } from './create_apm_server_route_repository'; -import { environmentRt, kueryRt, rangeRt } from './default_api_types'; - -const INVALID_LICENSE = i18n.translate( - 'xpack.apm.significanTerms.license.text', - { - defaultMessage: - 'To use the correlations API, you must be subscribed to an Elastic Platinum license.', - } -); - -const correlationsLatencyDistributionRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/correlations/latency/overall_distribution', - params: t.type({ - query: t.intersection([ - t.partial({ - serviceName: t.string, - transactionName: t.string, - transactionType: t.string, - }), - environmentRt, - kueryRt, - rangeRt, - ]), - }), - options: { tags: ['access:apm'] }, - handler: async (resources) => { - const { context, params } = resources; - if (!isActivePlatinumLicense(context.licensing.license)) { - throw Boom.forbidden(INVALID_LICENSE); - } - const setup = await setupRequest(resources); - const { - environment, - kuery, - serviceName, - transactionType, - transactionName, - } = params.query; - - return getOverallLatencyDistribution({ - environment, - kuery, - serviceName, - transactionType, - transactionName, - setup, - }); - }, -}); - -const correlationsForSlowTransactionsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/correlations/latency/slow_transactions', - params: t.type({ - query: t.intersection([ - t.partial({ - serviceName: t.string, - transactionName: t.string, - transactionType: t.string, - }), - t.type({ - durationPercentile: t.string, - fieldNames: t.string, - maxLatency: t.string, - distributionInterval: t.string, - }), - environmentRt, - kueryRt, - rangeRt, - ]), - }), - options: { tags: ['access:apm'] }, - handler: async (resources) => { - const { context, params } = resources; - - if (!isActivePlatinumLicense(context.licensing.license)) { - throw Boom.forbidden(INVALID_LICENSE); - } - const setup = await setupRequest(resources); - const { - environment, - kuery, - serviceName, - transactionType, - transactionName, - durationPercentile, - fieldNames, - maxLatency, - distributionInterval, - } = params.query; - - return getCorrelationsForSlowTransactions({ - environment, - kuery, - serviceName, - transactionType, - transactionName, - durationPercentile: parseInt(durationPercentile, 10), - fieldNames: fieldNames.split(','), - setup, - maxLatency: parseInt(maxLatency, 10), - distributionInterval: parseInt(distributionInterval, 10), - }); - }, -}); - -const correlationsErrorDistributionRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/correlations/errors/overall_timeseries', - params: t.type({ - query: t.intersection([ - t.partial({ - serviceName: t.string, - transactionName: t.string, - transactionType: t.string, - }), - environmentRt, - kueryRt, - rangeRt, - ]), - }), - options: { tags: ['access:apm'] }, - handler: async (resources) => { - const { params, context } = resources; - - if (!isActivePlatinumLicense(context.licensing.license)) { - throw Boom.forbidden(INVALID_LICENSE); - } - const setup = await setupRequest(resources); - const { - environment, - kuery, - serviceName, - transactionType, - transactionName, - } = params.query; - - return getOverallErrorTimeseries({ - environment, - kuery, - serviceName, - transactionType, - transactionName, - setup, - }); - }, -}); - -const correlationsForFailedTransactionsRoute = createApmServerRoute({ - endpoint: 'GET /api/apm/correlations/errors/failed_transactions', - params: t.type({ - query: t.intersection([ - t.partial({ - serviceName: t.string, - transactionName: t.string, - transactionType: t.string, - }), - t.type({ - fieldNames: t.string, - }), - environmentRt, - kueryRt, - rangeRt, - ]), - }), - options: { tags: ['access:apm'] }, - handler: async (resources) => { - const { context, params } = resources; - if (!isActivePlatinumLicense(context.licensing.license)) { - throw Boom.forbidden(INVALID_LICENSE); - } - const setup = await setupRequest(resources); - const { - environment, - kuery, - serviceName, - transactionType, - transactionName, - fieldNames, - } = params.query; - - return getCorrelationsForFailedTransactions({ - environment, - kuery, - serviceName, - transactionType, - transactionName, - fieldNames: fieldNames.split(','), - setup, - }); - }, -}); - -export const correlationsRouteRepository = createApmServerRouteRepository() - .add(correlationsLatencyDistributionRoute) - .add(correlationsForSlowTransactionsRoute) - .add(correlationsErrorDistributionRoute) - .add(correlationsForFailedTransactionsRoute); diff --git a/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts b/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts index 9bc9108da9055..09756e30d9682 100644 --- a/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts +++ b/x-pack/plugins/apm/server/routes/get_global_apm_server_route_repository.ts @@ -12,7 +12,6 @@ import type { import { PickByValue } from 'utility-types'; import { alertsChartPreviewRouteRepository } from './alerts/chart_preview'; import { backendsRouteRepository } from './backends'; -import { correlationsRouteRepository } from './correlations'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; import { environmentsRouteRepository } from './environments'; import { errorsRouteRepository } from './errors'; @@ -49,7 +48,6 @@ const getTypedGlobalApmServerRouteRepository = () => { .merge(traceRouteRepository) .merge(transactionRouteRepository) .merge(alertsChartPreviewRouteRepository) - .merge(correlationsRouteRepository) .merge(agentConfigurationRouteRepository) .merge(anomalyDetectionRouteRepository) .merge(apmIndicesRouteRepository) diff --git a/x-pack/plugins/canvas/public/application.tsx b/x-pack/plugins/canvas/public/application.tsx index 30b2d78a6b1fe..f2fe944bfd45d 100644 --- a/x-pack/plugins/canvas/public/application.tsx +++ b/x-pack/plugins/canvas/public/application.tsx @@ -98,11 +98,10 @@ export const initializeCanvas = async ( setupPlugins: CanvasSetupDeps, startPlugins: CanvasStartDeps, registries: SetupRegistries, - appUpdater: BehaviorSubject, - pluginServices: PluginServices + appUpdater: BehaviorSubject ) => { await startLegacyServices(coreSetup, coreStart, setupPlugins, startPlugins, appUpdater); - const { expressions } = pluginServices.getServices(); + const { expressions } = setupPlugins; // Adding these functions here instead of in plugin.ts. // Some of these functions have deep dependencies into Canvas, which was bulking up the size diff --git a/x-pack/plugins/canvas/public/plugin.tsx b/x-pack/plugins/canvas/public/plugin.tsx index 555cedb6b16a1..bd5d884f1485c 100644 --- a/x-pack/plugins/canvas/public/plugin.tsx +++ b/x-pack/plugins/canvas/public/plugin.tsx @@ -132,8 +132,7 @@ export class CanvasPlugin setupPlugins, startPlugins, registries, - this.appUpdater, - pluginServices + this.appUpdater ); const unmount = renderApp({ coreStart, startPlugins, params, canvasStore, pluginServices }); diff --git a/x-pack/plugins/canvas/public/services/expressions.ts b/x-pack/plugins/canvas/public/services/expressions.ts index a1af0fba50a5c..01bb0adb17711 100644 --- a/x-pack/plugins/canvas/public/services/expressions.ts +++ b/x-pack/plugins/canvas/public/services/expressions.ts @@ -5,6 +5,6 @@ * 2.0. */ -import { ExpressionsService } from '../../../../../src/plugins/expressions/public'; +import { ExpressionsServiceStart } from '../../../../../src/plugins/expressions/public'; -export type CanvasExpressionsService = ExpressionsService; +export type CanvasExpressionsService = ExpressionsServiceStart; diff --git a/x-pack/plugins/canvas/public/services/kibana/expressions.ts b/x-pack/plugins/canvas/public/services/kibana/expressions.ts index 4e3bb52a5d449..780de5309d97e 100644 --- a/x-pack/plugins/canvas/public/services/kibana/expressions.ts +++ b/x-pack/plugins/canvas/public/services/kibana/expressions.ts @@ -16,4 +16,4 @@ export type CanvasExpressionsServiceFactory = KibanaPluginServiceFactory< >; export const expressionsServiceFactory: CanvasExpressionsServiceFactory = ({ startPlugins }) => - startPlugins.expressions.fork(); + startPlugins.expressions; diff --git a/x-pack/plugins/canvas/server/saved_objects/workpad_references.ts b/x-pack/plugins/canvas/server/saved_objects/workpad_references.ts index b0d20add2f79a..e9eefa1bdb3f4 100644 --- a/x-pack/plugins/canvas/server/saved_objects/workpad_references.ts +++ b/x-pack/plugins/canvas/server/saved_objects/workpad_references.ts @@ -6,14 +6,15 @@ */ import { fromExpression, toExpression } from '@kbn/interpreter/common'; +import { PersistableStateService } from '../../../../../src/plugins/kibana_utils/common'; import { SavedObjectReference } from '../../../../../src/core/server'; import { WorkpadAttributes } from '../routes/workpad/workpad_attributes'; -import { ExpressionsServerSetup } from '../../../../../src/plugins/expressions/server'; +import type { ExpressionAstExpression } from '../../../../../src/plugins/expressions'; export const extractReferences = ( workpad: WorkpadAttributes, - expressions: ExpressionsServerSetup + expressions: PersistableStateService ): { workpad: WorkpadAttributes; references: SavedObjectReference[] } => { // We need to find every element in the workpad and extract references const references: SavedObjectReference[] = []; @@ -42,7 +43,7 @@ export const extractReferences = ( export const injectReferences = ( workpad: WorkpadAttributes, references: SavedObjectReference[], - expressions: ExpressionsServerSetup + expressions: PersistableStateService ) => { const pages = workpad.pages.map((page) => { const elements = page.elements.map((element) => { diff --git a/x-pack/plugins/cases/common/api/cases/case.ts b/x-pack/plugins/cases/common/api/cases/case.ts index 37a491cdad4c0..cd26ca0bab977 100644 --- a/x-pack/plugins/cases/common/api/cases/case.ts +++ b/x-pack/plugins/cases/common/api/cases/case.ts @@ -87,8 +87,11 @@ const CaseBasicRt = rt.type({ owner: rt.string, }); -export const CaseExternalServiceBasicRt = rt.type({ - connector_id: rt.union([rt.string, rt.null]), +/** + * This represents the push to service UserAction. It lacks the connector_id because that is stored in a different field + * within the user action object in the API response. + */ +export const CaseUserActionExternalServiceRt = rt.type({ connector_name: rt.string, external_id: rt.string, external_title: rt.string, @@ -97,7 +100,14 @@ export const CaseExternalServiceBasicRt = rt.type({ pushed_by: UserRT, }); -const CaseFullExternalServiceRt = rt.union([CaseExternalServiceBasicRt, rt.null]); +export const CaseExternalServiceBasicRt = rt.intersection([ + rt.type({ + connector_id: rt.union([rt.string, rt.null]), + }), + CaseUserActionExternalServiceRt, +]); + +export const CaseFullExternalServiceRt = rt.union([CaseExternalServiceBasicRt, rt.null]); export const CaseAttributesRt = rt.intersection([ CaseBasicRt, @@ -244,6 +254,16 @@ export const CaseResponseRt = rt.intersection([ }), ]); +export const CaseResolveResponseRt = rt.intersection([ + rt.type({ + case: CaseResponseRt, + outcome: rt.union([rt.literal('exactMatch'), rt.literal('aliasMatch'), rt.literal('conflict')]), + }), + rt.partial({ + alias_target_id: rt.string, + }), +]); + export const CasesFindResponseRt = rt.intersection([ rt.type({ cases: rt.array(CaseResponseRt), @@ -309,6 +329,7 @@ export type CaseAttributes = rt.TypeOf; export type CasesClientPostRequest = rt.TypeOf; export type CasePostRequest = rt.TypeOf; export type CaseResponse = rt.TypeOf; +export type CaseResolveResponse = rt.TypeOf; export type CasesResponse = rt.TypeOf; export type CasesFindRequest = rt.TypeOf; export type CasesByAlertIDRequest = rt.TypeOf; diff --git a/x-pack/plugins/cases/common/api/cases/user_actions.ts b/x-pack/plugins/cases/common/api/cases/user_actions.ts index 03912c550d77a..e86ce5248a6f9 100644 --- a/x-pack/plugins/cases/common/api/cases/user_actions.ts +++ b/x-pack/plugins/cases/common/api/cases/user_actions.ts @@ -34,7 +34,6 @@ const UserActionRt = rt.union([ rt.literal('push-to-service'), ]); -// TO DO change state to status const CaseUserActionBasicRT = rt.type({ action_field: UserActionFieldRt, action: UserActionRt, @@ -51,6 +50,8 @@ const CaseUserActionResponseRT = rt.intersection([ action_id: rt.string, case_id: rt.string, comment_id: rt.union([rt.string, rt.null]), + new_val_connector_id: rt.union([rt.string, rt.null]), + old_val_connector_id: rt.union([rt.string, rt.null]), }), rt.partial({ sub_case_id: rt.string }), ]); diff --git a/x-pack/plugins/cases/common/api/connectors/index.ts b/x-pack/plugins/cases/common/api/connectors/index.ts index 77af90b5d08cb..2b3483b4f6184 100644 --- a/x-pack/plugins/cases/common/api/connectors/index.ts +++ b/x-pack/plugins/cases/common/api/connectors/index.ts @@ -84,14 +84,22 @@ export const ConnectorTypeFieldsRt = rt.union([ ConnectorSwimlaneTypeFieldsRt, ]); +/** + * This type represents the connector's format when it is encoded within a user action. + */ +export const CaseUserActionConnectorRt = rt.intersection([ + rt.type({ name: rt.string }), + ConnectorTypeFieldsRt, +]); + export const CaseConnectorRt = rt.intersection([ rt.type({ id: rt.string, - name: rt.string, }), - ConnectorTypeFieldsRt, + CaseUserActionConnectorRt, ]); +export type CaseUserActionConnector = rt.TypeOf; export type CaseConnector = rt.TypeOf; export type ConnectorTypeFields = rt.TypeOf; export type ConnectorJiraTypeFields = rt.TypeOf; diff --git a/x-pack/plugins/cases/common/index.ts b/x-pack/plugins/cases/common/index.ts index 5305318cc9aa6..d38b1a779981c 100644 --- a/x-pack/plugins/cases/common/index.ts +++ b/x-pack/plugins/cases/common/index.ts @@ -12,3 +12,4 @@ export * from './constants'; export * from './api'; export * from './ui/types'; export * from './utils/connectors_api'; +export * from './utils/user_actions'; diff --git a/x-pack/plugins/cases/common/ui/types.ts b/x-pack/plugins/cases/common/ui/types.ts index bf4ec0da6ee56..948b203af14a8 100644 --- a/x-pack/plugins/cases/common/ui/types.ts +++ b/x-pack/plugins/cases/common/ui/types.ts @@ -66,7 +66,9 @@ export interface CaseUserActions { caseId: string; commentId: string | null; newValue: string | null; + newValConnectorId: string | null; oldValue: string | null; + oldValConnectorId: string | null; } export interface CaseExternalService { @@ -112,6 +114,12 @@ export interface Case extends BasicCase { type: CaseType; } +export interface ResolvedCase { + case: Case; + outcome: 'exactMatch' | 'aliasMatch' | 'conflict'; + aliasTargetId?: string; +} + export interface QueryParams { page: number; perPage: number; diff --git a/x-pack/plugins/cases/common/utils/user_actions.ts b/x-pack/plugins/cases/common/utils/user_actions.ts new file mode 100644 index 0000000000000..7de0d7066eaed --- /dev/null +++ b/x-pack/plugins/cases/common/utils/user_actions.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export function isCreateConnector(action?: string, actionFields?: string[]): boolean { + return action === 'create' && actionFields != null && actionFields.includes('connector'); +} + +export function isUpdateConnector(action?: string, actionFields?: string[]): boolean { + return action === 'update' && actionFields != null && actionFields.includes('connector'); +} + +export function isPush(action?: string, actionFields?: string[]): boolean { + return action === 'push-to-service' && actionFields != null && actionFields.includes('pushed'); +} diff --git a/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.ts b/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.ts index 18370be61bdf1..09f0215f5629f 100644 --- a/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.ts +++ b/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.ts @@ -13,6 +13,7 @@ import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_r import { StartServices } from '../../../types'; import { EuiTheme } from '../../../../../../../src/plugins/kibana_react/common'; import { securityMock } from '../../../../../security/public/mocks'; +import { spacesPluginMock } from '../../../../../spaces/public/mocks'; import { triggersActionsUiMock } from '../../../../../triggers_actions_ui/public/mocks'; export const createStartServicesMock = (): StartServices => @@ -25,6 +26,7 @@ export const createStartServicesMock = (): StartServices => }, security: securityMock.createStart(), triggersActionsUi: triggersActionsUiMock.createStart(), + spaces: spacesPluginMock.createStartContract(), } as unknown as StartServices); export const createWithKibanaMock = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/index.ts b/x-pack/plugins/cases/public/common/user_actions/index.ts similarity index 86% rename from x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/index.ts rename to x-pack/plugins/cases/public/common/user_actions/index.ts index ce1039f6ad0fd..507455f7102a7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/index.ts +++ b/x-pack/plugins/cases/public/common/user_actions/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { UserIcon } from './user_icon'; +export * from './parsers'; diff --git a/x-pack/plugins/cases/public/common/user_actions/parsers.test.ts b/x-pack/plugins/cases/public/common/user_actions/parsers.test.ts new file mode 100644 index 0000000000000..c6d13cc41686c --- /dev/null +++ b/x-pack/plugins/cases/public/common/user_actions/parsers.test.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ConnectorTypes, noneConnectorId } from '../../../common'; +import { parseStringAsConnector, parseStringAsExternalService } from './parsers'; + +describe('user actions utility functions', () => { + describe('parseStringAsConnector', () => { + it('return null if the data is null', () => { + expect(parseStringAsConnector('', null)).toBeNull(); + }); + + it('return null if the data is not a json object', () => { + expect(parseStringAsConnector('', 'blah')).toBeNull(); + }); + + it('return null if the data is not a valid connector', () => { + expect(parseStringAsConnector('', JSON.stringify({ a: '1' }))).toBeNull(); + }); + + it('return null if id is null but the data is a connector other than none', () => { + expect( + parseStringAsConnector( + null, + JSON.stringify({ type: ConnectorTypes.jira, name: '', fields: null }) + ) + ).toBeNull(); + }); + + it('return the id as the none connector if the data is the none connector', () => { + expect( + parseStringAsConnector( + null, + JSON.stringify({ type: ConnectorTypes.none, name: '', fields: null }) + ) + ).toEqual({ id: noneConnectorId, type: ConnectorTypes.none, name: '', fields: null }); + }); + + it('returns a decoded connector with the specified id', () => { + expect( + parseStringAsConnector( + 'a', + JSON.stringify({ type: ConnectorTypes.jira, name: 'hi', fields: null }) + ) + ).toEqual({ id: 'a', type: ConnectorTypes.jira, name: 'hi', fields: null }); + }); + }); + + describe('parseStringAsExternalService', () => { + it('returns null when the data is null', () => { + expect(parseStringAsExternalService('', null)).toBeNull(); + }); + + it('returns null when the data is not valid json', () => { + expect(parseStringAsExternalService('', 'blah')).toBeNull(); + }); + + it('returns null when the data is not a valid external service object', () => { + expect(parseStringAsExternalService('', JSON.stringify({ a: '1' }))).toBeNull(); + }); + + it('returns the decoded external service with the connector_id field added', () => { + const externalServiceInfo = { + connector_name: 'name', + external_id: '1', + external_title: 'title', + external_url: 'abc', + pushed_at: '1', + pushed_by: { + username: 'a', + email: 'a@a.com', + full_name: 'a', + }, + }; + + expect(parseStringAsExternalService('500', JSON.stringify(externalServiceInfo))).toEqual({ + ...externalServiceInfo, + connector_id: '500', + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/common/user_actions/parsers.ts b/x-pack/plugins/cases/public/common/user_actions/parsers.ts new file mode 100644 index 0000000000000..dfea22443aa51 --- /dev/null +++ b/x-pack/plugins/cases/public/common/user_actions/parsers.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + CaseUserActionConnectorRt, + CaseConnector, + ConnectorTypes, + noneConnectorId, + CaseFullExternalService, + CaseUserActionExternalServiceRt, +} from '../../../common'; + +export const parseStringAsConnector = ( + id: string | null, + encodedData: string | null +): CaseConnector | null => { + if (encodedData == null) { + return null; + } + + const decodedConnector = parseString(encodedData); + + if (!CaseUserActionConnectorRt.is(decodedConnector)) { + return null; + } + + if (id == null && decodedConnector.type === ConnectorTypes.none) { + return { + ...decodedConnector, + id: noneConnectorId, + }; + } else if (id == null) { + return null; + } else { + // id does not equal null or undefined and the connector type does not equal none + // so return the connector with its id + return { + ...decodedConnector, + id, + }; + } +}; + +const parseString = (params: string | null): unknown | null => { + if (params == null) { + return null; + } + + try { + return JSON.parse(params); + } catch { + return null; + } +}; + +export const parseStringAsExternalService = ( + id: string | null, + encodedData: string | null +): CaseFullExternalService => { + if (encodedData == null) { + return null; + } + + const decodedExternalService = parseString(encodedData); + if (!CaseUserActionExternalServiceRt.is(decodedExternalService)) { + return null; + } + + return { + ...decodedExternalService, + connector_id: id, + }; +}; diff --git a/x-pack/plugins/cases/public/components/case_view/index.test.tsx b/x-pack/plugins/cases/public/components/case_view/index.test.tsx index f12c8ba098d43..6fc9e1719e1cf 100644 --- a/x-pack/plugins/cases/public/components/case_view/index.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/index.test.tsx @@ -18,6 +18,7 @@ import { getAlertUserAction, } from '../../containers/mock'; import { TestProviders } from '../../common/mock'; +import { SpacesApi } from '../../../../spaces/public'; import { useUpdateCase } from '../../containers/use_update_case'; import { useGetCase } from '../../containers/use_get_case'; import { useGetCaseUserActions } from '../../containers/use_get_case_user_actions'; @@ -47,6 +48,13 @@ const useConnectorsMock = useConnectors as jest.Mock; const usePostPushToServiceMock = usePostPushToService as jest.Mock; const useKibanaMock = useKibana as jest.Mocked; +const spacesUiApiMock = { + redirectLegacyUrl: jest.fn().mockResolvedValue(undefined), + components: { + getLegacyUrlConflict: jest.fn().mockReturnValue(
), + }, +}; + const alertsHit = [ { _id: 'alert-id-1', @@ -138,6 +146,7 @@ describe('CaseView ', () => { isLoading: false, isError: false, data, + resolveOutcome: 'exactMatch', updateCase, fetchCase, }; @@ -174,6 +183,7 @@ describe('CaseView ', () => { actionTypeTitle: '.servicenow', iconClass: 'logoSecurity', }); + useKibanaMock().services.spaces = { ui: spacesUiApiMock } as unknown as SpacesApi; }); it('should render CaseComponent', async () => { @@ -395,36 +405,7 @@ describe('CaseView ', () => { })); const wrapper = mount( - + ); await waitFor(() => { @@ -439,36 +420,7 @@ describe('CaseView ', () => { })); const wrapper = mount( - + ); await waitFor(() => { @@ -477,43 +429,66 @@ describe('CaseView ', () => { }); it('should return case view when data is there', async () => { - (useGetCase as jest.Mock).mockImplementation(() => defaultGetCase); + (useGetCase as jest.Mock).mockImplementation(() => ({ + ...defaultGetCase, + resolveOutcome: 'exactMatch', + })); const wrapper = mount( - + ); await waitFor(() => { expect(wrapper.find('[data-test-subj="case-view-title"]').exists()).toBeTruthy(); + expect(spacesUiApiMock.components.getLegacyUrlConflict).not.toHaveBeenCalled(); + expect(spacesUiApiMock.redirectLegacyUrl).not.toHaveBeenCalled(); + }); + }); + + it('should redirect case view when resolves to alias match', async () => { + const resolveAliasId = `${defaultGetCase.data.id}_2`; + (useGetCase as jest.Mock).mockImplementation(() => ({ + ...defaultGetCase, + resolveOutcome: 'aliasMatch', + resolveAliasId, + })); + const wrapper = mount( + + + + ); + await waitFor(() => { + expect(wrapper.find('[data-test-subj="case-view-title"]').exists()).toBeTruthy(); + expect(spacesUiApiMock.components.getLegacyUrlConflict).not.toHaveBeenCalled(); + expect(spacesUiApiMock.redirectLegacyUrl).toHaveBeenCalledWith( + `cases/${resolveAliasId}`, + 'case' + ); + }); + }); + + it('should redirect case view when resolves to conflict', async () => { + const resolveAliasId = `${defaultGetCase.data.id}_2`; + (useGetCase as jest.Mock).mockImplementation(() => ({ + ...defaultGetCase, + resolveOutcome: 'conflict', + resolveAliasId, + })); + const wrapper = mount( + + + + ); + await waitFor(() => { + expect(wrapper.find('[data-test-subj="case-view-title"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="conflict-component"]').exists()).toBeTruthy(); + expect(spacesUiApiMock.redirectLegacyUrl).not.toHaveBeenCalled(); + expect(spacesUiApiMock.components.getLegacyUrlConflict).toHaveBeenCalledWith({ + objectNoun: 'case', + currentObjectId: defaultGetCase.data.id, + otherObjectId: resolveAliasId, + otherObjectPath: `cases/${resolveAliasId}`, + }); }); }); @@ -521,41 +496,12 @@ describe('CaseView ', () => { (useGetCase as jest.Mock).mockImplementation(() => defaultGetCase); const wrapper = mount( - + ); wrapper.find('[data-test-subj="case-refresh"]').first().simulate('click'); await waitFor(() => { - expect(fetchCaseUserActions).toBeCalledWith('1234', 'resilient-2', undefined); + expect(fetchCaseUserActions).toBeCalledWith(caseProps.caseData.id, 'resilient-2', undefined); expect(fetchCase).toBeCalled(); }); }); diff --git a/x-pack/plugins/cases/public/components/case_view/index.tsx b/x-pack/plugins/cases/public/components/case_view/index.tsx index bb0b894238b9d..81e7607c9011f 100644 --- a/x-pack/plugins/cases/public/components/case_view/index.tsx +++ b/x-pack/plugins/cases/public/components/case_view/index.tsx @@ -40,6 +40,7 @@ import { CasesNavigation } from '../links'; import { OwnerProvider } from '../owner_context'; import { getConnectorById } from '../utils'; import { DoesNotExist } from './does_not_exist'; +import { useKibana } from '../../common/lib/kibana'; export interface CaseViewComponentProps { allCasesNavigation: CasesNavigation; @@ -499,6 +500,14 @@ export const CaseComponent = React.memo( } ); +export const CaseViewLoading = () => ( + + + + + +); + export const CaseView = React.memo( ({ allCasesNavigation, @@ -518,27 +527,59 @@ export const CaseView = React.memo( refreshRef, hideSyncAlerts, }: CaseViewProps) => { - const { data, isLoading, isError, fetchCase, updateCase } = useGetCase(caseId, subCaseId); - if (isError) { - return ; - } - if (isLoading) { - return ( - - - - - - ); - } - if (onCaseDataSuccess && data) { - onCaseDataSuccess(data); - } + const { data, resolveOutcome, resolveAliasId, isLoading, isError, fetchCase, updateCase } = + useGetCase(caseId, subCaseId); + const { spaces: spacesApi, http } = useKibana().services; - return ( + useEffect(() => { + if (onCaseDataSuccess && data) { + onCaseDataSuccess(data); + } + }, [data, onCaseDataSuccess]); + + useEffect(() => { + if (spacesApi && resolveOutcome === 'aliasMatch' && resolveAliasId != null) { + // CAUTION: the path /cases/:detailName is working in both Observability (/app/observability/cases/:detailName) and + // Security Solutions (/app/security/cases/:detailName) plugins. This will need to be changed if this component is loaded + // under any another path, passing a path builder function by props from every parent plugin. + const newPath = http.basePath.prepend( + `cases/${resolveAliasId}${window.location.search}${window.location.hash}` + ); + spacesApi.ui.redirectLegacyUrl(newPath, i18n.CASE); + } + }, [resolveOutcome, resolveAliasId, spacesApi, http]); + + const getLegacyUrlConflictCallout = useCallback(() => { + // This function returns a callout component *if* we have encountered a "legacy URL conflict" scenario + if (data && spacesApi && resolveOutcome === 'conflict' && resolveAliasId != null) { + // We have resolved to one object, but another object has a legacy URL alias associated with this ID/page. We should display a + // callout with a warning for the user, and provide a way for them to navigate to the other object. + const otherObjectId = resolveAliasId; // This is always defined if outcome === 'conflict' + // CAUTION: the path /cases/:detailName is working in both Observability (/app/observability/cases/:detailName) and + // Security Solutions (/app/security/cases/:detailName) plugins. This will need to be changed if this component is loaded + // under any another path, passing a path builder function by props from every parent plugin. + const otherObjectPath = http.basePath.prepend( + `cases/${otherObjectId}${window.location.search}${window.location.hash}` + ); + return spacesApi.ui.components.getLegacyUrlConflict({ + objectNoun: i18n.CASE, + currentObjectId: data.id, + otherObjectId, + otherObjectPath, + }); + } + return null; + }, [data, resolveAliasId, resolveOutcome, spacesApi, http.basePath]); + + return isError ? ( + + ) : isLoading ? ( + + ) : ( data && ( + {getLegacyUrlConflictCallout()} { + describe('getConnectorFieldsFromUserActions', () => { + it('returns null when it cannot find the connector id', () => { + expect(getConnectorFieldsFromUserActions('a', [])).toBeNull(); + }); + + it('returns null when the value fields are not valid encoded fields', () => { + expect( + getConnectorFieldsFromUserActions('a', [createUserAction({ newValue: 'a', oldValue: 'a' })]) + ).toBeNull(); + }); + + it('returns null when it cannot find the connector id in a non empty array', () => { + expect( + getConnectorFieldsFromUserActions('a', [ + createUserAction({ + newValue: JSON.stringify({ a: '1' }), + oldValue: JSON.stringify({ a: '1' }), + }), + ]) + ).toBeNull(); + }); + + it('returns the fields when it finds the connector id in the new value', () => { + expect( + getConnectorFieldsFromUserActions('a', [ + createUserAction({ + newValue: createEncodedJiraConnector(), + oldValue: JSON.stringify({ a: '1' }), + newValConnectorId: 'a', + }), + ]) + ).toEqual(defaultJiraFields); + }); + + it('returns the fields when it finds the connector id in the new value and the old value is null', () => { + expect( + getConnectorFieldsFromUserActions('a', [ + createUserAction({ + newValue: createEncodedJiraConnector(), + newValConnectorId: 'a', + }), + ]) + ).toEqual(defaultJiraFields); + }); + + it('returns the fields when it finds the connector id in the old value', () => { + const expectedFields = { ...defaultJiraFields, issueType: '5' }; + + expect( + getConnectorFieldsFromUserActions('id-to-find', [ + createUserAction({ + newValue: createEncodedJiraConnector(), + oldValue: createEncodedJiraConnector({ + fields: expectedFields, + }), + newValConnectorId: 'b', + oldValConnectorId: 'id-to-find', + }), + ]) + ).toEqual(expectedFields); + }); + + it('returns the fields when it finds the connector id in the second user action', () => { + const expectedFields = { ...defaultJiraFields, issueType: '5' }; + + expect( + getConnectorFieldsFromUserActions('id-to-find', [ + createUserAction({ + newValue: createEncodedJiraConnector(), + oldValue: createEncodedJiraConnector(), + newValConnectorId: 'b', + oldValConnectorId: 'a', + }), + createUserAction({ + newValue: createEncodedJiraConnector(), + oldValue: createEncodedJiraConnector({ fields: expectedFields }), + newValConnectorId: 'b', + oldValConnectorId: 'id-to-find', + }), + ]) + ).toEqual(expectedFields); + }); + + it('ignores a parse failure and finds the right user action', () => { + expect( + getConnectorFieldsFromUserActions('none', [ + createUserAction({ + newValue: 'b', + newValConnectorId: null, + }), + createUserAction({ + newValue: createEncodedJiraConnector({ + type: ConnectorTypes.none, + name: '', + fields: null, + }), + newValConnectorId: null, + }), + ]) + ).toBeNull(); + }); + + it('returns null when the id matches but the encoded value is null', () => { + expect( + getConnectorFieldsFromUserActions('b', [ + createUserAction({ + newValue: null, + newValConnectorId: 'b', + }), + ]) + ).toBeNull(); + }); + + it('returns null when the action fields is not of length 1', () => { + expect( + getConnectorFieldsFromUserActions('id-to-find', [ + createUserAction({ + newValue: JSON.stringify({ a: '1', fields: { hello: '1' } }), + oldValue: JSON.stringify({ a: '1', fields: { hi: '2' } }), + newValConnectorId: 'b', + oldValConnectorId: 'id-to-find', + actionField: ['connector', 'connector'], + }), + ]) + ).toBeNull(); + }); + + it('matches the none connector the searched for id is none', () => { + expect( + getConnectorFieldsFromUserActions('none', [ + createUserAction({ + newValue: createEncodedJiraConnector({ + type: ConnectorTypes.none, + name: '', + fields: null, + }), + newValConnectorId: null, + }), + ]) + ).toBeNull(); + }); + }); +}); + +function createUserAction(fields: Partial): CaseUserActions { + return { + action: 'update', + actionAt: '', + actionBy: {}, + actionField: ['connector'], + actionId: '', + caseId: '', + commentId: '', + newValConnectorId: null, + oldValConnectorId: null, + newValue: null, + oldValue: null, + ...fields, + }; +} + +function createEncodedJiraConnector(fields?: Partial): string { + return JSON.stringify({ + type: ConnectorTypes.jira, + name: 'name', + fields: defaultJiraFields, + ...fields, + }); +} + +const defaultJiraFields = { + issueType: '1', + parent: null, + priority: null, +}; diff --git a/x-pack/plugins/cases/public/components/edit_connector/helpers.ts b/x-pack/plugins/cases/public/components/edit_connector/helpers.ts index 36eb3f58c8aaf..b97035c458aca 100644 --- a/x-pack/plugins/cases/public/components/edit_connector/helpers.ts +++ b/x-pack/plugins/cases/public/components/edit_connector/helpers.ts @@ -5,23 +5,33 @@ * 2.0. */ +import { ConnectorTypeFields } from '../../../common'; import { CaseUserActions } from '../../containers/types'; +import { parseStringAsConnector } from '../../common/user_actions'; -export const getConnectorFieldsFromUserActions = (id: string, userActions: CaseUserActions[]) => { +export const getConnectorFieldsFromUserActions = ( + id: string, + userActions: CaseUserActions[] +): ConnectorTypeFields['fields'] => { try { for (const action of [...userActions].reverse()) { if (action.actionField.length === 1 && action.actionField[0] === 'connector') { - if (action.oldValue && action.newValue) { - const oldValue = JSON.parse(action.oldValue); - const newValue = JSON.parse(action.newValue); + const parsedNewConnector = parseStringAsConnector( + action.newValConnectorId, + action.newValue + ); - if (newValue.id === id) { - return newValue.fields; - } + if (parsedNewConnector && id === parsedNewConnector.id) { + return parsedNewConnector.fields; + } + + const parsedOldConnector = parseStringAsConnector( + action.oldValConnectorId, + action.oldValue + ); - if (oldValue.id === id) { - return oldValue.fields; - } + if (parsedOldConnector && id === parsedOldConnector.id) { + return parsedOldConnector.fields; } } } diff --git a/x-pack/plugins/cases/public/components/user_action_tree/helpers.test.tsx b/x-pack/plugins/cases/public/components/user_action_tree/helpers.test.tsx index b49a010cff38f..841f0d36bbf17 100644 --- a/x-pack/plugins/cases/public/components/user_action_tree/helpers.test.tsx +++ b/x-pack/plugins/cases/public/components/user_action_tree/helpers.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import { CaseStatuses } from '../../../common'; +import { CaseStatuses, ConnectorTypes } from '../../../common'; import { basicPush, getUserAction } from '../../containers/mock'; import { getLabelTitle, @@ -129,7 +129,7 @@ describe('User action tree helpers', () => { `${i18n.PUSHED_NEW_INCIDENT} ${basicPush.connectorName}` ); expect(wrapper.find(`[data-test-subj="pushed-value"]`).first().prop('href')).toEqual( - JSON.parse(action.newValue).external_url + JSON.parse(action.newValue!).external_url ); }); @@ -142,50 +142,74 @@ describe('User action tree helpers', () => { `${i18n.UPDATE_INCIDENT} ${basicPush.connectorName}` ); expect(wrapper.find(`[data-test-subj="pushed-value"]`).first().prop('href')).toEqual( - JSON.parse(action.newValue).external_url + JSON.parse(action.newValue!).external_url ); }); - it('label title generated for update connector - change connector', () => { - const action = { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: 'servicenow-1' }), - newValue: JSON.stringify({ id: 'resilient-2' }), - }; - const result: string | JSX.Element = getConnectorLabelTitle({ - action, - connectors, - }); - - expect(result).toEqual('selected My Connector 2 as incident management system'); - }); - - it('label title generated for update connector - change connector to none', () => { - const action = { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: 'servicenow-1' }), - newValue: JSON.stringify({ id: 'none' }), - }; - const result: string | JSX.Element = getConnectorLabelTitle({ - action, - connectors, + describe('getConnectorLabelTitle', () => { + it('returns an empty string when the encoded old value is null', () => { + const result = getConnectorLabelTitle({ + action: getUserAction(['connector'], 'update', { oldValue: null }), + connectors, + }); + + expect(result).toEqual(''); + }); + + it('returns an empty string when the encoded new value is null', () => { + const result = getConnectorLabelTitle({ + action: getUserAction(['connector'], 'update', { newValue: null }), + connectors, + }); + + expect(result).toEqual(''); + }); + + it('returns the change connector label', () => { + const result: string | JSX.Element = getConnectorLabelTitle({ + action: getUserAction(['connector'], 'update', { + oldValue: JSON.stringify({ + type: ConnectorTypes.serviceNowITSM, + name: 'a', + fields: null, + }), + oldValConnectorId: 'servicenow-1', + newValue: JSON.stringify({ type: ConnectorTypes.resilient, name: 'a', fields: null }), + newValConnectorId: 'resilient-2', + }), + connectors, + }); + + expect(result).toEqual('selected My Connector 2 as incident management system'); + }); + + it('returns the removed connector label', () => { + const result: string | JSX.Element = getConnectorLabelTitle({ + action: getUserAction(['connector'], 'update', { + oldValue: JSON.stringify({ type: ConnectorTypes.serviceNowITSM, name: '', fields: null }), + oldValConnectorId: 'servicenow-1', + newValue: JSON.stringify({ type: ConnectorTypes.none, name: '', fields: null }), + newValConnectorId: 'none', + }), + connectors, + }); + + expect(result).toEqual('removed external incident management system'); + }); + + it('returns the connector fields changed label', () => { + const result: string | JSX.Element = getConnectorLabelTitle({ + action: getUserAction(['connector'], 'update', { + oldValue: JSON.stringify({ type: ConnectorTypes.serviceNowITSM, name: '', fields: null }), + oldValConnectorId: 'servicenow-1', + newValue: JSON.stringify({ type: ConnectorTypes.serviceNowITSM, name: '', fields: null }), + newValConnectorId: 'servicenow-1', + }), + connectors, + }); + + expect(result).toEqual('changed connector field'); }); - - expect(result).toEqual('removed external incident management system'); - }); - - it('label title generated for update connector - field change', () => { - const action = { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: 'servicenow-1' }), - newValue: JSON.stringify({ id: 'servicenow-1' }), - }; - const result: string | JSX.Element = getConnectorLabelTitle({ - action, - connectors, - }); - - expect(result).toEqual('changed connector field'); }); describe('toStringArray', () => { diff --git a/x-pack/plugins/cases/public/components/user_action_tree/helpers.tsx b/x-pack/plugins/cases/public/components/user_action_tree/helpers.tsx index 744b14926b358..2eb44f91190c6 100644 --- a/x-pack/plugins/cases/public/components/user_action_tree/helpers.tsx +++ b/x-pack/plugins/cases/public/components/user_action_tree/helpers.tsx @@ -23,10 +23,11 @@ import { CommentType, Comment, CommentRequestActionsType, + noneConnectorId, } from '../../../common'; import { CaseUserActions } from '../../containers/types'; import { CaseServices } from '../../containers/use_get_case_user_actions'; -import { parseString } from '../../containers/utils'; +import { parseStringAsConnector, parseStringAsExternalService } from '../../common/user_actions'; import { Tags } from '../tag_list/tags'; import { UserActionUsernameWithAvatar } from './user_action_username_with_avatar'; import { UserActionTimestamp } from './user_action_timestamp'; @@ -97,23 +98,27 @@ export const getConnectorLabelTitle = ({ action: CaseUserActions; connectors: ActionConnector[]; }) => { - const oldValue = parseString(`${action.oldValue}`); - const newValue = parseString(`${action.newValue}`); + const oldConnector = parseStringAsConnector(action.oldValConnectorId, action.oldValue); + const newConnector = parseStringAsConnector(action.newValConnectorId, action.newValue); - if (oldValue === null || newValue === null) { + if (!oldConnector || !newConnector) { return ''; } - // Connector changed - if (oldValue.id !== newValue.id) { - const newConnector = connectors.find((c) => c.id === newValue.id); - return newValue.id != null && newValue.id !== 'none' && newConnector != null - ? i18n.SELECTED_THIRD_PARTY(newConnector.name) - : i18n.REMOVED_THIRD_PARTY; - } else { - // Field changed + // if the ids are the same, assume we just changed the fields + if (oldConnector.id === newConnector.id) { return i18n.CHANGED_CONNECTOR_FIELD; } + + // ids are not the same so check and see if the id is a valid connector and then return its name + // if the connector id is the none connector value then it must have been removed + const newConnectorActionInfo = connectors.find((c) => c.id === newConnector.id); + if (newConnector.id !== noneConnectorId && newConnectorActionInfo != null) { + return i18n.SELECTED_THIRD_PARTY(newConnectorActionInfo.name); + } + + // it wasn't a valid connector or it was the none connector, so it must have been removed + return i18n.REMOVED_THIRD_PARTY; }; const getTagsLabelTitle = (action: CaseUserActions) => { @@ -133,7 +138,8 @@ const getTagsLabelTitle = (action: CaseUserActions) => { }; export const getPushedServiceLabelTitle = (action: CaseUserActions, firstPush: boolean) => { - const pushedVal = JSON.parse(action.newValue ?? '') as CaseFullExternalService; + const externalService = parseStringAsExternalService(action.newValConnectorId, action.newValue); + return ( {`${firstPush ? i18n.PUSHED_NEW_INCIDENT : i18n.UPDATE_INCIDENT} ${ - pushedVal?.connector_name + externalService?.connector_name }`} - - {pushedVal?.external_title} + + {externalService?.external_title} @@ -157,20 +163,19 @@ export const getPushedServiceLabelTitle = (action: CaseUserActions, firstPush: b export const getPushInfo = ( caseServices: CaseServices, - // a JSON parse failure will result in null for parsedValue - parsedValue: { connector_id: string | null; connector_name: string } | null, + externalService: CaseFullExternalService | undefined, index: number ) => - parsedValue != null && parsedValue.connector_id != null + externalService != null && externalService.connector_id != null ? { - firstPush: caseServices[parsedValue.connector_id]?.firstPushIndex === index, - parsedConnectorId: parsedValue.connector_id, - parsedConnectorName: parsedValue.connector_name, + firstPush: caseServices[externalService.connector_id]?.firstPushIndex === index, + parsedConnectorId: externalService.connector_id, + parsedConnectorName: externalService.connector_name, } : { firstPush: false, - parsedConnectorId: 'none', - parsedConnectorName: 'none', + parsedConnectorId: noneConnectorId, + parsedConnectorName: noneConnectorId, }; const getUpdateActionIcon = (actionField: string): string => { diff --git a/x-pack/plugins/cases/public/components/user_action_tree/index.tsx b/x-pack/plugins/cases/public/components/user_action_tree/index.tsx index 784817229caf9..7ea415324194c 100644 --- a/x-pack/plugins/cases/public/components/user_action_tree/index.tsx +++ b/x-pack/plugins/cases/public/components/user_action_tree/index.tsx @@ -35,7 +35,7 @@ import { Ecs, } from '../../../common'; import { CaseServices } from '../../containers/use_get_case_user_actions'; -import { parseString } from '../../containers/utils'; +import { parseStringAsExternalService } from '../../common/user_actions'; import { OnUpdateFields } from '../case_view'; import { getConnectorLabelTitle, @@ -512,10 +512,14 @@ export const UserActionTree = React.memo( // Pushed information if (action.actionField.length === 1 && action.actionField[0] === 'pushed') { - const parsedValue = parseString(`${action.newValue}`); + const parsedExternalService = parseStringAsExternalService( + action.newValConnectorId, + action.newValue + ); + const { firstPush, parsedConnectorId, parsedConnectorName } = getPushInfo( caseServices, - parsedValue, + parsedExternalService, index ); diff --git a/x-pack/plugins/cases/public/containers/__mocks__/api.ts b/x-pack/plugins/cases/public/containers/__mocks__/api.ts index 6db92829bb8d6..96e75a96ca115 100644 --- a/x-pack/plugins/cases/public/containers/__mocks__/api.ts +++ b/x-pack/plugins/cases/public/containers/__mocks__/api.ts @@ -21,6 +21,7 @@ import { basicCase, basicCaseCommentPatch, basicCasePost, + basicResolvedCase, casesStatus, caseUserActions, pushedCase, @@ -33,6 +34,7 @@ import { CommentRequest, User, CaseStatuses, + ResolvedCase, } from '../../../common'; export const getCase = async ( @@ -41,6 +43,12 @@ export const getCase = async ( signal: AbortSignal ): Promise => Promise.resolve(basicCase); +export const resolveCase = async ( + caseId: string, + includeComments: boolean = true, + signal: AbortSignal +): Promise => Promise.resolve(basicResolvedCase); + export const getCasesStatus = async (signal: AbortSignal): Promise => Promise.resolve(casesStatus); diff --git a/x-pack/plugins/cases/public/containers/api.test.tsx b/x-pack/plugins/cases/public/containers/api.test.tsx index e47930e81fe6b..654ade308ed44 100644 --- a/x-pack/plugins/cases/public/containers/api.test.tsx +++ b/x-pack/plugins/cases/public/containers/api.test.tsx @@ -30,6 +30,7 @@ import { postCase, postComment, pushCase, + resolveCase, } from './api'; import { @@ -68,7 +69,7 @@ describe('Case Configuration API', () => { }); const data = ['1', '2']; - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await deleteCases(data, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}`, { method: 'DELETE', @@ -77,7 +78,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await deleteCases(data, abortCtrl.signal); expect(resp).toEqual(''); }); @@ -89,7 +90,7 @@ describe('Case Configuration API', () => { fetchMock.mockResolvedValue(actionLicenses); }); - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await getActionLicense(abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`/api/actions/connector_types`, { method: 'GET', @@ -97,7 +98,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await getActionLicense(abortCtrl.signal); expect(resp).toEqual(actionLicenses); }); @@ -110,7 +111,7 @@ describe('Case Configuration API', () => { }); const data = basicCase.id; - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await getCase(data, true, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/${basicCase.id}`, { method: 'GET', @@ -119,18 +120,46 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await getCase(data, true, abortCtrl.signal); expect(resp).toEqual(basicCase); }); }); + describe('resolveCase', () => { + const targetAliasId = '12345'; + const basicResolveCase = { + outcome: 'aliasMatch', + case: basicCaseSnake, + }; + const caseId = basicCase.id; + + beforeEach(() => { + fetchMock.mockClear(); + fetchMock.mockResolvedValue({ ...basicResolveCase, target_alias_id: targetAliasId }); + }); + + test('should be called with correct check url, method, signal', async () => { + await resolveCase(caseId, true, abortCtrl.signal); + expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/${caseId}/resolve`, { + method: 'GET', + query: { includeComments: true }, + signal: abortCtrl.signal, + }); + }); + + test('should return correct response', async () => { + const resp = await resolveCase(caseId, true, abortCtrl.signal); + expect(resp).toEqual({ ...basicResolveCase, case: basicCase, targetAliasId }); + }); + }); + describe('getCases', () => { beforeEach(() => { fetchMock.mockClear(); fetchMock.mockResolvedValue(allCasesSnake); }); - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await getCases({ filterOptions: { ...DEFAULT_FILTER_OPTIONS, owner: [SECURITY_SOLUTION_OWNER] }, queryParams: DEFAULT_QUERY_PARAMS, @@ -148,7 +177,7 @@ describe('Case Configuration API', () => { }); }); - test('correctly applies filters', async () => { + test('should applies correct filters', async () => { await getCases({ filterOptions: { ...DEFAULT_FILTER_OPTIONS, @@ -175,7 +204,7 @@ describe('Case Configuration API', () => { }); }); - test('tags with weird chars get handled gracefully', async () => { + test('should handle tags with weird chars', async () => { const weirdTags: string[] = ['(', '"double"']; await getCases({ @@ -204,7 +233,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await getCases({ filterOptions: { ...DEFAULT_FILTER_OPTIONS, owner: [SECURITY_SOLUTION_OWNER] }, queryParams: DEFAULT_QUERY_PARAMS, @@ -219,7 +248,7 @@ describe('Case Configuration API', () => { fetchMock.mockClear(); fetchMock.mockResolvedValue(casesStatusSnake); }); - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await getCasesStatus(abortCtrl.signal, [SECURITY_SOLUTION_OWNER]); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/status`, { method: 'GET', @@ -228,7 +257,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await getCasesStatus(abortCtrl.signal, [SECURITY_SOLUTION_OWNER]); expect(resp).toEqual(casesStatus); }); @@ -240,7 +269,7 @@ describe('Case Configuration API', () => { fetchMock.mockResolvedValue(caseUserActionsSnake); }); - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await getCaseUserActions(basicCase.id, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/${basicCase.id}/user_actions`, { method: 'GET', @@ -248,7 +277,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await getCaseUserActions(basicCase.id, abortCtrl.signal); expect(resp).toEqual(caseUserActions); }); @@ -260,7 +289,7 @@ describe('Case Configuration API', () => { fetchMock.mockResolvedValue(respReporters); }); - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await getReporters(abortCtrl.signal, [SECURITY_SOLUTION_OWNER]); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/reporters`, { method: 'GET', @@ -271,7 +300,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await getReporters(abortCtrl.signal, [SECURITY_SOLUTION_OWNER]); expect(resp).toEqual(respReporters); }); @@ -283,7 +312,7 @@ describe('Case Configuration API', () => { fetchMock.mockResolvedValue(tags); }); - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await getTags(abortCtrl.signal, [SECURITY_SOLUTION_OWNER]); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/tags`, { method: 'GET', @@ -294,7 +323,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await getTags(abortCtrl.signal, [SECURITY_SOLUTION_OWNER]); expect(resp).toEqual(tags); }); @@ -306,7 +335,7 @@ describe('Case Configuration API', () => { fetchMock.mockResolvedValue([basicCaseSnake]); }); const data = { description: 'updated description' }; - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await patchCase(basicCase.id, data, basicCase.version, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}`, { method: 'PATCH', @@ -317,7 +346,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await patchCase( basicCase.id, { description: 'updated description' }, @@ -341,7 +370,7 @@ describe('Case Configuration API', () => { }, ]; - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await patchCasesStatus(data, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}`, { method: 'PATCH', @@ -350,7 +379,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await patchCasesStatus(data, abortCtrl.signal); expect(resp).toEqual({ ...cases }); }); @@ -362,7 +391,7 @@ describe('Case Configuration API', () => { fetchMock.mockResolvedValue(basicCaseSnake); }); - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await patchComment({ caseId: basicCase.id, commentId: basicCase.comments[0].id, @@ -384,7 +413,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await patchComment({ caseId: basicCase.id, commentId: basicCase.comments[0].id, @@ -418,7 +447,7 @@ describe('Case Configuration API', () => { owner: SECURITY_SOLUTION_OWNER, }; - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await postCase(data, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}`, { method: 'POST', @@ -427,7 +456,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await postCase(data, abortCtrl.signal); expect(resp).toEqual(basicCase); }); @@ -444,7 +473,7 @@ describe('Case Configuration API', () => { type: CommentType.user as const, }; - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await postComment(data, basicCase.id, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/${basicCase.id}/comments`, { method: 'POST', @@ -453,7 +482,7 @@ describe('Case Configuration API', () => { }); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await postComment(data, basicCase.id, abortCtrl.signal); expect(resp).toEqual(basicCase); }); @@ -467,7 +496,7 @@ describe('Case Configuration API', () => { fetchMock.mockResolvedValue(pushedCaseSnake); }); - test('check url, method, signal', async () => { + test('should be called with correct check url, method, signal', async () => { await pushCase(basicCase.id, connectorId, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith( `${CASES_URL}/${basicCase.id}/connector/${connectorId}/_push`, @@ -479,7 +508,7 @@ describe('Case Configuration API', () => { ); }); - test('happy path', async () => { + test('should return correct response', async () => { const resp = await pushCase(basicCase.id, connectorId, abortCtrl.signal); expect(resp).toEqual(pushedCase); }); diff --git a/x-pack/plugins/cases/public/containers/api.ts b/x-pack/plugins/cases/public/containers/api.ts index 51a68376936af..75e8c8f58705d 100644 --- a/x-pack/plugins/cases/public/containers/api.ts +++ b/x-pack/plugins/cases/public/containers/api.ts @@ -14,6 +14,7 @@ import { CasePatchRequest, CasePostRequest, CaseResponse, + CaseResolveResponse, CASES_URL, CasesFindResponse, CasesResponse, @@ -35,6 +36,7 @@ import { SubCaseResponse, SubCasesResponse, User, + ResolvedCase, } from '../../common'; import { getAllConnectorTypesUrl } from '../../common/utils/connectors_api'; @@ -61,6 +63,7 @@ import { decodeCasesFindResponse, decodeCasesStatusResponse, decodeCaseUserActionsResponse, + decodeCaseResolveResponse, } from './utils'; export const getCase = async ( @@ -78,6 +81,24 @@ export const getCase = async ( return convertToCamelCase(decodeCaseResponse(response)); }; +export const resolveCase = async ( + caseId: string, + includeComments: boolean = true, + signal: AbortSignal +): Promise => { + const response = await KibanaServices.get().http.fetch( + getCaseDetailsUrl(caseId) + '/resolve', + { + method: 'GET', + query: { + includeComments, + }, + signal, + } + ); + return convertToCamelCase(decodeCaseResolveResponse(response)); +}; + export const getSubCase = async ( caseId: string, subCaseId: string, diff --git a/x-pack/plugins/cases/public/containers/mock.ts b/x-pack/plugins/cases/public/containers/mock.ts index c955bb34240e2..f7d1daabd60ea 100644 --- a/x-pack/plugins/cases/public/containers/mock.ts +++ b/x-pack/plugins/cases/public/containers/mock.ts @@ -9,6 +9,7 @@ import { ActionLicense, AllCases, Case, CasesStatus, CaseUserActions, Comment } import { AssociationType, + CaseUserActionConnector, CaseResponse, CasesFindResponse, CasesResponse, @@ -19,6 +20,10 @@ import { CommentResponse, CommentType, ConnectorTypes, + ResolvedCase, + isCreateConnector, + isPush, + isUpdateConnector, SECURITY_SOLUTION_OWNER, UserAction, UserActionField, @@ -159,6 +164,12 @@ export const basicCase: Case = { subCaseIds: [], }; +export const basicResolvedCase: ResolvedCase = { + case: basicCase, + outcome: 'aliasMatch', + aliasTargetId: `${basicCase.id}_2`, +}; + export const collectionCase: Case = { type: CaseType.collection, owner: SECURITY_SOLUTION_OWNER, @@ -240,7 +251,9 @@ export const pushedCase: Case = { const basicAction = { actionAt: basicCreatedAt, actionBy: elasticUser, + oldValConnectorId: null, oldValue: null, + newValConnectorId: null, newValue: 'what a cool value', caseId: basicCaseId, commentId: null, @@ -308,12 +321,7 @@ export const basicCaseSnake: CaseResponse = { closed_at: null, closed_by: null, comments: [basicCommentSnake], - connector: { - id: 'none', - name: 'My Connector', - type: ConnectorTypes.none, - fields: null, - }, + connector: { id: 'none', name: 'My Connector', type: ConnectorTypes.none, fields: null }, created_at: basicCreatedAt, created_by: elasticUserSnake, external_service: null, @@ -328,8 +336,8 @@ export const casesStatusSnake: CasesStatusResponse = { count_open_cases: 20, }; +export const pushConnectorId = '123'; export const pushSnake = { - connector_id: '123', connector_name: 'connector name', external_id: 'external_id', external_title: 'external title', @@ -350,7 +358,7 @@ export const pushedCaseSnake = { type: ConnectorTypes.jira, fields: null, }, - external_service: basicPushSnake, + external_service: { ...basicPushSnake, connector_id: pushConnectorId }, }; export const reporters: string[] = ['alexis', 'kim', 'maria', 'steph']; @@ -385,17 +393,20 @@ const basicActionSnake = { comment_id: null, owner: SECURITY_SOLUTION_OWNER, }; -export const getUserActionSnake = (af: UserActionField, a: UserAction) => ({ - ...basicActionSnake, - action_id: `${af[0]}-${a}`, - action_field: af, - action: a, - comment_id: af[0] === 'comment' ? basicCommentId : null, - new_value: - a === 'push-to-service' && af[0] === 'pushed' - ? JSON.stringify(basicPushSnake) - : basicAction.newValue, -}); +export const getUserActionSnake = (af: UserActionField, a: UserAction) => { + const isPushToService = a === 'push-to-service' && af[0] === 'pushed'; + + return { + ...basicActionSnake, + action_id: `${af[0]}-${a}`, + action_field: af, + action: a, + comment_id: af[0] === 'comment' ? basicCommentId : null, + new_value: isPushToService ? JSON.stringify(basicPushSnake) : basicAction.newValue, + new_val_connector_id: isPushToService ? pushConnectorId : null, + old_val_connector_id: null, + }; +}; export const caseUserActionsSnake: CaseUserActionsResponse = [ getUserActionSnake(['description'], 'create'), @@ -405,17 +416,76 @@ export const caseUserActionsSnake: CaseUserActionsResponse = [ // user actions -export const getUserAction = (af: UserActionField, a: UserAction) => ({ - ...basicAction, - actionId: `${af[0]}-${a}`, - actionField: af, - action: a, - commentId: af[0] === 'comment' ? basicCommentId : null, - newValue: - a === 'push-to-service' && af[0] === 'pushed' - ? JSON.stringify(basicPushSnake) - : basicAction.newValue, -}); +export const getUserAction = ( + af: UserActionField, + a: UserAction, + overrides?: Partial +): CaseUserActions => { + return { + ...basicAction, + actionId: `${af[0]}-${a}`, + actionField: af, + action: a, + commentId: af[0] === 'comment' ? basicCommentId : null, + ...getValues(a, af, overrides), + }; +}; + +const getValues = ( + userAction: UserAction, + actionFields: UserActionField, + overrides?: Partial +): Partial => { + if (isCreateConnector(userAction, actionFields)) { + return { + newValue: + overrides?.newValue === undefined ? JSON.stringify(basicCaseSnake) : overrides.newValue, + newValConnectorId: overrides?.newValConnectorId ?? null, + oldValue: null, + oldValConnectorId: null, + }; + } else if (isUpdateConnector(userAction, actionFields)) { + return { + newValue: + overrides?.newValue === undefined + ? JSON.stringify({ name: 'My Connector', type: ConnectorTypes.none, fields: null }) + : overrides.newValue, + newValConnectorId: overrides?.newValConnectorId ?? null, + oldValue: + overrides?.oldValue === undefined + ? JSON.stringify({ name: 'My Connector2', type: ConnectorTypes.none, fields: null }) + : overrides.oldValue, + oldValConnectorId: overrides?.oldValConnectorId ?? null, + }; + } else if (isPush(userAction, actionFields)) { + return { + newValue: + overrides?.newValue === undefined ? JSON.stringify(basicPushSnake) : overrides?.newValue, + newValConnectorId: + overrides?.newValConnectorId === undefined ? pushConnectorId : overrides.newValConnectorId, + oldValue: overrides?.oldValue ?? null, + oldValConnectorId: overrides?.oldValConnectorId ?? null, + }; + } else { + return { + newValue: overrides?.newValue === undefined ? basicAction.newValue : overrides.newValue, + newValConnectorId: overrides?.newValConnectorId ?? null, + oldValue: overrides?.oldValue ?? null, + oldValConnectorId: overrides?.oldValConnectorId ?? null, + }; + } +}; + +export const getJiraConnectorWithoutId = (overrides?: Partial) => { + return JSON.stringify({ + name: 'jira1', + type: ConnectorTypes.jira, + ...jiraFields, + ...overrides, + }); +}; + +export const jiraFields = { fields: { issueType: '10006', priority: null, parent: null } }; export const getAlertUserAction = () => ({ ...basicAction, diff --git a/x-pack/plugins/cases/public/containers/use_get_case.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case.test.tsx index c88f530709c8a..e825e232aebdc 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case.test.tsx @@ -7,7 +7,7 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { useGetCase, UseGetCase } from './use_get_case'; -import { basicCase } from './mock'; +import { basicCase, basicResolvedCase } from './mock'; import * as api from './api'; jest.mock('./api'); @@ -28,6 +28,7 @@ describe('useGetCase', () => { await waitForNextUpdate(); expect(result.current).toEqual({ data: null, + resolveOutcome: null, isLoading: false, isError: false, fetchCase: result.current.fetchCase, @@ -36,13 +37,13 @@ describe('useGetCase', () => { }); }); - it('calls getCase with correct arguments', async () => { - const spyOnGetCase = jest.spyOn(api, 'getCase'); + it('calls resolveCase with correct arguments', async () => { + const spyOnResolveCase = jest.spyOn(api, 'resolveCase'); await act(async () => { const { waitForNextUpdate } = renderHook(() => useGetCase(basicCase.id)); await waitForNextUpdate(); await waitForNextUpdate(); - expect(spyOnGetCase).toBeCalledWith(basicCase.id, true, abortCtrl.signal); + expect(spyOnResolveCase).toBeCalledWith(basicCase.id, true, abortCtrl.signal); }); }); @@ -55,6 +56,8 @@ describe('useGetCase', () => { await waitForNextUpdate(); expect(result.current).toEqual({ data: basicCase, + resolveOutcome: basicResolvedCase.outcome, + resolveAliasId: basicResolvedCase.aliasTargetId, isLoading: false, isError: false, fetchCase: result.current.fetchCase, @@ -64,7 +67,7 @@ describe('useGetCase', () => { }); it('refetch case', async () => { - const spyOnGetCase = jest.spyOn(api, 'getCase'); + const spyOnResolveCase = jest.spyOn(api, 'resolveCase'); await act(async () => { const { result, waitForNextUpdate } = renderHook(() => useGetCase(basicCase.id) @@ -72,7 +75,7 @@ describe('useGetCase', () => { await waitForNextUpdate(); await waitForNextUpdate(); result.current.fetchCase(); - expect(spyOnGetCase).toHaveBeenCalledTimes(2); + expect(spyOnResolveCase).toHaveBeenCalledTimes(2); }); }); @@ -103,8 +106,8 @@ describe('useGetCase', () => { }); it('unhappy path', async () => { - const spyOnGetCase = jest.spyOn(api, 'getCase'); - spyOnGetCase.mockImplementation(() => { + const spyOnResolveCase = jest.spyOn(api, 'resolveCase'); + spyOnResolveCase.mockImplementation(() => { throw new Error('Something went wrong'); }); @@ -117,6 +120,7 @@ describe('useGetCase', () => { expect(result.current).toEqual({ data: null, + resolveOutcome: null, isLoading: false, isError: true, fetchCase: result.current.fetchCase, diff --git a/x-pack/plugins/cases/public/containers/use_get_case.tsx b/x-pack/plugins/cases/public/containers/use_get_case.tsx index b9326ad057c9e..52610981a227c 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case.tsx @@ -7,20 +7,22 @@ import { useEffect, useReducer, useCallback, useRef } from 'react'; -import { Case } from './types'; +import { Case, ResolvedCase } from './types'; import * as i18n from './translations'; import { useToasts } from '../common/lib/kibana'; -import { getCase, getSubCase } from './api'; +import { resolveCase, getSubCase } from './api'; interface CaseState { data: Case | null; + resolveOutcome: ResolvedCase['outcome'] | null; + resolveAliasId?: string; isLoading: boolean; isError: boolean; } type Action = | { type: 'FETCH_INIT'; payload: { silent: boolean } } - | { type: 'FETCH_SUCCESS'; payload: Case } + | { type: 'FETCH_SUCCESS'; payload: ResolvedCase } | { type: 'FETCH_FAILURE' } | { type: 'UPDATE_CASE'; payload: Case }; @@ -40,7 +42,9 @@ const dataFetchReducer = (state: CaseState, action: Action): CaseState => { ...state, isLoading: false, isError: false, - data: action.payload, + data: action.payload.case, + resolveOutcome: action.payload.outcome, + resolveAliasId: action.payload.aliasTargetId, }; case 'FETCH_FAILURE': return { @@ -72,6 +76,7 @@ export const useGetCase = (caseId: string, subCaseId?: string): UseGetCase => { isLoading: false, isError: false, data: null, + resolveOutcome: null, }); const toasts = useToasts(); const isCancelledRef = useRef(false); @@ -89,9 +94,12 @@ export const useGetCase = (caseId: string, subCaseId?: string): UseGetCase => { abortCtrlRef.current = new AbortController(); dispatch({ type: 'FETCH_INIT', payload: { silent } }); - const response = await (subCaseId - ? getSubCase(caseId, subCaseId, true, abortCtrlRef.current.signal) - : getCase(caseId, true, abortCtrlRef.current.signal)); + const response: ResolvedCase = subCaseId + ? { + case: await getSubCase(caseId, subCaseId, true, abortCtrlRef.current.signal), + outcome: 'exactMatch', // sub-cases are not resolved, forced to exactMatch always + } + : await resolveCase(caseId, true, abortCtrlRef.current.signal); if (!isCancelledRef.current) { dispatch({ type: 'FETCH_SUCCESS', payload: response }); diff --git a/x-pack/plugins/cases/public/containers/use_get_case_user_actions.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case_user_actions.test.tsx index 62b4cf92434cd..e7e46fa46c7cc 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_user_actions.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_user_actions.test.tsx @@ -18,7 +18,9 @@ import { basicPushSnake, caseUserActions, elasticUser, + getJiraConnectorWithoutId, getUserAction, + jiraFields, } from './mock'; import * as api from './api'; @@ -299,15 +301,14 @@ describe('useGetCaseUserActions', () => { const pushAction123 = getUserAction(['pushed'], 'push-to-service'); const push456 = { ...basicPushSnake, - connector_id: '456', connector_name: 'other connector name', external_id: 'other_external_id', }; - const pushAction456 = { - ...getUserAction(['pushed'], 'push-to-service'), + const pushAction456 = getUserAction(['pushed'], 'push-to-service', { newValue: JSON.stringify(push456), - }; + newValConnectorId: '456', + }); const userActions = [ ...caseUserActions, @@ -346,15 +347,14 @@ describe('useGetCaseUserActions', () => { const pushAction123 = getUserAction(['pushed'], 'push-to-service'); const push456 = { ...basicPushSnake, - connector_id: '456', connector_name: 'other connector name', external_id: 'other_external_id', }; - const pushAction456 = { - ...getUserAction(['pushed'], 'push-to-service'), + const pushAction456 = getUserAction(['pushed'], 'push-to-service', { newValue: JSON.stringify(push456), - }; + newValConnectorId: '456', + }); const userActions = [ ...caseUserActions, @@ -392,11 +392,7 @@ describe('useGetCaseUserActions', () => { const userActions = [ ...caseUserActions, getUserAction(['pushed'], 'push-to-service'), - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - }, + createUpdateConnectorFields123HighPriorityUserAction(), ]; const result = getPushedInfo(userActions, '123'); @@ -418,11 +414,7 @@ describe('useGetCaseUserActions', () => { const userActions = [ ...caseUserActions, getUserAction(['pushed'], 'push-to-service'), - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - }, + createChangeConnector123To456UserAction(), ]; const result = getPushedInfo(userActions, '123'); @@ -444,16 +436,8 @@ describe('useGetCaseUserActions', () => { const userActions = [ ...caseUserActions, getUserAction(['pushed'], 'push-to-service'), - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - }, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - }, + createChangeConnector123To456UserAction(), + createChangeConnector456To123UserAction(), ]; const result = getPushedInfo(userActions, '123'); @@ -474,22 +458,10 @@ describe('useGetCaseUserActions', () => { it('Change fields and connector after push - hasDataToPush: true', () => { const userActions = [ ...caseUserActions, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - }, + createUpdateConnectorFields123HighPriorityUserAction(), getUserAction(['pushed'], 'push-to-service'), - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - }, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'Low' } }), - }, + createChangeConnector123HighPriorityTo456UserAction(), + createChangeConnector456To123PriorityLowUserAction(), ]; const result = getPushedInfo(userActions, '123'); @@ -510,22 +482,10 @@ describe('useGetCaseUserActions', () => { it('Change only connector after push - hasDataToPush: false', () => { const userActions = [ ...caseUserActions, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - }, + createUpdateConnectorFields123HighPriorityUserAction(), getUserAction(['pushed'], 'push-to-service'), - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - }, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - }, + createChangeConnector123HighPriorityTo456UserAction(), + createChangeConnector456To123HighPriorityUserAction(), ]; const result = getPushedInfo(userActions, '123'); @@ -547,45 +507,24 @@ describe('useGetCaseUserActions', () => { const pushAction123 = getUserAction(['pushed'], 'push-to-service'); const push456 = { ...basicPushSnake, - connector_id: '456', connector_name: 'other connector name', external_id: 'other_external_id', }; - const pushAction456 = { - ...getUserAction(['pushed'], 'push-to-service'), + const pushAction456 = getUserAction(['pushed'], 'push-to-service', { newValue: JSON.stringify(push456), - }; + newValConnectorId: '456', + }); const userActions = [ ...caseUserActions, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - }, + createUpdateConnectorFields123HighPriorityUserAction(), pushAction123, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - }, + createChangeConnector123HighPriorityTo456UserAction(), pushAction456, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'Low' } }), - }, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'Low' } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - }, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'Low' } }), - }, + createChangeConnector456To123PriorityLowUserAction(), + createChangeConnector123LowPriorityTo456UserAction(), + createChangeConnector456To123PriorityLowUserAction(), ]; const result = getPushedInfo(userActions, '123'); @@ -617,34 +556,22 @@ describe('useGetCaseUserActions', () => { const pushAction123 = getUserAction(['pushed'], 'push-to-service'); const push456 = { ...basicPushSnake, - connector_id: '456', connector_name: 'other connector name', external_id: 'other_external_id', }; - const pushAction456 = { - ...getUserAction(['pushed'], 'push-to-service'), + const pushAction456 = getUserAction(['pushed'], 'push-to-service', { + newValConnectorId: '456', newValue: JSON.stringify(push456), - }; + }); + const userActions = [ ...caseUserActions, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - }, + createUpdateConnectorFields123HighPriorityUserAction(), pushAction123, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - }, + createChangeConnector123HighPriorityTo456UserAction(), pushAction456, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - }, + createChangeConnector456To123HighPriorityUserAction(), ]; const result = getPushedInfo(userActions, '123'); @@ -675,22 +602,10 @@ describe('useGetCaseUserActions', () => { it('Changing other connectors fields does not count as an update', () => { const userActions = [ ...caseUserActions, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: null } }), - newValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - }, + createUpdateConnectorFields123HighPriorityUserAction(), getUserAction(['pushed'], 'push-to-service'), - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '123', fields: { issueType: '10006', priority: 'High' } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - }, - { - ...getUserAction(['connector'], 'update'), - oldValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '6' } }), - newValue: JSON.stringify({ id: '456', fields: { issueTypes: ['10'], severity: '3' } }), - }, + createChangeConnector123HighPriorityTo456UserAction(), + createUpdateConnectorFields456HighPriorityUserAction(), ]; const result = getPushedInfo(userActions, '123'); @@ -709,3 +624,83 @@ describe('useGetCaseUserActions', () => { }); }); }); + +const jira123HighPriorityFields = { + fields: { ...jiraFields.fields, priority: 'High' }, +}; + +const jira123LowPriorityFields = { + fields: { ...jiraFields.fields, priority: 'Low' }, +}; + +const jira456Fields = { + fields: { issueType: '10', parent: null, priority: null }, +}; + +const jira456HighPriorityFields = { + fields: { ...jira456Fields.fields, priority: 'High' }, +}; + +const createUpdateConnectorFields123HighPriorityUserAction = () => + getUserAction(['connector'], 'update', { + oldValue: getJiraConnectorWithoutId(), + newValue: getJiraConnectorWithoutId(jira123HighPriorityFields), + oldValConnectorId: '123', + newValConnectorId: '123', + }); + +const createUpdateConnectorFields456HighPriorityUserAction = () => + getUserAction(['connector'], 'update', { + oldValue: getJiraConnectorWithoutId(jira456Fields), + newValue: getJiraConnectorWithoutId(jira456HighPriorityFields), + oldValConnectorId: '456', + newValConnectorId: '456', + }); + +const createChangeConnector123HighPriorityTo456UserAction = () => + getUserAction(['connector'], 'update', { + oldValue: getJiraConnectorWithoutId(jira123HighPriorityFields), + oldValConnectorId: '123', + newValue: getJiraConnectorWithoutId(jira456Fields), + newValConnectorId: '456', + }); + +const createChangeConnector123To456UserAction = () => + getUserAction(['connector'], 'update', { + oldValue: getJiraConnectorWithoutId(), + oldValConnectorId: '123', + newValue: getJiraConnectorWithoutId(jira456Fields), + newValConnectorId: '456', + }); + +const createChangeConnector123LowPriorityTo456UserAction = () => + getUserAction(['connector'], 'update', { + oldValue: getJiraConnectorWithoutId(jira123LowPriorityFields), + oldValConnectorId: '123', + newValue: getJiraConnectorWithoutId(jira456Fields), + newValConnectorId: '456', + }); + +const createChangeConnector456To123UserAction = () => + getUserAction(['connector'], 'update', { + oldValue: getJiraConnectorWithoutId(jira456Fields), + oldValConnectorId: '456', + newValue: getJiraConnectorWithoutId(), + newValConnectorId: '123', + }); + +const createChangeConnector456To123HighPriorityUserAction = () => + getUserAction(['connector'], 'update', { + oldValue: getJiraConnectorWithoutId(jira456Fields), + oldValConnectorId: '456', + newValue: getJiraConnectorWithoutId(jira123HighPriorityFields), + newValConnectorId: '123', + }); + +const createChangeConnector456To123PriorityLowUserAction = () => + getUserAction(['connector'], 'update', { + oldValue: getJiraConnectorWithoutId(jira456Fields), + oldValConnectorId: '456', + newValue: getJiraConnectorWithoutId(jira123LowPriorityFields), + newValConnectorId: '123', + }); diff --git a/x-pack/plugins/cases/public/containers/use_get_case_user_actions.tsx b/x-pack/plugins/cases/public/containers/use_get_case_user_actions.tsx index e481519ba19a3..36d600c3f1c9d 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_user_actions.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_user_actions.tsx @@ -18,7 +18,8 @@ import { } from '../../common'; import { getCaseUserActions, getSubCaseUserActions } from './api'; import * as i18n from './translations'; -import { convertToCamelCase, parseString } from './utils'; +import { convertToCamelCase } from './utils'; +import { parseStringAsConnector, parseStringAsExternalService } from '../common/user_actions'; import { useToasts } from '../common/lib/kibana'; export interface CaseService extends CaseExternalService { @@ -58,8 +59,24 @@ export interface UseGetCaseUserActions extends CaseUserActionsState { ) => Promise; } -const getExternalService = (value: string): CaseExternalService | null => - convertToCamelCase(parseString(`${value}`)); +const unknownExternalServiceConnectorId = 'unknown'; + +const getExternalService = ( + connectorId: string | null, + encodedValue: string | null +): CaseExternalService | null => { + const decodedValue = parseStringAsExternalService(connectorId, encodedValue); + + if (decodedValue == null) { + return null; + } + return { + ...convertToCamelCase(decodedValue), + // if in the rare case that the connector id is null we'll set it to unknown if we need to reference it in the UI + // anywhere. The id would only ever be null if a migration failed or some logic error within the backend occurred + connectorId: connectorId ?? unknownExternalServiceConnectorId, + }; +}; const groupConnectorFields = ( userActions: CaseUserActions[] @@ -69,22 +86,26 @@ const groupConnectorFields = ( return acc; } - const oldValue = parseString(`${mua.oldValue}`); - const newValue = parseString(`${mua.newValue}`); + const oldConnector = parseStringAsConnector(mua.oldValConnectorId, mua.oldValue); + const newConnector = parseStringAsConnector(mua.newValConnectorId, mua.newValue); - if (oldValue == null || newValue == null) { + if (!oldConnector || !newConnector) { return acc; } return { ...acc, - [oldValue.id]: [ - ...(acc[oldValue.id] || []), - ...(oldValue.id === newValue.id ? [oldValue.fields, newValue.fields] : [oldValue.fields]), + [oldConnector.id]: [ + ...(acc[oldConnector.id] || []), + ...(oldConnector.id === newConnector.id + ? [oldConnector.fields, newConnector.fields] + : [oldConnector.fields]), ], - [newValue.id]: [ - ...(acc[newValue.id] || []), - ...(oldValue.id === newValue.id ? [oldValue.fields, newValue.fields] : [newValue.fields]), + [newConnector.id]: [ + ...(acc[newConnector.id] || []), + ...(oldConnector.id === newConnector.id + ? [oldConnector.fields, newConnector.fields] + : [newConnector.fields]), ], }; }, {} as Record>); @@ -137,9 +158,7 @@ export const getPushedInfo = ( const hasDataToPushForConnector = (connectorId: string): boolean => { const caseUserActionsReversed = [...caseUserActions].reverse(); const lastPushOfConnectorReversedIndex = caseUserActionsReversed.findIndex( - (mua) => - mua.action === 'push-to-service' && - getExternalService(`${mua.newValue}`)?.connectorId === connectorId + (mua) => mua.action === 'push-to-service' && mua.newValConnectorId === connectorId ); if (lastPushOfConnectorReversedIndex === -1) { @@ -190,7 +209,7 @@ export const getPushedInfo = ( return acc; } - const externalService = getExternalService(`${cua.newValue}`); + const externalService = getExternalService(cua.newValConnectorId, cua.newValue); if (externalService === null) { return acc; } diff --git a/x-pack/plugins/cases/public/containers/utils.ts b/x-pack/plugins/cases/public/containers/utils.ts index de67b1cfbd6fa..458899e5f53c9 100644 --- a/x-pack/plugins/cases/public/containers/utils.ts +++ b/x-pack/plugins/cases/public/containers/utils.ts @@ -30,20 +30,14 @@ import { CaseUserActionsResponseRt, CommentType, CasePatchRequest, + CaseResolveResponse, + CaseResolveResponseRt, } from '../../common'; import { AllCases, Case, UpdateByKey } from './types'; import * as i18n from './translations'; export const getTypedPayload = (a: unknown): T => a as T; -export const parseString = (params: string) => { - try { - return JSON.parse(params); - } catch { - return null; - } -}; - export const convertArrayToCamelCase = (arrayOfSnakes: unknown[]): unknown[] => arrayOfSnakes.reduce((acc: unknown[], value) => { if (isArray(value)) { @@ -88,6 +82,12 @@ export const createToasterPlainError = (message: string) => new ToasterError([me export const decodeCaseResponse = (respCase?: CaseResponse) => pipe(CaseResponseRt.decode(respCase), fold(throwErrors(createToasterPlainError), identity)); +export const decodeCaseResolveResponse = (respCase?: CaseResolveResponse) => + pipe( + CaseResolveResponseRt.decode(respCase), + fold(throwErrors(createToasterPlainError), identity) + ); + export const decodeCasesResponse = (respCase?: CasesResponse) => pipe(CasesResponseRt.decode(respCase), fold(throwErrors(createToasterPlainError), identity)); diff --git a/x-pack/plugins/cases/public/types.ts b/x-pack/plugins/cases/public/types.ts index db2e5d6ab6bff..5b19bcfa8ac46 100644 --- a/x-pack/plugins/cases/public/types.ts +++ b/x-pack/plugins/cases/public/types.ts @@ -16,6 +16,7 @@ import type { } from '../../triggers_actions_ui/public'; import type { DataPublicPluginStart } from '../../../../src/plugins/data/public'; import type { EmbeddableStart } from '../../../../src/plugins/embeddable/public'; +import type { SpacesPluginStart } from '../../spaces/public'; import type { Storage } from '../../../../src/plugins/kibana_utils/public'; import { AllCasesProps } from './components/all_cases'; @@ -36,6 +37,7 @@ export interface StartPlugins { lens: LensPublicStart; storage: Storage; triggersActionsUi: TriggersActionsStart; + spaces?: SpacesPluginStart; } /** diff --git a/x-pack/plugins/cases/server/authorization/__snapshots__/audit_logger.test.ts.snap b/x-pack/plugins/cases/server/authorization/__snapshots__/audit_logger.test.ts.snap index 3ca77944776b3..50c085b7f22a8 100644 --- a/x-pack/plugins/cases/server/authorization/__snapshots__/audit_logger.test.ts.snap +++ b/x-pack/plugins/cases/server/authorization/__snapshots__/audit_logger.test.ts.snap @@ -1596,6 +1596,90 @@ Object { } `; +exports[`audit_logger log function event structure creates the correct audit event for operation: "resolveCase" with an error and entity 1`] = ` +Object { + "error": Object { + "code": "Error", + "message": "an error", + }, + "event": Object { + "action": "case_resolve", + "category": Array [ + "database", + ], + "outcome": "failure", + "type": Array [ + "access", + ], + }, + "kibana": Object { + "saved_object": Object { + "id": "1", + "type": "cases", + }, + }, + "message": "Failed attempt to access cases [id=1] as owner \\"awesome\\"", +} +`; + +exports[`audit_logger log function event structure creates the correct audit event for operation: "resolveCase" with an error but no entity 1`] = ` +Object { + "error": Object { + "code": "Error", + "message": "an error", + }, + "event": Object { + "action": "case_resolve", + "category": Array [ + "database", + ], + "outcome": "failure", + "type": Array [ + "access", + ], + }, + "message": "Failed attempt to access a case as any owners", +} +`; + +exports[`audit_logger log function event structure creates the correct audit event for operation: "resolveCase" without an error but with an entity 1`] = ` +Object { + "event": Object { + "action": "case_resolve", + "category": Array [ + "database", + ], + "outcome": "success", + "type": Array [ + "access", + ], + }, + "kibana": Object { + "saved_object": Object { + "id": "5", + "type": "cases", + }, + }, + "message": "User has accessed cases [id=5] as owner \\"super\\"", +} +`; + +exports[`audit_logger log function event structure creates the correct audit event for operation: "resolveCase" without an error or entity 1`] = ` +Object { + "event": Object { + "action": "case_resolve", + "category": Array [ + "database", + ], + "outcome": "success", + "type": Array [ + "access", + ], + }, + "message": "User has accessed a case as any owners", +} +`; + exports[`audit_logger log function event structure creates the correct audit event for operation: "updateCase" with an error and entity 1`] = ` Object { "error": Object { diff --git a/x-pack/plugins/cases/server/authorization/index.ts b/x-pack/plugins/cases/server/authorization/index.ts index 90b89c7f75766..1a74640515173 100644 --- a/x-pack/plugins/cases/server/authorization/index.ts +++ b/x-pack/plugins/cases/server/authorization/index.ts @@ -152,6 +152,14 @@ export const Operations: Record Promise; */ export enum ReadOperations { GetCase = 'getCase', + ResolveCase = 'resolveCase', FindCases = 'findCases', GetCaseIDsByAlertID = 'getCaseIDsByAlertID', GetCaseStatuses = 'getCaseStatuses', diff --git a/x-pack/plugins/cases/server/client/attachments/add.ts b/x-pack/plugins/cases/server/client/attachments/add.ts index 507405d58cef1..b84a6bd84c43b 100644 --- a/x-pack/plugins/cases/server/client/attachments/add.ts +++ b/x-pack/plugins/cases/server/client/attachments/add.ts @@ -106,7 +106,7 @@ async function getSubCase({ caseId, subCaseId: newSubCase.id, fields: ['status', 'sub_case'], - newValue: JSON.stringify({ status: newSubCase.attributes.status }), + newValue: { status: newSubCase.attributes.status }, owner: newSubCase.attributes.owner, }), ], @@ -220,7 +220,7 @@ const addGeneratedAlerts = async ( subCaseId: updatedCase.subCaseId, commentId: newComment.id, fields: ['comment'], - newValue: JSON.stringify(query), + newValue: query, owner: newComment.attributes.owner, }), ], @@ -408,7 +408,7 @@ export const addComment = async ( subCaseId: updatedCase.subCaseId, commentId: newComment.id, fields: ['comment'], - newValue: JSON.stringify(query), + newValue: query, owner: newComment.attributes.owner, }), ], diff --git a/x-pack/plugins/cases/server/client/attachments/update.ts b/x-pack/plugins/cases/server/client/attachments/update.ts index 9816efd9a8452..b5e9e6c372355 100644 --- a/x-pack/plugins/cases/server/client/attachments/update.ts +++ b/x-pack/plugins/cases/server/client/attachments/update.ts @@ -17,6 +17,7 @@ import { SUB_CASE_SAVED_OBJECT, CaseResponse, CommentPatchRequest, + CommentRequest, } from '../../../common'; import { AttachmentService, CasesService } from '../../services'; import { CasesClientArgs } from '..'; @@ -193,12 +194,12 @@ export async function update( subCaseId: subCaseID, commentId: updatedComment.id, fields: ['comment'], - newValue: JSON.stringify(queryRestAttributes), - oldValue: JSON.stringify( + // casting because typescript is complaining that it's not a Record even though it is + newValue: queryRestAttributes as CommentRequest, + oldValue: // We are interested only in ContextBasicRt attributes // myComment.attribute contains also CommentAttributesBasicRt attributes - pick(Object.keys(queryRestAttributes), myComment.attributes) - ), + pick(Object.keys(queryRestAttributes), myComment.attributes), owner: myComment.attributes.owner, }), ], diff --git a/x-pack/plugins/cases/server/client/cases/client.ts b/x-pack/plugins/cases/server/client/cases/client.ts index 0932308c2e269..fd9bd489f31b2 100644 --- a/x-pack/plugins/cases/server/client/cases/client.ts +++ b/x-pack/plugins/cases/server/client/cases/client.ts @@ -18,6 +18,7 @@ import { CasesClient } from '../client'; import { CasesClientInternal } from '../client_internal'; import { ICasePostRequest, + ICaseResolveResponse, ICaseResponse, ICasesFindRequest, ICasesFindResponse, @@ -31,6 +32,7 @@ import { find } from './find'; import { CasesByAlertIDParams, get, + resolve, getCasesByAlertID, GetParams, getReporters, @@ -57,6 +59,11 @@ export interface CasesSubClient { * Retrieves a single case with the specified ID. */ get(params: GetParams): Promise; + /** + * @experimental + * Retrieves a single case resolving the specified ID. + */ + resolve(params: GetParams): Promise; /** * Pushes a specific case to an external system. */ @@ -99,6 +106,7 @@ export const createCasesSubClient = ( create: (data: CasePostRequest) => create(data, clientArgs), find: (params: CasesFindRequest) => find(params, clientArgs), get: (params: GetParams) => get(params, clientArgs), + resolve: (params: GetParams) => resolve(params, clientArgs), push: (params: PushParams) => push(params, clientArgs, casesClient, casesClientInternal), update: (cases: CasesPatchRequest) => update(cases, clientArgs, casesClientInternal), delete: (ids: string[]) => deleteCases(ids, clientArgs), diff --git a/x-pack/plugins/cases/server/client/cases/create.ts b/x-pack/plugins/cases/server/client/cases/create.ts index 887990fef8938..488bc523f7796 100644 --- a/x-pack/plugins/cases/server/client/cases/create.ts +++ b/x-pack/plugins/cases/server/client/cases/create.ts @@ -106,7 +106,7 @@ export const create = async ( actionBy: { username, full_name, email }, caseId: newCase.id, fields: ['description', 'status', 'tags', 'title', 'connector', 'settings', OWNER_FIELD], - newValue: JSON.stringify(query), + newValue: query, owner: newCase.attributes.owner, }), ], diff --git a/x-pack/plugins/cases/server/client/cases/delete.ts b/x-pack/plugins/cases/server/client/cases/delete.ts index 80a687a0e72f8..4333535f17a24 100644 --- a/x-pack/plugins/cases/server/client/cases/delete.ts +++ b/x-pack/plugins/cases/server/client/cases/delete.ts @@ -168,7 +168,7 @@ export async function deleteCases(ids: string[], clientArgs: CasesClientArgs): P 'settings', OWNER_FIELD, 'comment', - ...(ENABLE_CASE_CONNECTOR ? ['sub_case'] : []), + ...(ENABLE_CASE_CONNECTOR ? ['sub_case' as const] : []), ], owner: caseInfo.attributes.owner, }) diff --git a/x-pack/plugins/cases/server/client/cases/get.ts b/x-pack/plugins/cases/server/client/cases/get.ts index 6b0015d4ffb14..c6ab033c2a848 100644 --- a/x-pack/plugins/cases/server/client/cases/get.ts +++ b/x-pack/plugins/cases/server/client/cases/get.ts @@ -9,10 +9,12 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; -import { SavedObject } from 'kibana/server'; +import { SavedObject, SavedObjectsResolveResponse } from 'kibana/server'; import { CaseResponseRt, CaseResponse, + CaseResolveResponseRt, + CaseResolveResponse, User, UsersRt, AllTagsFindRequest, @@ -230,6 +232,86 @@ export const get = async ( } }; +/** + * Retrieves a case resolving its ID and optionally loading its comments and sub case comments. + * + * @experimental + */ +export const resolve = async ( + { id, includeComments, includeSubCaseComments }: GetParams, + clientArgs: CasesClientArgs +): Promise => { + const { unsecuredSavedObjectsClient, caseService, logger, authorization } = clientArgs; + + try { + if (!ENABLE_CASE_CONNECTOR && includeSubCaseComments) { + throw Boom.badRequest( + 'The `includeSubCaseComments` is not supported when the case connector feature is disabled' + ); + } + + const { + saved_object: savedObject, + ...resolveData + }: SavedObjectsResolveResponse = await caseService.getResolveCase({ + unsecuredSavedObjectsClient, + id, + }); + + await authorization.ensureAuthorized({ + operation: Operations.resolveCase, + entities: [ + { + id: savedObject.id, + owner: savedObject.attributes.owner, + }, + ], + }); + + let subCaseIds: string[] = []; + if (ENABLE_CASE_CONNECTOR) { + const subCasesForCaseId = await caseService.findSubCasesByCaseId({ + unsecuredSavedObjectsClient, + ids: [id], + }); + subCaseIds = subCasesForCaseId.saved_objects.map((so) => so.id); + } + + if (!includeComments) { + return CaseResolveResponseRt.encode({ + ...resolveData, + case: flattenCaseSavedObject({ + savedObject, + subCaseIds, + }), + }); + } + + const theComments = await caseService.getAllCaseComments({ + unsecuredSavedObjectsClient, + id, + options: { + sortField: 'created_at', + sortOrder: 'asc', + }, + includeSubCaseComments: ENABLE_CASE_CONNECTOR && includeSubCaseComments, + }); + + return CaseResolveResponseRt.encode({ + ...resolveData, + case: flattenCaseSavedObject({ + savedObject, + subCaseIds, + comments: theComments.saved_objects, + totalComment: theComments.total, + totalAlerts: countAlertsForID({ comments: theComments, id }), + }), + }); + } catch (error) { + throw createCaseError({ message: `Failed to resolve case id: ${id}: ${error}`, error, logger }); + } +}; + /** * Retrieves the tags from all the cases. */ diff --git a/x-pack/plugins/cases/server/client/cases/mock.ts b/x-pack/plugins/cases/server/client/cases/mock.ts index 313d6cd12a6db..22520cea11014 100644 --- a/x-pack/plugins/cases/server/client/cases/mock.ts +++ b/x-pack/plugins/cases/server/client/cases/mock.ts @@ -231,8 +231,10 @@ export const userActions: CaseUserActionsResponse = [ username: 'elastic', }, new_value: - '{"title":"Case SIR","tags":["sir"],"description":"testing sir","connector":{"id":"456","name":"ServiceNow SN","type":".servicenow-sir","fields":{"category":"Denial of Service","destIp":true,"malwareHash":true,"malwareUrl":true,"priority":"2","sourceIp":true,"subcategory":"45"}},"settings":{"syncAlerts":true}}', + '{"title":"Case SIR","tags":["sir"],"description":"testing sir","connector":{"name":"ServiceNow SN","type":".servicenow-sir","fields":{"category":"Denial of Service","destIp":true,"malwareHash":true,"malwareUrl":true,"priority":"2","sourceIp":true,"subcategory":"45"}},"settings":{"syncAlerts":true}}', + new_val_connector_id: '456', old_value: null, + old_val_connector_id: null, action_id: 'fd830c60-6646-11eb-a291-51bf6b175a53', case_id: 'fcdedd20-6646-11eb-a291-51bf6b175a53', comment_id: null, @@ -248,7 +250,9 @@ export const userActions: CaseUserActionsResponse = [ username: 'elastic', }, new_value: - '{"pushed_at":"2021-02-03T17:41:26.108Z","pushed_by":{"username":"elastic","full_name":"Elastic","email":"elastic@elastic.co"},"connector_id":"456","connector_name":"ServiceNow SN","external_id":"external-id","external_title":"SIR0010037","external_url":"https://dev92273.service-now.com/nav_to.do?uri=sn_si_incident.do?sys_id=external-id"}', + '{"pushed_at":"2021-02-03T17:41:26.108Z","pushed_by":{"username":"elastic","full_name":"Elastic","email":"elastic@elastic.co"},"connector_name":"ServiceNow SN","external_id":"external-id","external_title":"SIR0010037","external_url":"https://dev92273.service-now.com/nav_to.do?uri=sn_si_incident.do?sys_id=external-id"}', + new_val_connector_id: '456', + old_val_connector_id: null, old_value: null, action_id: '0a801750-6647-11eb-a291-51bf6b175a53', case_id: 'fcdedd20-6646-11eb-a291-51bf6b175a53', @@ -265,6 +269,8 @@ export const userActions: CaseUserActionsResponse = [ username: 'elastic', }, new_value: '{"type":"alert","alertId":"alert-id-1","index":".siem-signals-default-000008"}', + new_val_connector_id: null, + old_val_connector_id: null, old_value: null, action_id: '7373eb60-6647-11eb-a291-51bf6b175a53', case_id: 'fcdedd20-6646-11eb-a291-51bf6b175a53', @@ -282,6 +288,8 @@ export const userActions: CaseUserActionsResponse = [ }, new_value: '{"type":"alert","alertId":"alert-id-2","index":".siem-signals-default-000008"}', old_value: null, + new_val_connector_id: null, + old_val_connector_id: null, action_id: '7abc6410-6647-11eb-a291-51bf6b175a53', case_id: 'fcdedd20-6646-11eb-a291-51bf6b175a53', comment_id: 'comment-alert-2', @@ -297,8 +305,10 @@ export const userActions: CaseUserActionsResponse = [ username: 'elastic', }, new_value: - '{"pushed_at":"2021-02-03T17:45:29.400Z","pushed_by":{"username":"elastic","full_name":"Elastic","email":"elastic@elastic.co"},"connector_id":"456","connector_name":"ServiceNow SN","external_id":"external-id","external_title":"SIR0010037","external_url":"https://dev92273.service-now.com/nav_to.do?uri=sn_si_incident.do?sys_id=external-id"}', + '{"pushed_at":"2021-02-03T17:45:29.400Z","pushed_by":{"username":"elastic","full_name":"Elastic","email":"elastic@elastic.co"},"connector_name":"ServiceNow SN","external_id":"external-id","external_title":"SIR0010037","external_url":"https://dev92273.service-now.com/nav_to.do?uri=sn_si_incident.do?sys_id=external-id"}', + new_val_connector_id: '456', old_value: null, + old_val_connector_id: null, action_id: '9b91d8f0-6647-11eb-a291-51bf6b175a53', case_id: 'fcdedd20-6646-11eb-a291-51bf6b175a53', comment_id: null, @@ -315,6 +325,8 @@ export const userActions: CaseUserActionsResponse = [ }, new_value: '{"comment":"a comment!","type":"user"}', old_value: null, + new_val_connector_id: null, + old_val_connector_id: null, action_id: '0818e5e0-6648-11eb-a291-51bf6b175a53', case_id: 'fcdedd20-6646-11eb-a291-51bf6b175a53', comment_id: 'comment-user-1', diff --git a/x-pack/plugins/cases/server/client/cases/push.ts b/x-pack/plugins/cases/server/client/cases/push.ts index 3048cf01bb3ba..1b090a653546d 100644 --- a/x-pack/plugins/cases/server/client/cases/push.ts +++ b/x-pack/plugins/cases/server/client/cases/push.ts @@ -241,7 +241,7 @@ export const push = async ( actionBy: { username, full_name, email }, caseId, fields: ['pushed'], - newValue: JSON.stringify(externalService), + newValue: externalService, owner: myCase.attributes.owner, }), ], diff --git a/x-pack/plugins/cases/server/client/cases/utils.test.ts b/x-pack/plugins/cases/server/client/cases/utils.test.ts index d7c45d3e1e9ae..315e9966d347b 100644 --- a/x-pack/plugins/cases/server/client/cases/utils.test.ts +++ b/x-pack/plugins/cases/server/client/cases/utils.test.ts @@ -799,8 +799,10 @@ describe('utils', () => { username: 'elastic', }, new_value: - // The connector id is 123 - '{"pushed_at":"2021-02-03T17:45:29.400Z","pushed_by":{"username":"elastic","full_name":"Elastic","email":"elastic@elastic.co"},"connector_id":"123","connector_name":"ServiceNow SN","external_id":"external-id","external_title":"SIR0010037","external_url":"https://dev92273.service-now.com/nav_to.do?uri=sn_si_incident.do?sys_id=external-id"}', + // The connector id is 123 + '{"pushed_at":"2021-02-03T17:45:29.400Z","pushed_by":{"username":"elastic","full_name":"Elastic","email":"elastic@elastic.co"},"connector_name":"ServiceNow SN","external_id":"external-id","external_title":"SIR0010037","external_url":"https://dev92273.service-now.com/nav_to.do?uri=sn_si_incident.do?sys_id=external-id"}', + new_val_connector_id: '123', + old_val_connector_id: null, old_value: null, action_id: '9b91d8f0-6647-11eb-a291-51bf6b175a53', case_id: 'fcdedd20-6646-11eb-a291-51bf6b175a53', diff --git a/x-pack/plugins/cases/server/client/cases/utils.ts b/x-pack/plugins/cases/server/client/cases/utils.ts index 359ad4b41ead0..f5cf2fe4b3f51 100644 --- a/x-pack/plugins/cases/server/client/cases/utils.ts +++ b/x-pack/plugins/cases/server/client/cases/utils.ts @@ -20,6 +20,8 @@ import { CommentRequestUserType, CommentRequestAlertType, CommentRequestActionsType, + CaseUserActionResponse, + isPush, } from '../../../common'; import { ActionsClient } from '../../../../actions/server'; import { CasesClientGetAlertsResponse } from '../../client/alerts/types'; @@ -55,22 +57,36 @@ export const getLatestPushInfo = ( userActions: CaseUserActionsResponse ): { index: number; pushedInfo: CaseFullExternalService } | null => { for (const [index, action] of [...userActions].reverse().entries()) { - if (action.action === 'push-to-service' && action.new_value) + if ( + isPush(action.action, action.action_field) && + isValidNewValue(action) && + connectorId === action.new_val_connector_id + ) { try { const pushedInfo = JSON.parse(action.new_value); - if (pushedInfo.connector_id === connectorId) { - // We returned the index of the element in the userActions array. - // As we traverse the userActions in reverse we need to calculate the index of a normal traversal - return { index: userActions.length - index - 1, pushedInfo }; - } + // We returned the index of the element in the userActions array. + // As we traverse the userActions in reverse we need to calculate the index of a normal traversal + return { + index: userActions.length - index - 1, + pushedInfo: { ...pushedInfo, connector_id: connectorId }, + }; } catch (e) { - // Silence JSON parse errors + // ignore parse failures and check the next user action } + } } return null; }; +type NonNullNewValueAction = Omit & { + new_value: string; + new_val_connector_id: string; +}; + +const isValidNewValue = (userAction: CaseUserActionResponse): userAction is NonNullNewValueAction => + userAction.new_val_connector_id != null && userAction.new_value != null; + const getCommentContent = (comment: CommentResponse): string => { if (comment.type === CommentType.user) { return comment.comment; diff --git a/x-pack/plugins/cases/server/client/mocks.ts b/x-pack/plugins/cases/server/client/mocks.ts index 05b7d055656b1..f0ca7ae9eaf71 100644 --- a/x-pack/plugins/cases/server/client/mocks.ts +++ b/x-pack/plugins/cases/server/client/mocks.ts @@ -22,6 +22,7 @@ const createCasesSubClientMock = (): CasesSubClientMock => { return { create: jest.fn(), find: jest.fn(), + resolve: jest.fn(), get: jest.fn(), push: jest.fn(), update: jest.fn(), diff --git a/x-pack/plugins/cases/server/client/typedoc_interfaces.ts b/x-pack/plugins/cases/server/client/typedoc_interfaces.ts index bf444ee9420ed..feeaa6b6dcb58 100644 --- a/x-pack/plugins/cases/server/client/typedoc_interfaces.ts +++ b/x-pack/plugins/cases/server/client/typedoc_interfaces.ts @@ -16,6 +16,7 @@ import { AllCommentsResponse, CasePostRequest, + CaseResolveResponse, CaseResponse, CasesConfigurePatch, CasesConfigureRequest, @@ -40,6 +41,7 @@ export interface ICasePostRequest extends CasePostRequest {} export interface ICasesFindRequest extends CasesFindRequest {} export interface ICasesPatchRequest extends CasesPatchRequest {} export interface ICaseResponse extends CaseResponse {} +export interface ICaseResolveResponse extends CaseResolveResponse {} export interface ICasesResponse extends CasesResponse {} export interface ICasesFindResponse extends CasesFindResponse {} diff --git a/x-pack/plugins/cases/server/client/user_actions/get.test.ts b/x-pack/plugins/cases/server/client/user_actions/get.test.ts new file mode 100644 index 0000000000000..302e069cde4d1 --- /dev/null +++ b/x-pack/plugins/cases/server/client/user_actions/get.test.ts @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CaseUserActionResponse, SUB_CASE_SAVED_OBJECT } from '../../../common'; +import { SUB_CASE_REF_NAME } from '../../common'; +import { extractAttributesWithoutSubCases } from './get'; + +describe('get', () => { + describe('extractAttributesWithoutSubCases', () => { + it('returns an empty array when given an empty array', () => { + expect( + extractAttributesWithoutSubCases({ ...getFindResponseFields(), saved_objects: [] }) + ).toEqual([]); + }); + + it('filters out saved objects with a sub case reference', () => { + expect( + extractAttributesWithoutSubCases({ + ...getFindResponseFields(), + saved_objects: [ + { + type: 'a', + references: [{ name: SUB_CASE_REF_NAME, type: SUB_CASE_SAVED_OBJECT, id: '1' }], + id: 'b', + score: 0, + attributes: {} as CaseUserActionResponse, + }, + ], + }) + ).toEqual([]); + }); + + it('filters out saved objects with a sub case reference with other references', () => { + expect( + extractAttributesWithoutSubCases({ + ...getFindResponseFields(), + saved_objects: [ + { + type: 'a', + references: [ + { name: SUB_CASE_REF_NAME, type: SUB_CASE_SAVED_OBJECT, id: '1' }, + { name: 'a', type: 'b', id: '5' }, + ], + id: 'b', + score: 0, + attributes: {} as CaseUserActionResponse, + }, + ], + }) + ).toEqual([]); + }); + + it('keeps saved objects that do not have a sub case reference', () => { + expect( + extractAttributesWithoutSubCases({ + ...getFindResponseFields(), + saved_objects: [ + { + type: 'a', + references: [ + { name: SUB_CASE_REF_NAME, type: 'awesome', id: '1' }, + { name: 'a', type: 'b', id: '5' }, + ], + id: 'b', + score: 0, + attributes: { field: '1' } as unknown as CaseUserActionResponse, + }, + ], + }) + ).toEqual([{ field: '1' }]); + }); + + it('filters multiple saved objects correctly', () => { + expect( + extractAttributesWithoutSubCases({ + ...getFindResponseFields(), + saved_objects: [ + { + type: 'a', + references: [ + { name: SUB_CASE_REF_NAME, type: 'awesome', id: '1' }, + { name: 'a', type: 'b', id: '5' }, + ], + id: 'b', + score: 0, + attributes: { field: '2' } as unknown as CaseUserActionResponse, + }, + { + type: 'a', + references: [{ name: SUB_CASE_REF_NAME, type: SUB_CASE_SAVED_OBJECT, id: '1' }], + id: 'b', + score: 0, + attributes: { field: '1' } as unknown as CaseUserActionResponse, + }, + ], + }) + ).toEqual([{ field: '2' }]); + }); + }); +}); + +const getFindResponseFields = () => ({ page: 1, per_page: 1, total: 0 }); diff --git a/x-pack/plugins/cases/server/client/user_actions/get.ts b/x-pack/plugins/cases/server/client/user_actions/get.ts index 2a6608014c800..660cf1b6a336e 100644 --- a/x-pack/plugins/cases/server/client/user_actions/get.ts +++ b/x-pack/plugins/cases/server/client/user_actions/get.ts @@ -5,14 +5,14 @@ * 2.0. */ +import { SavedObjectReference, SavedObjectsFindResponse } from 'kibana/server'; import { - CASE_COMMENT_SAVED_OBJECT, - CASE_SAVED_OBJECT, CaseUserActionsResponse, CaseUserActionsResponseRt, SUB_CASE_SAVED_OBJECT, + CaseUserActionResponse, } from '../../../common'; -import { createCaseError, checkEnabledCaseConnectorOrThrow } from '../../common'; +import { createCaseError, checkEnabledCaseConnectorOrThrow, SUB_CASE_REF_NAME } from '../../common'; import { CasesClientArgs } from '..'; import { Operations } from '../../authorization'; import { UserActionGet } from './client'; @@ -40,23 +40,12 @@ export const get = async ( operation: Operations.getUserActions, }); - return CaseUserActionsResponseRt.encode( - userActions.saved_objects.reduce((acc, ua) => { - if (subCaseId == null && ua.references.some((uar) => uar.type === SUB_CASE_SAVED_OBJECT)) { - return acc; - } - return [ - ...acc, - { - ...ua.attributes, - action_id: ua.id, - case_id: ua.references.find((r) => r.type === CASE_SAVED_OBJECT)?.id ?? '', - comment_id: ua.references.find((r) => r.type === CASE_COMMENT_SAVED_OBJECT)?.id ?? null, - sub_case_id: ua.references.find((r) => r.type === SUB_CASE_SAVED_OBJECT)?.id ?? '', - }, - ]; - }, []) - ); + const resultsToEncode = + subCaseId == null + ? extractAttributesWithoutSubCases(userActions) + : extractAttributes(userActions); + + return CaseUserActionsResponseRt.encode(resultsToEncode); } catch (error) { throw createCaseError({ message: `Failed to retrieve user actions case id: ${caseId} sub case id: ${subCaseId}: ${error}`, @@ -65,3 +54,21 @@ export const get = async ( }); } }; + +export function extractAttributesWithoutSubCases( + userActions: SavedObjectsFindResponse +): CaseUserActionsResponse { + // exclude user actions relating to sub cases from the results + const hasSubCaseReference = (references: SavedObjectReference[]) => + references.find((ref) => ref.type === SUB_CASE_SAVED_OBJECT && ref.name === SUB_CASE_REF_NAME); + + return userActions.saved_objects + .filter((so) => !hasSubCaseReference(so.references)) + .map((so) => so.attributes); +} + +function extractAttributes( + userActions: SavedObjectsFindResponse +): CaseUserActionsResponse { + return userActions.saved_objects.map((so) => so.attributes); +} diff --git a/x-pack/plugins/cases/server/common/constants.ts b/x-pack/plugins/cases/server/common/constants.ts index 1f6af310d6ece..eba0a64a5c0be 100644 --- a/x-pack/plugins/cases/server/common/constants.ts +++ b/x-pack/plugins/cases/server/common/constants.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { CASE_COMMENT_SAVED_OBJECT, CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../common'; + /** * The name of the saved object reference indicating the action connector ID. This is stored in the Saved Object reference * field's name property. @@ -15,3 +17,30 @@ export const CONNECTOR_ID_REFERENCE_NAME = 'connectorId'; * The name of the saved object reference indicating the action connector ID that was used to push a case. */ export const PUSH_CONNECTOR_ID_REFERENCE_NAME = 'pushConnectorId'; + +/** + * The name of the saved object reference indicating the action connector ID that was used for + * adding a connector, or updating the existing connector for a user action's old_value field. + */ +export const USER_ACTION_OLD_ID_REF_NAME = 'oldConnectorId'; + +/** + * The name of the saved object reference indicating the action connector ID that was used for pushing a case, + * for a user action's old_value field. + */ +export const USER_ACTION_OLD_PUSH_ID_REF_NAME = 'oldPushConnectorId'; + +/** + * The name of the saved object reference indicating the caseId reference + */ +export const CASE_REF_NAME = `associated-${CASE_SAVED_OBJECT}`; + +/** + * The name of the saved object reference indicating the commentId reference + */ +export const COMMENT_REF_NAME = `associated-${CASE_COMMENT_SAVED_OBJECT}`; + +/** + * The name of the saved object reference indicating the subCaseId reference + */ +export const SUB_CASE_REF_NAME = `associated-${SUB_CASE_SAVED_OBJECT}`; diff --git a/x-pack/plugins/cases/server/index.ts b/x-pack/plugins/cases/server/index.ts index 5e433b46b80e5..ad76724eb49f7 100644 --- a/x-pack/plugins/cases/server/index.ts +++ b/x-pack/plugins/cases/server/index.ts @@ -15,7 +15,8 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { markdownPlugins: true, }, - deprecations: ({ renameFromRoot }) => [ + deprecations: ({ deprecate, renameFromRoot }) => [ + deprecate('enabled', '8.0.0'), renameFromRoot('xpack.case.enabled', 'xpack.cases.enabled'), ], }; diff --git a/x-pack/plugins/cases/server/routes/api/cases/get_case.ts b/x-pack/plugins/cases/server/routes/api/cases/get_case.ts index 2313c3cad9007..4d81b6d5e11b3 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/get_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/get_case.ts @@ -45,4 +45,38 @@ export function initGetCaseApi({ router, logger }: RouteDeps) { } } ); + + router.get( + { + path: `${CASE_DETAILS_URL}/resolve`, + validate: { + params: schema.object({ + case_id: schema.string(), + }), + query: schema.object({ + includeComments: schema.boolean({ defaultValue: true }), + includeSubCaseComments: schema.maybe(schema.boolean({ defaultValue: false })), + }), + }, + }, + async (context, request, response) => { + try { + const casesClient = await context.cases.getCasesClient(); + const id = request.params.case_id; + + return response.ok({ + body: await casesClient.cases.resolve({ + id, + includeComments: request.query.includeComments, + includeSubCaseComments: request.query.includeSubCaseComments, + }), + }); + } catch (error) { + logger.error( + `Failed to retrieve case in resolve route case id: ${request.params.case_id} \ninclude comments: ${request.query.includeComments} \ninclude sub comments: ${request.query.includeSubCaseComments}: ${error}` + ); + return response.customError(wrapError(error)); + } + } + ); } diff --git a/x-pack/plugins/cases/server/saved_object_types/cases.ts b/x-pack/plugins/cases/server/saved_object_types/cases.ts index a362d77c06626..74c6a053e95c0 100644 --- a/x-pack/plugins/cases/server/saved_object_types/cases.ts +++ b/x-pack/plugins/cases/server/saved_object_types/cases.ts @@ -117,7 +117,7 @@ export const createCaseSavedObjectType = ( type: 'keyword', }, title: { - type: 'keyword', + type: 'text', }, status: { type: 'keyword', diff --git a/x-pack/plugins/cases/server/saved_object_types/comments.ts b/x-pack/plugins/cases/server/saved_object_types/comments.ts index af14123eca580..64e75ad26ae28 100644 --- a/x-pack/plugins/cases/server/saved_object_types/comments.ts +++ b/x-pack/plugins/cases/server/saved_object_types/comments.ts @@ -112,5 +112,6 @@ export const createCaseCommentSavedObjectType = ({ migrations: createCommentsMigrations(migrationDeps), management: { importableAndExportable: true, + visibleInManagement: false, }, }); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts index bca12a86a544e..9020f65ae352c 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts @@ -30,322 +30,324 @@ const create_7_14_0_case = ({ }, }); -describe('7.15.0 connector ID migration', () => { - it('does not create a reference when the connector.id is none', () => { - const caseSavedObject = create_7_14_0_case({ connector: getNoneCaseConnector() }); - - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; - - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); - expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` - Object { - "fields": null, - "name": "none", - "type": ".none", - } - `); - }); +describe('case migrations', () => { + describe('7.15.0 connector ID migration', () => { + it('does not create a reference when the connector.id is none', () => { + const caseSavedObject = create_7_14_0_case({ connector: getNoneCaseConnector() }); + + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); + expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` + Object { + "fields": null, + "name": "none", + "type": ".none", + } + `); + }); - it('does not create a reference when the connector is undefined', () => { - const caseSavedObject = create_7_14_0_case(); - - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; - - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); - expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` - Object { - "fields": null, - "name": "none", - "type": ".none", - } - `); - }); + it('does not create a reference when the connector is undefined', () => { + const caseSavedObject = create_7_14_0_case(); - it('sets the connector to the default none connector if the connector.id is undefined', () => { - const caseSavedObject = create_7_14_0_case({ - connector: { - fields: null, - name: ConnectorTypes.jira, - type: ConnectorTypes.jira, - } as ESCaseConnectorWithId, - }); + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; - - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); - expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` - Object { - "fields": null, - "name": "none", - "type": ".none", - } - `); - }); + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); + expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` + Object { + "fields": null, + "name": "none", + "type": ".none", + } + `); + }); - it('does not create a reference when the external_service is null', () => { - const caseSavedObject = create_7_14_0_case({ externalService: null }); + it('sets the connector to the default none connector if the connector.id is undefined', () => { + const caseSavedObject = create_7_14_0_case({ + connector: { + fields: null, + name: ConnectorTypes.jira, + type: ConnectorTypes.jira, + } as ESCaseConnectorWithId, + }); + + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); + expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` + Object { + "fields": null, + "name": "none", + "type": ".none", + } + `); + }); - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; + it('does not create a reference when the external_service is null', () => { + const caseSavedObject = create_7_14_0_case({ externalService: null }); - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.external_service).toBeNull(); - }); + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; - it('does not create a reference when the external_service is undefined and sets external_service to null', () => { - const caseSavedObject = create_7_14_0_case(); + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.external_service).toBeNull(); + }); - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; + it('does not create a reference when the external_service is undefined and sets external_service to null', () => { + const caseSavedObject = create_7_14_0_case(); - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.external_service).toBeNull(); - }); + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; - it('does not create a reference when the external_service.connector_id is none', () => { - const caseSavedObject = create_7_14_0_case({ - externalService: createExternalService({ connector_id: noneConnectorId }), + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.external_service).toBeNull(); }); - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; - - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` - Object { - "connector_name": ".jira", - "external_id": "100", - "external_title": "awesome", - "external_url": "http://www.google.com", - "pushed_at": "2019-11-25T21:54:48.952Z", - "pushed_by": Object { - "email": "testemail@elastic.co", - "full_name": "elastic", - "username": "elastic", - }, - } - `); - }); - - it('preserves the existing references when migrating', () => { - const caseSavedObject = { - ...create_7_14_0_case(), - references: [{ id: '1', name: 'awesome', type: 'hello' }], - }; + it('does not create a reference when the external_service.connector_id is none', () => { + const caseSavedObject = create_7_14_0_case({ + externalService: createExternalService({ connector_id: noneConnectorId }), + }); - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; - expect(migratedConnector.references.length).toBe(1); - expect(migratedConnector.references).toMatchInlineSnapshot(` - Array [ + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` Object { - "id": "1", - "name": "awesome", - "type": "hello", - }, - ] - `); - }); + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + }); - it('creates a connector reference and removes the connector.id field', () => { - const caseSavedObject = create_7_14_0_case({ - connector: { - id: '123', - fields: null, - name: 'connector', - type: ConnectorTypes.jira, - }, + it('preserves the existing references when migrating', () => { + const caseSavedObject = { + ...create_7_14_0_case(), + references: [{ id: '1', name: 'awesome', type: 'hello' }], + }; + + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector.references.length).toBe(1); + expect(migratedConnector.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "awesome", + "type": "hello", + }, + ] + `); }); - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; - - expect(migratedConnector.references.length).toBe(1); - expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); - expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` - Object { - "fields": null, - "name": "connector", - "type": ".jira", - } - `); - expect(migratedConnector.references).toMatchInlineSnapshot(` - Array [ - Object { - "id": "123", - "name": "connectorId", - "type": "action", + it('creates a connector reference and removes the connector.id field', () => { + const caseSavedObject = create_7_14_0_case({ + connector: { + id: '123', + fields: null, + name: 'connector', + type: ConnectorTypes.jira, }, - ] - `); - }); + }); - it('creates a push connector reference and removes the connector_id field', () => { - const caseSavedObject = create_7_14_0_case({ - externalService: { - connector_id: '100', - connector_name: '.jira', - external_id: '100', - external_title: 'awesome', - external_url: 'http://www.google.com', - pushed_at: '2019-11-25T21:54:48.952Z', - pushed_by: { - full_name: 'elastic', - email: 'testemail@elastic.co', - username: 'elastic', - }, - }, - }); + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; - - expect(migratedConnector.references.length).toBe(1); - expect(migratedConnector.attributes.external_service).not.toHaveProperty('connector_id'); - expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` - Object { - "connector_name": ".jira", - "external_id": "100", - "external_title": "awesome", - "external_url": "http://www.google.com", - "pushed_at": "2019-11-25T21:54:48.952Z", - "pushed_by": Object { - "email": "testemail@elastic.co", - "full_name": "elastic", - "username": "elastic", - }, - } - `); - expect(migratedConnector.references).toMatchInlineSnapshot(` - Array [ + expect(migratedConnector.references.length).toBe(1); + expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); + expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` Object { - "id": "100", - "name": "pushConnectorId", - "type": "action", - }, - ] - `); - }); + "fields": null, + "name": "connector", + "type": ".jira", + } + `); + expect(migratedConnector.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "123", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); - it('does not create a reference and preserves the existing external_service fields when connector_id is null', () => { - const caseSavedObject = create_7_14_0_case({ - externalService: { - connector_id: null, - connector_name: '.jira', - external_id: '100', - external_title: 'awesome', - external_url: 'http://www.google.com', - pushed_at: '2019-11-25T21:54:48.952Z', - pushed_by: { - full_name: 'elastic', - email: 'testemail@elastic.co', - username: 'elastic', + it('creates a push connector reference and removes the connector_id field', () => { + const caseSavedObject = create_7_14_0_case({ + externalService: { + connector_id: '100', + connector_name: '.jira', + external_id: '100', + external_title: 'awesome', + external_url: 'http://www.google.com', + pushed_at: '2019-11-25T21:54:48.952Z', + pushed_by: { + full_name: 'elastic', + email: 'testemail@elastic.co', + username: 'elastic', + }, }, - }, + }); + + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector.references.length).toBe(1); + expect(migratedConnector.attributes.external_service).not.toHaveProperty('connector_id'); + expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + expect(migratedConnector.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); }); - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; - - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.external_service).not.toHaveProperty('connector_id'); - expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` - Object { - "connector_name": ".jira", - "external_id": "100", - "external_title": "awesome", - "external_url": "http://www.google.com", - "pushed_at": "2019-11-25T21:54:48.952Z", - "pushed_by": Object { - "email": "testemail@elastic.co", - "full_name": "elastic", - "username": "elastic", + it('does not create a reference and preserves the existing external_service fields when connector_id is null', () => { + const caseSavedObject = create_7_14_0_case({ + externalService: { + connector_id: null, + connector_name: '.jira', + external_id: '100', + external_title: 'awesome', + external_url: 'http://www.google.com', + pushed_at: '2019-11-25T21:54:48.952Z', + pushed_by: { + full_name: 'elastic', + email: 'testemail@elastic.co', + username: 'elastic', + }, }, - } - `); - }); + }); - it('migrates both connector and external_service when provided', () => { - const caseSavedObject = create_7_14_0_case({ - externalService: { - connector_id: '100', - connector_name: '.jira', - external_id: '100', - external_title: 'awesome', - external_url: 'http://www.google.com', - pushed_at: '2019-11-25T21:54:48.952Z', - pushed_by: { - full_name: 'elastic', - email: 'testemail@elastic.co', - username: 'elastic', - }, - }, - connector: { - id: '123', - fields: null, - name: 'connector', - type: ConnectorTypes.jira, - }, + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.external_service).not.toHaveProperty('connector_id'); + expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); }); - const migratedConnector = caseConnectorIdMigration( - caseSavedObject - ) as SavedObjectSanitizedDoc; - - expect(migratedConnector.references.length).toBe(2); - expect(migratedConnector.attributes.external_service).not.toHaveProperty('connector_id'); - expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` - Object { - "connector_name": ".jira", - "external_id": "100", - "external_title": "awesome", - "external_url": "http://www.google.com", - "pushed_at": "2019-11-25T21:54:48.952Z", - "pushed_by": Object { - "email": "testemail@elastic.co", - "full_name": "elastic", - "username": "elastic", + it('migrates both connector and external_service when provided', () => { + const caseSavedObject = create_7_14_0_case({ + externalService: { + connector_id: '100', + connector_name: '.jira', + external_id: '100', + external_title: 'awesome', + external_url: 'http://www.google.com', + pushed_at: '2019-11-25T21:54:48.952Z', + pushed_by: { + full_name: 'elastic', + email: 'testemail@elastic.co', + username: 'elastic', + }, }, - } - `); - expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); - expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` - Object { - "fields": null, - "name": "connector", - "type": ".jira", - } - `); - expect(migratedConnector.references).toMatchInlineSnapshot(` - Array [ - Object { - "id": "123", - "name": "connectorId", - "type": "action", + connector: { + id: '123', + fields: null, + name: 'connector', + type: ConnectorTypes.jira, }, + }); + + const migratedConnector = caseConnectorIdMigration( + caseSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector.references.length).toBe(2); + expect(migratedConnector.attributes.external_service).not.toHaveProperty('connector_id'); + expect(migratedConnector.attributes.external_service).toMatchInlineSnapshot(` Object { - "id": "100", - "name": "pushConnectorId", - "type": "action", - }, - ] - `); + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); + expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` + Object { + "fields": null, + "name": "connector", + "type": ".jira", + } + `); + expect(migratedConnector.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "123", + "name": "connectorId", + "type": "action", + }, + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); + }); }); }); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts index bffd4171270ef..80f02fa3bf6a6 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts @@ -14,7 +14,11 @@ import { } from '../../../../../../src/core/server'; import { ESConnectorFields } from '../../services'; import { ConnectorTypes, CaseType } from '../../../common'; -import { transformConnectorIdToReference, transformPushConnectorIdToReference } from './utils'; +import { + transformConnectorIdToReference, + transformPushConnectorIdToReference, +} from '../../services/user_actions/transform'; +import { CONNECTOR_ID_REFERENCE_NAME, PUSH_CONNECTOR_ID_REFERENCE_NAME } from '../../common'; interface UnsanitizedCaseConnector { connector_id: string; @@ -50,11 +54,13 @@ export const caseConnectorIdMigration = ( // removing the id field since it will be stored in the references instead const { connector, external_service, ...restAttributes } = doc.attributes; - const { transformedConnector, references: connectorReferences } = - transformConnectorIdToReference(connector); + const { transformedConnector, references: connectorReferences } = transformConnectorIdToReference( + CONNECTOR_ID_REFERENCE_NAME, + connector + ); const { transformedPushConnector, references: pushConnectorReferences } = - transformPushConnectorIdToReference(external_service); + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, external_service); const { references = [] } = doc; diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.test.ts index 4467b499817a5..9ae0285598dbf 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.test.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.test.ts @@ -40,87 +40,89 @@ const create_7_14_0_configSchema = (connector?: ESCaseConnectorWithId) => ({ }, }); -describe('7.15.0 connector ID migration', () => { - it('does not create a reference when the connector ID is none', () => { - const configureSavedObject = create_7_14_0_configSchema(getNoneCaseConnector()); +describe('configuration migrations', () => { + describe('7.15.0 connector ID migration', () => { + it('does not create a reference when the connector ID is none', () => { + const configureSavedObject = create_7_14_0_configSchema(getNoneCaseConnector()); - const migratedConnector = configureConnectorIdMigration( - configureSavedObject - ) as SavedObjectSanitizedDoc; + const migratedConnector = configureConnectorIdMigration( + configureSavedObject + ) as SavedObjectSanitizedDoc; - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); - }); + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); + }); - it('does not create a reference when the connector is undefined and defaults it to the none connector', () => { - const configureSavedObject = create_7_14_0_configSchema(); + it('does not create a reference when the connector is undefined and defaults it to the none connector', () => { + const configureSavedObject = create_7_14_0_configSchema(); - const migratedConnector = configureConnectorIdMigration( - configureSavedObject - ) as SavedObjectSanitizedDoc; + const migratedConnector = configureConnectorIdMigration( + configureSavedObject + ) as SavedObjectSanitizedDoc; - expect(migratedConnector.references.length).toBe(0); - expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` - Object { - "fields": null, - "name": "none", - "type": ".none", - } - `); - }); - - it('creates a reference using the connector id', () => { - const configureSavedObject = create_7_14_0_configSchema({ - id: '123', - fields: null, - name: 'connector', - type: ConnectorTypes.jira, + expect(migratedConnector.references.length).toBe(0); + expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` + Object { + "fields": null, + "name": "none", + "type": ".none", + } + `); }); - const migratedConnector = configureConnectorIdMigration( - configureSavedObject - ) as SavedObjectSanitizedDoc; + it('creates a reference using the connector id', () => { + const configureSavedObject = create_7_14_0_configSchema({ + id: '123', + fields: null, + name: 'connector', + type: ConnectorTypes.jira, + }); - expect(migratedConnector.references).toEqual([ - { id: '123', type: ACTION_SAVED_OBJECT_TYPE, name: CONNECTOR_ID_REFERENCE_NAME }, - ]); - expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); - }); + const migratedConnector = configureConnectorIdMigration( + configureSavedObject + ) as SavedObjectSanitizedDoc; - it('returns the other attributes and default connector when the connector is undefined', () => { - const configureSavedObject = create_7_14_0_configSchema(); + expect(migratedConnector.references).toEqual([ + { id: '123', type: ACTION_SAVED_OBJECT_TYPE, name: CONNECTOR_ID_REFERENCE_NAME }, + ]); + expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); + }); - const migratedConnector = configureConnectorIdMigration( - configureSavedObject - ) as SavedObjectSanitizedDoc; + it('returns the other attributes and default connector when the connector is undefined', () => { + const configureSavedObject = create_7_14_0_configSchema(); - expect(migratedConnector).toMatchInlineSnapshot(` - Object { - "attributes": Object { - "closure_type": "close-by-pushing", - "connector": Object { - "fields": null, - "name": "none", - "type": ".none", - }, - "created_at": "2020-04-09T09:43:51.778Z", - "created_by": Object { - "email": "testemail@elastic.co", - "full_name": "elastic", - "username": "elastic", - }, - "owner": "securitySolution", - "updated_at": "2020-04-09T09:43:51.778Z", - "updated_by": Object { - "email": "testemail@elastic.co", - "full_name": "elastic", - "username": "elastic", + const migratedConnector = configureConnectorIdMigration( + configureSavedObject + ) as SavedObjectSanitizedDoc; + + expect(migratedConnector).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "closure_type": "close-by-pushing", + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + "created_at": "2020-04-09T09:43:51.778Z", + "created_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + "owner": "securitySolution", + "updated_at": "2020-04-09T09:43:51.778Z", + "updated_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, }, - }, - "id": "1", - "references": Array [], - "type": "cases-configure", - } - `); + "id": "1", + "references": Array [], + "type": "cases-configure", + } + `); + }); }); }); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.ts index 527d40fca2e35..f9937253e0d2f 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.ts @@ -13,7 +13,8 @@ import { } from '../../../../../../src/core/server'; import { ConnectorTypes } from '../../../common'; import { addOwnerToSO, SanitizedCaseOwner } from '.'; -import { transformConnectorIdToReference } from './utils'; +import { transformConnectorIdToReference } from '../../services/user_actions/transform'; +import { CONNECTOR_ID_REFERENCE_NAME } from '../../common'; interface UnsanitizedConfigureConnector { connector_id: string; @@ -34,8 +35,10 @@ export const configureConnectorIdMigration = ( ): SavedObjectSanitizedDoc => { // removing the id field since it will be stored in the references instead const { connector, ...restAttributes } = doc.attributes; - const { transformedConnector, references: connectorReferences } = - transformConnectorIdToReference(connector); + const { transformedConnector, references: connectorReferences } = transformConnectorIdToReference( + CONNECTOR_ID_REFERENCE_NAME, + connector + ); const { references = [] } = doc; return { diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/index.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/index.ts index a445131073d19..a4f50fbfcde5b 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/index.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/index.ts @@ -5,24 +5,17 @@ * 2.0. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import { SavedObjectUnsanitizedDoc, SavedObjectSanitizedDoc, } from '../../../../../../src/core/server'; -import { ConnectorTypes, SECURITY_SOLUTION_OWNER } from '../../../common'; +import { SECURITY_SOLUTION_OWNER } from '../../../common'; export { caseMigrations } from './cases'; export { configureMigrations } from './configuration'; +export { userActionsMigrations } from './user_actions'; export { createCommentsMigrations, CreateCommentsMigrationsDeps } from './comments'; -interface UserActions { - action_field: string[]; - new_value: string; - old_value: string; -} - export interface SanitizedCaseOwner { owner: string; } @@ -38,52 +31,6 @@ export const addOwnerToSO = >( references: doc.references || [], }); -export const userActionsMigrations = { - '7.10.0': (doc: SavedObjectUnsanitizedDoc): SavedObjectSanitizedDoc => { - const { action_field, new_value, old_value, ...restAttributes } = doc.attributes; - - if ( - action_field == null || - !Array.isArray(action_field) || - action_field[0] !== 'connector_id' - ) { - return { ...doc, references: doc.references || [] }; - } - - return { - ...doc, - attributes: { - ...restAttributes, - action_field: ['connector'], - new_value: - new_value != null - ? JSON.stringify({ - id: new_value, - name: 'none', - type: ConnectorTypes.none, - fields: null, - }) - : new_value, - old_value: - old_value != null - ? JSON.stringify({ - id: old_value, - name: 'none', - type: ConnectorTypes.none, - fields: null, - }) - : old_value, - }, - references: doc.references || [], - }; - }, - '7.14.0': ( - doc: SavedObjectUnsanitizedDoc> - ): SavedObjectSanitizedDoc => { - return addOwnerToSO(doc); - }, -}; - export const connectorMappingsMigrations = { '7.14.0': ( doc: SavedObjectUnsanitizedDoc> diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions.test.ts new file mode 100644 index 0000000000000..e71c8db0db694 --- /dev/null +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions.test.ts @@ -0,0 +1,562 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import { SavedObjectMigrationContext, SavedObjectSanitizedDoc } from 'kibana/server'; +import { migrationMocks } from 'src/core/server/mocks'; +import { CaseUserActionAttributes, CASE_USER_ACTION_SAVED_OBJECT } from '../../../common'; +import { + createConnectorObject, + createExternalService, + createJiraConnector, +} from '../../services/test_utils'; +import { userActionsConnectorIdMigration } from './user_actions'; + +const create_7_14_0_userAction = ( + params: { + action?: string; + action_field?: string[]; + new_value?: string | null | object; + old_value?: string | null | object; + } = {} +) => { + const { new_value, old_value, ...restParams } = params; + + return { + type: CASE_USER_ACTION_SAVED_OBJECT, + id: '1', + attributes: { + ...restParams, + new_value: new_value && typeof new_value === 'object' ? JSON.stringify(new_value) : new_value, + old_value: old_value && typeof old_value === 'object' ? JSON.stringify(old_value) : old_value, + }, + }; +}; + +describe('user action migrations', () => { + describe('7.15.0 connector ID migration', () => { + describe('userActionsConnectorIdMigration', () => { + let context: jest.Mocked; + + beforeEach(() => { + context = migrationMocks.createContext(); + }); + + describe('push user action', () => { + it('extracts the external_service connector_id to references for a new pushed user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'push-to-service', + action_field: ['pushed'], + new_value: createExternalService(), + old_value: null, + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedExternalService = JSON.parse(migratedUserAction.attributes.new_value!); + expect(parsedExternalService).not.toHaveProperty('connector_id'); + expect(parsedExternalService).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + + expect(migratedUserAction.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); + + expect(migratedUserAction.attributes.old_value).toBeNull(); + }); + + it('extract the external_service connector_id to references for new and old pushed user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'push-to-service', + action_field: ['pushed'], + new_value: createExternalService(), + old_value: createExternalService({ connector_id: '5' }), + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedNewExternalService = JSON.parse(migratedUserAction.attributes.new_value!); + const parsedOldExternalService = JSON.parse(migratedUserAction.attributes.old_value!); + + expect(parsedNewExternalService).not.toHaveProperty('connector_id'); + expect(parsedOldExternalService).not.toHaveProperty('connector_id'); + expect(migratedUserAction.references).toEqual([ + { id: '100', name: 'pushConnectorId', type: 'action' }, + { id: '5', name: 'oldPushConnectorId', type: 'action' }, + ]); + }); + + it('preserves the existing references after extracting the external_service connector_id field', () => { + const userAction = { + ...create_7_14_0_userAction({ + action: 'push-to-service', + action_field: ['pushed'], + new_value: createExternalService(), + old_value: createExternalService({ connector_id: '5' }), + }), + references: [{ id: '500', name: 'someReference', type: 'ref' }], + }; + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedNewExternalService = JSON.parse(migratedUserAction.attributes.new_value!); + const parsedOldExternalService = JSON.parse(migratedUserAction.attributes.old_value!); + + expect(parsedNewExternalService).not.toHaveProperty('connector_id'); + expect(parsedOldExternalService).not.toHaveProperty('connector_id'); + expect(migratedUserAction.references).toEqual([ + { id: '500', name: 'someReference', type: 'ref' }, + { id: '100', name: 'pushConnectorId', type: 'action' }, + { id: '5', name: 'oldPushConnectorId', type: 'action' }, + ]); + }); + + it('leaves the object unmodified when it is not a valid push user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'push-to-service', + action_field: ['invalid field'], + new_value: 'hello', + old_value: null, + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + expect(migratedUserAction.attributes.old_value).toBeNull(); + expect(migratedUserAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "push-to-service", + "action_field": Array [ + "invalid field", + ], + "new_value": "hello", + "old_value": null, + }, + "id": "1", + "references": Array [], + "type": "cases-user-actions", + } + `); + }); + + it('leaves the object unmodified when it new value is invalid json', () => { + const userAction = create_7_14_0_userAction({ + action: 'push-to-service', + action_field: ['pushed'], + new_value: '{a', + old_value: null, + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + expect(migratedUserAction.attributes.old_value).toBeNull(); + expect(migratedUserAction.attributes.new_value).toEqual('{a'); + expect(migratedUserAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "push-to-service", + "action_field": Array [ + "pushed", + ], + "new_value": "{a", + "old_value": null, + }, + "id": "1", + "references": Array [], + "type": "cases-user-actions", + } + `); + }); + + it('logs an error new value is invalid json', () => { + const userAction = create_7_14_0_userAction({ + action: 'push-to-service', + action_field: ['pushed'], + new_value: '{a', + old_value: null, + }); + + userActionsConnectorIdMigration(userAction, context); + + expect(context.log.error).toHaveBeenCalled(); + }); + }); + + describe('update connector user action', () => { + it('extracts the connector id to references for a new create connector user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'update', + action_field: ['connector'], + new_value: createJiraConnector(), + old_value: null, + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedConnector = JSON.parse(migratedUserAction.attributes.new_value!); + expect(parsedConnector).not.toHaveProperty('id'); + expect(parsedConnector).toMatchInlineSnapshot(` + Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + } + `); + + expect(migratedUserAction.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + + expect(migratedUserAction.attributes.old_value).toBeNull(); + }); + + it('extracts the connector id to references for a new and old create connector user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'update', + action_field: ['connector'], + new_value: createJiraConnector(), + old_value: { ...createJiraConnector(), id: '5' }, + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedNewConnector = JSON.parse(migratedUserAction.attributes.new_value!); + const parsedOldConnector = JSON.parse(migratedUserAction.attributes.new_value!); + + expect(parsedNewConnector).not.toHaveProperty('id'); + expect(parsedOldConnector).not.toHaveProperty('id'); + + expect(migratedUserAction.references).toEqual([ + { id: '1', name: 'connectorId', type: 'action' }, + { id: '5', name: 'oldConnectorId', type: 'action' }, + ]); + }); + + it('preserves the existing references after extracting the connector.id field', () => { + const userAction = { + ...create_7_14_0_userAction({ + action: 'update', + action_field: ['connector'], + new_value: createJiraConnector(), + old_value: { ...createJiraConnector(), id: '5' }, + }), + references: [{ id: '500', name: 'someReference', type: 'ref' }], + }; + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedNewConnectorId = JSON.parse(migratedUserAction.attributes.new_value!); + const parsedOldConnectorId = JSON.parse(migratedUserAction.attributes.old_value!); + + expect(parsedNewConnectorId).not.toHaveProperty('id'); + expect(parsedOldConnectorId).not.toHaveProperty('id'); + expect(migratedUserAction.references).toEqual([ + { id: '500', name: 'someReference', type: 'ref' }, + { id: '1', name: 'connectorId', type: 'action' }, + { id: '5', name: 'oldConnectorId', type: 'action' }, + ]); + }); + + it('leaves the object unmodified when it is not a valid create connector user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'update', + action_field: ['invalid action'], + new_value: 'new json value', + old_value: 'old value', + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + expect(migratedUserAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "update", + "action_field": Array [ + "invalid action", + ], + "new_value": "new json value", + "old_value": "old value", + }, + "id": "1", + "references": Array [], + "type": "cases-user-actions", + } + `); + }); + + it('leaves the object unmodified when old_value is invalid json', () => { + const userAction = create_7_14_0_userAction({ + action: 'update', + action_field: ['connector'], + new_value: '{}', + old_value: '{b', + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + expect(migratedUserAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "update", + "action_field": Array [ + "connector", + ], + "new_value": "{}", + "old_value": "{b", + }, + "id": "1", + "references": Array [], + "type": "cases-user-actions", + } + `); + }); + + it('logs an error message when old_value is invalid json', () => { + const userAction = create_7_14_0_userAction({ + action: 'update', + action_field: ['connector'], + new_value: createJiraConnector(), + old_value: '{b', + }); + + userActionsConnectorIdMigration(userAction, context); + + expect(context.log.error).toHaveBeenCalled(); + }); + }); + + describe('create connector user action', () => { + it('extracts the connector id to references for a new create connector user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'create', + action_field: ['connector'], + new_value: createConnectorObject(), + old_value: null, + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedConnector = JSON.parse(migratedUserAction.attributes.new_value!); + expect(parsedConnector.connector).not.toHaveProperty('id'); + expect(parsedConnector).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + + expect(migratedUserAction.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + + expect(migratedUserAction.attributes.old_value).toBeNull(); + }); + + it('extracts the connector id to references for a new and old create connector user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'create', + action_field: ['connector'], + new_value: createConnectorObject(), + old_value: createConnectorObject({ id: '5' }), + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedNewConnector = JSON.parse(migratedUserAction.attributes.new_value!); + const parsedOldConnector = JSON.parse(migratedUserAction.attributes.new_value!); + + expect(parsedNewConnector.connector).not.toHaveProperty('id'); + expect(parsedOldConnector.connector).not.toHaveProperty('id'); + + expect(migratedUserAction.references).toEqual([ + { id: '1', name: 'connectorId', type: 'action' }, + { id: '5', name: 'oldConnectorId', type: 'action' }, + ]); + }); + + it('preserves the existing references after extracting the connector.id field', () => { + const userAction = { + ...create_7_14_0_userAction({ + action: 'create', + action_field: ['connector'], + new_value: createConnectorObject(), + old_value: createConnectorObject({ id: '5' }), + }), + references: [{ id: '500', name: 'someReference', type: 'ref' }], + }; + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + const parsedNewConnectorId = JSON.parse(migratedUserAction.attributes.new_value!); + const parsedOldConnectorId = JSON.parse(migratedUserAction.attributes.old_value!); + + expect(parsedNewConnectorId.connector).not.toHaveProperty('id'); + expect(parsedOldConnectorId.connector).not.toHaveProperty('id'); + expect(migratedUserAction.references).toEqual([ + { id: '500', name: 'someReference', type: 'ref' }, + { id: '1', name: 'connectorId', type: 'action' }, + { id: '5', name: 'oldConnectorId', type: 'action' }, + ]); + }); + + it('leaves the object unmodified when it is not a valid create connector user action', () => { + const userAction = create_7_14_0_userAction({ + action: 'create', + action_field: ['invalid action'], + new_value: 'new json value', + old_value: 'old value', + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + expect(migratedUserAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "create", + "action_field": Array [ + "invalid action", + ], + "new_value": "new json value", + "old_value": "old value", + }, + "id": "1", + "references": Array [], + "type": "cases-user-actions", + } + `); + }); + + it('leaves the object unmodified when new_value is invalid json', () => { + const userAction = create_7_14_0_userAction({ + action: 'create', + action_field: ['connector'], + new_value: 'new json value', + old_value: 'old value', + }); + + const migratedUserAction = userActionsConnectorIdMigration( + userAction, + context + ) as SavedObjectSanitizedDoc; + + expect(migratedUserAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "create", + "action_field": Array [ + "connector", + ], + "new_value": "new json value", + "old_value": "old value", + }, + "id": "1", + "references": Array [], + "type": "cases-user-actions", + } + `); + }); + + it('logs an error message when new_value is invalid json', () => { + const userAction = create_7_14_0_userAction({ + action: 'create', + action_field: ['connector'], + new_value: 'new json value', + old_value: 'old value', + }); + + userActionsConnectorIdMigration(userAction, context); + + expect(context.log.error).toHaveBeenCalled(); + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions.ts new file mode 100644 index 0000000000000..ed6b57ef647f9 --- /dev/null +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions.ts @@ -0,0 +1,159 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import { addOwnerToSO, SanitizedCaseOwner } from '.'; +import { + SavedObjectUnsanitizedDoc, + SavedObjectSanitizedDoc, + SavedObjectMigrationContext, + LogMeta, +} from '../../../../../../src/core/server'; +import { ConnectorTypes, isCreateConnector, isPush, isUpdateConnector } from '../../../common'; + +import { extractConnectorIdFromJson } from '../../services/user_actions/transform'; +import { UserActionFieldType } from '../../services/user_actions/types'; + +interface UserActions { + action_field: string[]; + new_value: string; + old_value: string; +} + +interface UserActionUnmigratedConnectorDocument { + action?: string; + action_field?: string[]; + new_value?: string | null; + old_value?: string | null; +} + +interface UserActionLogMeta extends LogMeta { + migrations: { userAction: { id: string } }; +} + +export function userActionsConnectorIdMigration( + doc: SavedObjectUnsanitizedDoc, + context: SavedObjectMigrationContext +): SavedObjectSanitizedDoc { + const originalDocWithReferences = { ...doc, references: doc.references ?? [] }; + + if (!isConnectorUserAction(doc.attributes.action, doc.attributes.action_field)) { + return originalDocWithReferences; + } + + try { + return formatDocumentWithConnectorReferences(doc); + } catch (error) { + logError(doc.id, context, error); + + return originalDocWithReferences; + } +} + +function isConnectorUserAction(action?: string, actionFields?: string[]): boolean { + return ( + isCreateConnector(action, actionFields) || + isUpdateConnector(action, actionFields) || + isPush(action, actionFields) + ); +} + +function formatDocumentWithConnectorReferences( + doc: SavedObjectUnsanitizedDoc +): SavedObjectSanitizedDoc { + const { new_value, old_value, action, action_field, ...restAttributes } = doc.attributes; + const { references = [] } = doc; + + const { transformedActionDetails: transformedNewValue, references: newValueConnectorRefs } = + extractConnectorIdFromJson({ + action, + actionFields: action_field, + actionDetails: new_value, + fieldType: UserActionFieldType.New, + }); + + const { transformedActionDetails: transformedOldValue, references: oldValueConnectorRefs } = + extractConnectorIdFromJson({ + action, + actionFields: action_field, + actionDetails: old_value, + fieldType: UserActionFieldType.Old, + }); + + return { + ...doc, + attributes: { + ...restAttributes, + action, + action_field, + new_value: transformedNewValue, + old_value: transformedOldValue, + }, + references: [...references, ...newValueConnectorRefs, ...oldValueConnectorRefs], + }; +} + +function logError(id: string, context: SavedObjectMigrationContext, error: Error) { + context.log.error( + `Failed to migrate user action connector doc id: ${id} version: ${context.migrationVersion} error: ${error.message}`, + { + migrations: { + userAction: { + id, + }, + }, + } + ); +} + +export const userActionsMigrations = { + '7.10.0': (doc: SavedObjectUnsanitizedDoc): SavedObjectSanitizedDoc => { + const { action_field, new_value, old_value, ...restAttributes } = doc.attributes; + + if ( + action_field == null || + !Array.isArray(action_field) || + action_field[0] !== 'connector_id' + ) { + return { ...doc, references: doc.references || [] }; + } + + return { + ...doc, + attributes: { + ...restAttributes, + action_field: ['connector'], + new_value: + new_value != null + ? JSON.stringify({ + id: new_value, + name: 'none', + type: ConnectorTypes.none, + fields: null, + }) + : new_value, + old_value: + old_value != null + ? JSON.stringify({ + id: old_value, + name: 'none', + type: ConnectorTypes.none, + fields: null, + }) + : old_value, + }, + references: doc.references || [], + }; + }, + '7.14.0': ( + doc: SavedObjectUnsanitizedDoc> + ): SavedObjectSanitizedDoc => { + return addOwnerToSO(doc); + }, + '7.16.0': userActionsConnectorIdMigration, +}; diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/utils.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/utils.test.ts deleted file mode 100644 index f591bef6b3236..0000000000000 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/utils.test.ts +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { noneConnectorId } from '../../../common'; -import { createExternalService, createJiraConnector } from '../../services/test_utils'; -import { transformConnectorIdToReference, transformPushConnectorIdToReference } from './utils'; - -describe('migration utils', () => { - describe('transformConnectorIdToReference', () => { - it('returns the default none connector when the connector is undefined', () => { - expect(transformConnectorIdToReference().transformedConnector).toMatchInlineSnapshot(` - Object { - "connector": Object { - "fields": null, - "name": "none", - "type": ".none", - }, - } - `); - }); - - it('returns the default none connector when the id is undefined', () => { - expect(transformConnectorIdToReference({ id: undefined }).transformedConnector) - .toMatchInlineSnapshot(` - Object { - "connector": Object { - "fields": null, - "name": "none", - "type": ".none", - }, - } - `); - }); - - it('returns the default none connector when the id is none', () => { - expect(transformConnectorIdToReference({ id: noneConnectorId }).transformedConnector) - .toMatchInlineSnapshot(` - Object { - "connector": Object { - "fields": null, - "name": "none", - "type": ".none", - }, - } - `); - }); - - it('returns the default none connector when the id is none and other fields are defined', () => { - expect( - transformConnectorIdToReference({ ...createJiraConnector(), id: noneConnectorId }) - .transformedConnector - ).toMatchInlineSnapshot(` - Object { - "connector": Object { - "fields": null, - "name": "none", - "type": ".none", - }, - } - `); - }); - - it('returns an empty array of references when the connector is undefined', () => { - expect(transformConnectorIdToReference().references.length).toBe(0); - }); - - it('returns an empty array of references when the id is undefined', () => { - expect(transformConnectorIdToReference({ id: undefined }).references.length).toBe(0); - }); - - it('returns an empty array of references when the id is the none connector', () => { - expect(transformConnectorIdToReference({ id: noneConnectorId }).references.length).toBe(0); - }); - - it('returns an empty array of references when the id is the none connector and other fields are defined', () => { - expect( - transformConnectorIdToReference({ ...createJiraConnector(), id: noneConnectorId }) - .references.length - ).toBe(0); - }); - - it('returns a jira connector', () => { - const transformedFields = transformConnectorIdToReference(createJiraConnector()); - expect(transformedFields.transformedConnector).toMatchInlineSnapshot(` - Object { - "connector": Object { - "fields": Object { - "issueType": "bug", - "parent": "2", - "priority": "high", - }, - "name": ".jira", - "type": ".jira", - }, - } - `); - expect(transformedFields.references).toMatchInlineSnapshot(` - Array [ - Object { - "id": "1", - "name": "connectorId", - "type": "action", - }, - ] - `); - }); - }); - - describe('transformPushConnectorIdToReference', () => { - it('sets external_service to null when it is undefined', () => { - expect(transformPushConnectorIdToReference().transformedPushConnector).toMatchInlineSnapshot(` - Object { - "external_service": null, - } - `); - }); - - it('sets external_service to null when it is null', () => { - expect(transformPushConnectorIdToReference(null).transformedPushConnector) - .toMatchInlineSnapshot(` - Object { - "external_service": null, - } - `); - }); - - it('returns an object when external_service is defined but connector_id is undefined', () => { - expect( - transformPushConnectorIdToReference({ connector_id: undefined }).transformedPushConnector - ).toMatchInlineSnapshot(` - Object { - "external_service": Object {}, - } - `); - }); - - it('returns an object when external_service is defined but connector_id is null', () => { - expect(transformPushConnectorIdToReference({ connector_id: null }).transformedPushConnector) - .toMatchInlineSnapshot(` - Object { - "external_service": Object {}, - } - `); - }); - - it('returns an object when external_service is defined but connector_id is none', () => { - const otherFields = { otherField: 'hi' }; - - expect( - transformPushConnectorIdToReference({ ...otherFields, connector_id: noneConnectorId }) - .transformedPushConnector - ).toMatchInlineSnapshot(` - Object { - "external_service": Object { - "otherField": "hi", - }, - } - `); - }); - - it('returns an empty array of references when the external_service is undefined', () => { - expect(transformPushConnectorIdToReference().references.length).toBe(0); - }); - - it('returns an empty array of references when the external_service is null', () => { - expect(transformPushConnectorIdToReference(null).references.length).toBe(0); - }); - - it('returns an empty array of references when the connector_id is undefined', () => { - expect( - transformPushConnectorIdToReference({ connector_id: undefined }).references.length - ).toBe(0); - }); - - it('returns an empty array of references when the connector_id is null', () => { - expect( - transformPushConnectorIdToReference({ connector_id: undefined }).references.length - ).toBe(0); - }); - - it('returns an empty array of references when the connector_id is the none connector', () => { - expect( - transformPushConnectorIdToReference({ connector_id: noneConnectorId }).references.length - ).toBe(0); - }); - - it('returns an empty array of references when the connector_id is the none connector and other fields are defined', () => { - expect( - transformPushConnectorIdToReference({ - ...createExternalService(), - connector_id: noneConnectorId, - }).references.length - ).toBe(0); - }); - - it('returns the external_service connector', () => { - const transformedFields = transformPushConnectorIdToReference(createExternalService()); - expect(transformedFields.transformedPushConnector).toMatchInlineSnapshot(` - Object { - "external_service": Object { - "connector_name": ".jira", - "external_id": "100", - "external_title": "awesome", - "external_url": "http://www.google.com", - "pushed_at": "2019-11-25T21:54:48.952Z", - "pushed_by": Object { - "email": "testemail@elastic.co", - "full_name": "elastic", - "username": "elastic", - }, - }, - } - `); - expect(transformedFields.references).toMatchInlineSnapshot(` - Array [ - Object { - "id": "100", - "name": "pushConnectorId", - "type": "action", - }, - ] - `); - }); - }); -}); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/utils.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/utils.ts deleted file mode 100644 index 0100a04cde679..0000000000000 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/utils.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import { noneConnectorId } from '../../../common'; -import { SavedObjectReference } from '../../../../../../src/core/server'; -import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server'; -import { - getNoneCaseConnector, - CONNECTOR_ID_REFERENCE_NAME, - PUSH_CONNECTOR_ID_REFERENCE_NAME, -} from '../../common'; - -export const transformConnectorIdToReference = (connector?: { - id?: string; -}): { transformedConnector: Record; references: SavedObjectReference[] } => { - const { id: connectorId, ...restConnector } = connector ?? {}; - - const references = createConnectorReference( - connectorId, - ACTION_SAVED_OBJECT_TYPE, - CONNECTOR_ID_REFERENCE_NAME - ); - - const { id: ignoreNoneId, ...restNoneConnector } = getNoneCaseConnector(); - const connectorFieldsToReturn = - connector && references.length > 0 ? restConnector : restNoneConnector; - - return { - transformedConnector: { - connector: connectorFieldsToReturn, - }, - references, - }; -}; - -const createConnectorReference = ( - id: string | null | undefined, - type: string, - name: string -): SavedObjectReference[] => { - return id && id !== noneConnectorId - ? [ - { - id, - type, - name, - }, - ] - : []; -}; - -export const transformPushConnectorIdToReference = ( - external_service?: { connector_id?: string | null } | null -): { transformedPushConnector: Record; references: SavedObjectReference[] } => { - const { connector_id: pushConnectorId, ...restExternalService } = external_service ?? {}; - - const references = createConnectorReference( - pushConnectorId, - ACTION_SAVED_OBJECT_TYPE, - PUSH_CONNECTOR_ID_REFERENCE_NAME - ); - - return { - transformedPushConnector: { external_service: external_service ? restExternalService : null }, - references, - }; -}; diff --git a/x-pack/plugins/cases/server/saved_object_types/user_actions.ts b/x-pack/plugins/cases/server/saved_object_types/user_actions.ts index 883105982bcb3..7ef7c639ed9db 100644 --- a/x-pack/plugins/cases/server/saved_object_types/user_actions.ts +++ b/x-pack/plugins/cases/server/saved_object_types/user_actions.ts @@ -51,5 +51,6 @@ export const caseUserActionSavedObjectType: SavedObjectsType = { migrations: userActionsMigrations, management: { importableAndExportable: true, + visibleInManagement: false, }, }; diff --git a/x-pack/plugins/cases/server/services/cases/index.test.ts b/x-pack/plugins/cases/server/services/cases/index.test.ts index 18f4ff867cfa9..8c71abe5bff4f 100644 --- a/x-pack/plugins/cases/server/services/cases/index.test.ts +++ b/x-pack/plugins/cases/server/services/cases/index.test.ts @@ -40,6 +40,7 @@ import { createSavedObjectReferences, createCaseSavedObjectResponse, basicCaseFields, + createSOFindResponse, } from '../test_utils'; import { ESCaseAttributes } from './types'; @@ -87,13 +88,6 @@ const createFindSO = ( score: 0, }); -const createSOFindResponse = (savedObjects: Array>) => ({ - saved_objects: savedObjects, - total: savedObjects.length, - per_page: savedObjects.length, - page: 1, -}); - const createCaseUpdateParams = ( connector?: CaseConnector, externalService?: CaseFullExternalService diff --git a/x-pack/plugins/cases/server/services/cases/index.ts b/x-pack/plugins/cases/server/services/cases/index.ts index 72c2033f83535..3c76be6d6dd93 100644 --- a/x-pack/plugins/cases/server/services/cases/index.ts +++ b/x-pack/plugins/cases/server/services/cases/index.ts @@ -16,6 +16,7 @@ import { SavedObjectsFindResult, SavedObjectsBulkUpdateResponse, SavedObjectsUpdateResponse, + SavedObjectsResolveResponse, } from 'kibana/server'; import type { estypes } from '@elastic/elasticsearch'; @@ -738,6 +739,27 @@ export class CasesService { throw error; } } + + public async getResolveCase({ + unsecuredSavedObjectsClient, + id: caseId, + }: GetCaseArgs): Promise> { + try { + this.log.debug(`Attempting to resolve case ${caseId}`); + const resolveCaseResult = await unsecuredSavedObjectsClient.resolve( + CASE_SAVED_OBJECT, + caseId + ); + return { + ...resolveCaseResult, + saved_object: transformSavedObjectToExternalModel(resolveCaseResult.saved_object), + }; + } catch (error) { + this.log.error(`Error on resolve case ${caseId}: ${error}`); + throw error; + } + } + public async getSubCase({ unsecuredSavedObjectsClient, id, diff --git a/x-pack/plugins/cases/server/services/mocks.ts b/x-pack/plugins/cases/server/services/mocks.ts index a29d227cfbb0f..1ea9f481d302f 100644 --- a/x-pack/plugins/cases/server/services/mocks.ts +++ b/x-pack/plugins/cases/server/services/mocks.ts @@ -36,6 +36,7 @@ export const createCaseServiceMock = (): CaseServiceMock => { getCases: jest.fn(), getCaseIdsByAlertId: jest.fn(), getMostRecentSubCase: jest.fn(), + getResolveCase: jest.fn(), getSubCase: jest.fn(), getSubCases: jest.fn(), getTags: jest.fn(), diff --git a/x-pack/plugins/cases/server/services/test_utils.ts b/x-pack/plugins/cases/server/services/test_utils.ts index b712ea07f9c71..07743eda61212 100644 --- a/x-pack/plugins/cases/server/services/test_utils.ts +++ b/x-pack/plugins/cases/server/services/test_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SavedObject, SavedObjectReference } from 'kibana/server'; +import { SavedObject, SavedObjectReference, SavedObjectsFindResult } from 'kibana/server'; import { ESConnectorFields } from '.'; import { CONNECTOR_ID_REFERENCE_NAME, PUSH_CONNECTOR_ID_REFERENCE_NAME } from '../common'; import { @@ -54,7 +54,7 @@ export const createESJiraConnector = ( { key: 'parent', value: '2' }, ], type: ConnectorTypes.jira, - ...(overrides && { ...overrides }), + ...overrides, }; }; @@ -94,7 +94,7 @@ export const createExternalService = ( email: 'testemail@elastic.co', username: 'elastic', }, - ...(overrides && { ...overrides }), + ...overrides, }); export const basicCaseFields = { @@ -198,3 +198,14 @@ export const createSavedObjectReferences = ({ ] : []), ]; + +export const createConnectorObject = (overrides?: Partial) => ({ + connector: { ...createJiraConnector(), ...overrides }, +}); + +export const createSOFindResponse = (savedObjects: Array>) => ({ + saved_objects: savedObjects, + total: savedObjects.length, + per_page: savedObjects.length, + page: 1, +}); diff --git a/x-pack/plugins/cases/server/services/user_actions/helpers.test.ts b/x-pack/plugins/cases/server/services/user_actions/helpers.test.ts new file mode 100644 index 0000000000000..7bcbaf58d0f6e --- /dev/null +++ b/x-pack/plugins/cases/server/services/user_actions/helpers.test.ts @@ -0,0 +1,332 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { UserActionField } from '../../../common'; +import { createConnectorObject, createExternalService, createJiraConnector } from '../test_utils'; +import { buildCaseUserActionItem } from './helpers'; + +const defaultFields = () => ({ + actionAt: 'now', + actionBy: { + email: 'a', + full_name: 'j', + username: '1', + }, + caseId: '300', + owner: 'securitySolution', +}); + +describe('user action helpers', () => { + describe('buildCaseUserActionItem', () => { + describe('push user action', () => { + it('extracts the external_service connector_id to references for a new pushed user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'push-to-service', + fields: ['pushed'], + newValue: createExternalService(), + }); + + const parsedExternalService = JSON.parse(userAction.attributes.new_value!); + expect(parsedExternalService).not.toHaveProperty('connector_id'); + expect(parsedExternalService).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + + expect(userAction.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "300", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); + + expect(userAction.attributes.old_value).toBeNull(); + }); + + it('extract the external_service connector_id to references for new and old pushed user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'push-to-service', + fields: ['pushed'], + newValue: createExternalService(), + oldValue: createExternalService({ connector_id: '5' }), + }); + + const parsedNewExternalService = JSON.parse(userAction.attributes.new_value!); + const parsedOldExternalService = JSON.parse(userAction.attributes.old_value!); + + expect(parsedNewExternalService).not.toHaveProperty('connector_id'); + expect(parsedOldExternalService).not.toHaveProperty('connector_id'); + expect(userAction.references).toEqual([ + { id: '300', name: 'associated-cases', type: 'cases' }, + { id: '100', name: 'pushConnectorId', type: 'action' }, + { id: '5', name: 'oldPushConnectorId', type: 'action' }, + ]); + }); + + it('leaves the object unmodified when it is not a valid push user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'push-to-service', + fields: ['invalid field'] as unknown as UserActionField, + newValue: 'hello' as unknown as Record, + }); + + expect(userAction.attributes.old_value).toBeNull(); + expect(userAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "push-to-service", + "action_at": "now", + "action_by": Object { + "email": "a", + "full_name": "j", + "username": "1", + }, + "action_field": Array [ + "invalid field", + ], + "new_value": "hello", + "old_value": null, + "owner": "securitySolution", + }, + "references": Array [ + Object { + "id": "300", + "name": "associated-cases", + "type": "cases", + }, + ], + } + `); + }); + }); + + describe('update connector user action', () => { + it('extracts the connector id to references for a new create connector user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'update', + fields: ['connector'], + newValue: createJiraConnector(), + }); + + const parsedConnector = JSON.parse(userAction.attributes.new_value!); + expect(parsedConnector).not.toHaveProperty('id'); + expect(parsedConnector).toMatchInlineSnapshot(` + Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + } + `); + + expect(userAction.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "300", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + + expect(userAction.attributes.old_value).toBeNull(); + }); + + it('extracts the connector id to references for a new and old create connector user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'update', + fields: ['connector'], + newValue: createJiraConnector(), + oldValue: { ...createJiraConnector(), id: '5' }, + }); + + const parsedNewConnector = JSON.parse(userAction.attributes.new_value!); + const parsedOldConnector = JSON.parse(userAction.attributes.new_value!); + + expect(parsedNewConnector).not.toHaveProperty('id'); + expect(parsedOldConnector).not.toHaveProperty('id'); + + expect(userAction.references).toEqual([ + { id: '300', name: 'associated-cases', type: 'cases' }, + { id: '1', name: 'connectorId', type: 'action' }, + { id: '5', name: 'oldConnectorId', type: 'action' }, + ]); + }); + + it('leaves the object unmodified when it is not a valid create connector user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'update', + fields: ['invalid field'] as unknown as UserActionField, + newValue: 'hello' as unknown as Record, + oldValue: 'old value' as unknown as Record, + }); + + expect(userAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "update", + "action_at": "now", + "action_by": Object { + "email": "a", + "full_name": "j", + "username": "1", + }, + "action_field": Array [ + "invalid field", + ], + "new_value": "hello", + "old_value": "old value", + "owner": "securitySolution", + }, + "references": Array [ + Object { + "id": "300", + "name": "associated-cases", + "type": "cases", + }, + ], + } + `); + }); + }); + + describe('create connector user action', () => { + it('extracts the connector id to references for a new create connector user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'create', + fields: ['connector'], + newValue: createConnectorObject(), + }); + + const parsedConnector = JSON.parse(userAction.attributes.new_value!); + expect(parsedConnector.connector).not.toHaveProperty('id'); + expect(parsedConnector).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + + expect(userAction.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "300", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + + expect(userAction.attributes.old_value).toBeNull(); + }); + + it('extracts the connector id to references for a new and old create connector user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'create', + fields: ['connector'], + newValue: createConnectorObject(), + oldValue: createConnectorObject({ id: '5' }), + }); + + const parsedNewConnector = JSON.parse(userAction.attributes.new_value!); + const parsedOldConnector = JSON.parse(userAction.attributes.new_value!); + + expect(parsedNewConnector.connector).not.toHaveProperty('id'); + expect(parsedOldConnector.connector).not.toHaveProperty('id'); + + expect(userAction.references).toEqual([ + { id: '300', name: 'associated-cases', type: 'cases' }, + { id: '1', name: 'connectorId', type: 'action' }, + { id: '5', name: 'oldConnectorId', type: 'action' }, + ]); + }); + + it('leaves the object unmodified when it is not a valid create connector user action', () => { + const userAction = buildCaseUserActionItem({ + ...defaultFields(), + action: 'create', + fields: ['invalid action'] as unknown as UserActionField, + newValue: 'new json value' as unknown as Record, + oldValue: 'old value' as unknown as Record, + }); + + expect(userAction).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "create", + "action_at": "now", + "action_by": Object { + "email": "a", + "full_name": "j", + "username": "1", + }, + "action_field": Array [ + "invalid action", + ], + "new_value": "new json value", + "old_value": "old value", + "owner": "securitySolution", + }, + "references": Array [ + Object { + "id": "300", + "name": "associated-cases", + "type": "cases", + }, + ], + } + `); + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/server/services/user_actions/helpers.ts b/x-pack/plugins/cases/server/services/user_actions/helpers.ts index 223e731aa8d9b..e91b69f0995bd 100644 --- a/x-pack/plugins/cases/server/services/user_actions/helpers.ts +++ b/x-pack/plugins/cases/server/services/user_actions/helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SavedObject, SavedObjectsUpdateResponse } from 'kibana/server'; +import { SavedObject, SavedObjectReference, SavedObjectsUpdateResponse } from 'kibana/server'; import { get, isPlainObject, isString } from 'lodash'; import deepEqual from 'fast-deep-equal'; @@ -23,8 +23,68 @@ import { } from '../../../common'; import { isTwoArraysDifference } from '../../client/utils'; import { UserActionItem } from '.'; +import { extractConnectorId } from './transform'; +import { UserActionFieldType } from './types'; +import { CASE_REF_NAME, COMMENT_REF_NAME, SUB_CASE_REF_NAME } from '../../common'; -export const transformNewUserAction = ({ +interface BuildCaseUserActionParams { + action: UserAction; + actionAt: string; + actionBy: User; + caseId: string; + owner: string; + fields: UserActionField; + newValue?: Record | string | null; + oldValue?: Record | string | null; + subCaseId?: string; +} + +export const buildCaseUserActionItem = ({ + action, + actionAt, + actionBy, + caseId, + fields, + newValue, + oldValue, + subCaseId, + owner, +}: BuildCaseUserActionParams): UserActionItem => { + const { transformedActionDetails: transformedNewValue, references: newValueReferences } = + extractConnectorId({ + action, + actionFields: fields, + actionDetails: newValue, + fieldType: UserActionFieldType.New, + }); + + const { transformedActionDetails: transformedOldValue, references: oldValueReferences } = + extractConnectorId({ + action, + actionFields: fields, + actionDetails: oldValue, + fieldType: UserActionFieldType.Old, + }); + + return { + attributes: transformNewUserAction({ + actionField: fields, + action, + actionAt, + owner, + ...actionBy, + newValue: transformedNewValue, + oldValue: transformedOldValue, + }), + references: [ + ...createCaseReferences(caseId, subCaseId), + ...newValueReferences, + ...oldValueReferences, + ], + }; +}; + +const transformNewUserAction = ({ actionField, action, actionAt, @@ -55,103 +115,43 @@ export const transformNewUserAction = ({ owner, }); -interface BuildCaseUserAction { - action: UserAction; - actionAt: string; - actionBy: User; - caseId: string; - owner: string; - fields: UserActionField | unknown[]; - newValue?: string | unknown; - oldValue?: string | unknown; - subCaseId?: string; -} +const createCaseReferences = (caseId: string, subCaseId?: string): SavedObjectReference[] => [ + { + type: CASE_SAVED_OBJECT, + name: CASE_REF_NAME, + id: caseId, + }, + ...(subCaseId + ? [ + { + type: SUB_CASE_SAVED_OBJECT, + name: SUB_CASE_REF_NAME, + id: subCaseId, + }, + ] + : []), +]; -interface BuildCommentUserActionItem extends BuildCaseUserAction { +interface BuildCommentUserActionItem extends BuildCaseUserActionParams { commentId: string; } -export const buildCommentUserActionItem = ({ - action, - actionAt, - actionBy, - caseId, - commentId, - fields, - newValue, - oldValue, - subCaseId, - owner, -}: BuildCommentUserActionItem): UserActionItem => ({ - attributes: transformNewUserAction({ - actionField: fields as UserActionField, - action, - actionAt, - owner, - ...actionBy, - newValue: newValue as string, - oldValue: oldValue as string, - }), - references: [ - { - type: CASE_SAVED_OBJECT, - name: `associated-${CASE_SAVED_OBJECT}`, - id: caseId, - }, - { - type: CASE_COMMENT_SAVED_OBJECT, - name: `associated-${CASE_COMMENT_SAVED_OBJECT}`, - id: commentId, - }, - ...(subCaseId - ? [ - { - type: SUB_CASE_SAVED_OBJECT, - id: subCaseId, - name: `associated-${SUB_CASE_SAVED_OBJECT}`, - }, - ] - : []), - ], -}); +export const buildCommentUserActionItem = (params: BuildCommentUserActionItem): UserActionItem => { + const { commentId } = params; + const { attributes, references } = buildCaseUserActionItem(params); -export const buildCaseUserActionItem = ({ - action, - actionAt, - actionBy, - caseId, - fields, - newValue, - oldValue, - subCaseId, - owner, -}: BuildCaseUserAction): UserActionItem => ({ - attributes: transformNewUserAction({ - actionField: fields as UserActionField, - action, - actionAt, - owner, - ...actionBy, - newValue: newValue as string, - oldValue: oldValue as string, - }), - references: [ - { - type: CASE_SAVED_OBJECT, - name: `associated-${CASE_SAVED_OBJECT}`, - id: caseId, - }, - ...(subCaseId - ? [ - { - type: SUB_CASE_SAVED_OBJECT, - name: `associated-${SUB_CASE_SAVED_OBJECT}`, - id: subCaseId, - }, - ] - : []), - ], -}); + return { + attributes, + references: [ + ...references, + { + type: CASE_COMMENT_SAVED_OBJECT, + name: COMMENT_REF_NAME, + id: commentId, + }, + ], + }; +}; const userActionFieldsAllowed: UserActionField = [ 'comment', @@ -278,8 +278,8 @@ const buildGenericCaseUserActions = ({ caseId, subCaseId, fields: [field], - newValue: JSON.stringify(updatedValue), - oldValue: JSON.stringify(origValue), + newValue: updatedValue, + oldValue: origValue, owner: originalItem.attributes.owner, }), ]; diff --git a/x-pack/plugins/cases/server/services/user_actions/index.test.ts b/x-pack/plugins/cases/server/services/user_actions/index.test.ts new file mode 100644 index 0000000000000..c4a350f4ac015 --- /dev/null +++ b/x-pack/plugins/cases/server/services/user_actions/index.test.ts @@ -0,0 +1,557 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObject, SavedObjectsFindResult } from 'kibana/server'; +import { transformFindResponseToExternalModel, UserActionItem } from '.'; +import { + CaseUserActionAttributes, + CASE_USER_ACTION_SAVED_OBJECT, + UserAction, + UserActionField, +} from '../../../common'; + +import { + createConnectorObject, + createExternalService, + createJiraConnector, + createSOFindResponse, +} from '../test_utils'; +import { buildCaseUserActionItem, buildCommentUserActionItem } from './helpers'; + +const createConnectorUserAction = ( + subCaseId?: string, + overrides?: Partial +): SavedObject => { + return { + ...createUserActionSO({ + action: 'create', + fields: ['connector'], + newValue: createConnectorObject(), + subCaseId, + }), + ...(overrides && { ...overrides }), + }; +}; + +const updateConnectorUserAction = ({ + subCaseId, + overrides, + oldValue, +}: { + subCaseId?: string; + overrides?: Partial; + oldValue?: string | null | Record; +} = {}): SavedObject => { + return { + ...createUserActionSO({ + action: 'update', + fields: ['connector'], + newValue: createJiraConnector(), + oldValue, + subCaseId, + }), + ...(overrides && { ...overrides }), + }; +}; + +const pushConnectorUserAction = ({ + subCaseId, + overrides, + oldValue, +}: { + subCaseId?: string; + overrides?: Partial; + oldValue?: string | null | Record; +} = {}): SavedObject => { + return { + ...createUserActionSO({ + action: 'push-to-service', + fields: ['pushed'], + newValue: createExternalService(), + oldValue, + subCaseId, + }), + ...(overrides && { ...overrides }), + }; +}; + +const createUserActionFindSO = ( + userAction: SavedObject +): SavedObjectsFindResult => ({ + ...userAction, + score: 0, +}); + +const createUserActionSO = ({ + action, + fields, + subCaseId, + newValue, + oldValue, + attributesOverrides, + commentId, +}: { + action: UserAction; + fields: UserActionField; + subCaseId?: string; + newValue?: string | null | Record; + oldValue?: string | null | Record; + attributesOverrides?: Partial; + commentId?: string; +}): SavedObject => { + const defaultParams = { + action, + actionAt: 'abc', + actionBy: { + email: 'a', + username: 'b', + full_name: 'abc', + }, + caseId: '1', + subCaseId, + fields, + newValue, + oldValue, + owner: 'securitySolution', + }; + + let userAction: UserActionItem; + + if (commentId) { + userAction = buildCommentUserActionItem({ + commentId, + ...defaultParams, + }); + } else { + userAction = buildCaseUserActionItem(defaultParams); + } + + return { + type: CASE_USER_ACTION_SAVED_OBJECT, + id: '100', + attributes: { + ...userAction.attributes, + ...(attributesOverrides && { ...attributesOverrides }), + }, + references: userAction.references, + }; +}; + +describe('CaseUserActionService', () => { + describe('transformFindResponseToExternalModel', () => { + it('does not populate the ids when the response is an empty array', () => { + expect(transformFindResponseToExternalModel(createSOFindResponse([]))).toMatchInlineSnapshot(` + Object { + "page": 1, + "per_page": 0, + "saved_objects": Array [], + "total": 0, + } + `); + }); + + it('preserves the saved object fields and attributes when inject the ids', () => { + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(createConnectorUserAction())]) + ); + + expect(transformed).toMatchInlineSnapshot(` + Object { + "page": 1, + "per_page": 1, + "saved_objects": Array [ + Object { + "attributes": Object { + "action": "create", + "action_at": "abc", + "action_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "action_field": Array [ + "connector", + ], + "action_id": "100", + "case_id": "1", + "comment_id": null, + "new_val_connector_id": "1", + "new_value": "{\\"connector\\":{\\"name\\":\\".jira\\",\\"type\\":\\".jira\\",\\"fields\\":{\\"issueType\\":\\"bug\\",\\"priority\\":\\"high\\",\\"parent\\":\\"2\\"}}}", + "old_val_connector_id": null, + "old_value": null, + "owner": "securitySolution", + "sub_case_id": "", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, + ], + "total": 1, + } + `); + }); + + it('populates the new_val_connector_id for multiple user actions', () => { + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO(createConnectorUserAction()), + createUserActionFindSO(createConnectorUserAction()), + ]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toEqual('1'); + expect(transformed.saved_objects[1].attributes.new_val_connector_id).toEqual('1'); + }); + + it('populates the old_val_connector_id for multiple user actions', () => { + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO( + createUserActionSO({ + action: 'create', + fields: ['connector'], + oldValue: createConnectorObject(), + }) + ), + createUserActionFindSO( + createUserActionSO({ + action: 'create', + fields: ['connector'], + oldValue: createConnectorObject({ id: '10' }), + }) + ), + ]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toEqual('1'); + expect(transformed.saved_objects[1].attributes.old_val_connector_id).toEqual('10'); + }); + + describe('reference ids', () => { + it('sets case_id to an empty string when it cannot find the reference', () => { + const userAction = { + ...createConnectorUserAction(), + references: [], + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.case_id).toEqual(''); + }); + + it('sets comment_id to null when it cannot find the reference', () => { + const userAction = { + ...createUserActionSO({ action: 'create', fields: ['connector'], commentId: '5' }), + references: [], + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.comment_id).toBeNull(); + }); + + it('sets sub_case_id to an empty string when it cannot find the reference', () => { + const userAction = { + ...createUserActionSO({ action: 'create', fields: ['connector'], subCaseId: '5' }), + references: [], + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.comment_id).toBeNull(); + }); + + it('sets case_id correctly when it finds the reference', () => { + const userAction = createConnectorUserAction(); + + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.case_id).toEqual('1'); + }); + + it('sets comment_id correctly when it finds the reference', () => { + const userAction = createUserActionSO({ + action: 'create', + fields: ['connector'], + commentId: '5', + }); + + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.comment_id).toEqual('5'); + }); + + it('sets sub_case_id correctly when it finds the reference', () => { + const userAction = { + ...createUserActionSO({ action: 'create', fields: ['connector'], subCaseId: '5' }), + }; + + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.sub_case_id).toEqual('5'); + }); + + it('sets action_id correctly to the saved object id', () => { + const userAction = { + ...createUserActionSO({ action: 'create', fields: ['connector'], subCaseId: '5' }), + }; + + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.action_id).toEqual('100'); + }); + }); + + describe('create connector', () => { + it('does not populate the new_val_connector_id when it cannot find the reference', () => { + const userAction = { ...createConnectorUserAction(), references: [] }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toBeNull(); + }); + + it('does not populate the old_val_connector_id when it cannot find the reference', () => { + const userAction = { ...createConnectorUserAction(), references: [] }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toBeNull(); + }); + + it('does not populate the new_val_connector_id when the reference exists but the action and fields are invalid', () => { + const validUserAction = createConnectorUserAction(); + const invalidUserAction = { + ...validUserAction, + attributes: { ...validUserAction.attributes, action: 'invalid' }, + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO(invalidUserAction as SavedObject), + ]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toBeNull(); + }); + + it('does not populate the old_val_connector_id when the reference exists but the action and fields are invalid', () => { + const validUserAction = createUserActionSO({ + action: 'create', + fields: ['connector'], + oldValue: createConnectorObject(), + }); + + const invalidUserAction = { + ...validUserAction, + attributes: { ...validUserAction.attributes, action: 'invalid' }, + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO(invalidUserAction as SavedObject), + ]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toBeNull(); + }); + + it('populates the new_val_connector_id', () => { + const userAction = createConnectorUserAction(); + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toEqual('1'); + }); + + it('populates the old_val_connector_id', () => { + const userAction = createUserActionSO({ + action: 'create', + fields: ['connector'], + oldValue: createConnectorObject(), + }); + + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toEqual('1'); + }); + }); + + describe('update connector', () => { + it('does not populate the new_val_connector_id when it cannot find the reference', () => { + const userAction = { ...updateConnectorUserAction(), references: [] }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toBeNull(); + }); + + it('does not populate the old_val_connector_id when it cannot find the reference', () => { + const userAction = { + ...updateConnectorUserAction({ oldValue: createJiraConnector() }), + references: [], + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toBeNull(); + }); + + it('does not populate the new_val_connector_id when the reference exists but the action and fields are invalid', () => { + const validUserAction = updateConnectorUserAction(); + const invalidUserAction = { + ...validUserAction, + attributes: { ...validUserAction.attributes, action: 'invalid' }, + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO(invalidUserAction as SavedObject), + ]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toBeNull(); + }); + + it('does not populate the old_val_connector_id when the reference exists but the action and fields are invalid', () => { + const validUserAction = updateConnectorUserAction({ oldValue: createJiraConnector() }); + + const invalidUserAction = { + ...validUserAction, + attributes: { ...validUserAction.attributes, action: 'invalid' }, + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO(invalidUserAction as SavedObject), + ]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toBeNull(); + }); + + it('populates the new_val_connector_id', () => { + const userAction = updateConnectorUserAction(); + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toEqual('1'); + }); + + it('populates the old_val_connector_id', () => { + const userAction = updateConnectorUserAction({ oldValue: createJiraConnector() }); + + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toEqual('1'); + }); + }); + + describe('push connector', () => { + it('does not populate the new_val_connector_id when it cannot find the reference', () => { + const userAction = { ...pushConnectorUserAction(), references: [] }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toBeNull(); + }); + + it('does not populate the old_val_connector_id when it cannot find the reference', () => { + const userAction = { + ...pushConnectorUserAction({ oldValue: createExternalService() }), + references: [], + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toBeNull(); + }); + + it('does not populate the new_val_connector_id when the reference exists but the action and fields are invalid', () => { + const validUserAction = pushConnectorUserAction(); + const invalidUserAction = { + ...validUserAction, + attributes: { ...validUserAction.attributes, action: 'invalid' }, + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO(invalidUserAction as SavedObject), + ]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toBeNull(); + }); + + it('does not populate the old_val_connector_id when the reference exists but the action and fields are invalid', () => { + const validUserAction = pushConnectorUserAction({ oldValue: createExternalService() }); + + const invalidUserAction = { + ...validUserAction, + attributes: { ...validUserAction.attributes, action: 'invalid' }, + }; + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([ + createUserActionFindSO(invalidUserAction as SavedObject), + ]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toBeNull(); + }); + + it('populates the new_val_connector_id', () => { + const userAction = pushConnectorUserAction(); + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.new_val_connector_id).toEqual('100'); + }); + + it('populates the old_val_connector_id', () => { + const userAction = pushConnectorUserAction({ oldValue: createExternalService() }); + + const transformed = transformFindResponseToExternalModel( + createSOFindResponse([createUserActionFindSO(userAction)]) + ); + + expect(transformed.saved_objects[0].attributes.old_val_connector_id).toEqual('100'); + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/server/services/user_actions/index.ts b/x-pack/plugins/cases/server/services/user_actions/index.ts index b702448165554..4f158862e3d63 100644 --- a/x-pack/plugins/cases/server/services/user_actions/index.ts +++ b/x-pack/plugins/cases/server/services/user_actions/index.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { Logger, SavedObjectReference } from 'kibana/server'; +import { + Logger, + SavedObjectReference, + SavedObjectsFindResponse, + SavedObjectsFindResult, +} from 'kibana/server'; import { CASE_SAVED_OBJECT, @@ -13,8 +18,17 @@ import { CaseUserActionAttributes, MAX_DOCS_PER_PAGE, SUB_CASE_SAVED_OBJECT, + CaseUserActionResponse, + CASE_COMMENT_SAVED_OBJECT, + isCreateConnector, + isPush, + isUpdateConnector, } from '../../../common'; import { ClientArgs } from '..'; +import { UserActionFieldType } from './types'; +import { CASE_REF_NAME, COMMENT_REF_NAME, SUB_CASE_REF_NAME } from '../../common'; +import { ConnectorIdReferenceName, PushConnectorIdReferenceName } from './transform'; +import { findConnectorIdReference } from '../transform'; interface GetCaseUserActionArgs extends ClientArgs { caseId: string; @@ -33,12 +47,16 @@ interface PostCaseUserActionArgs extends ClientArgs { export class CaseUserActionService { constructor(private readonly log: Logger) {} - public async getAll({ unsecuredSavedObjectsClient, caseId, subCaseId }: GetCaseUserActionArgs) { + public async getAll({ + unsecuredSavedObjectsClient, + caseId, + subCaseId, + }: GetCaseUserActionArgs): Promise> { try { const id = subCaseId ?? caseId; const type = subCaseId ? SUB_CASE_SAVED_OBJECT : CASE_SAVED_OBJECT; - return await unsecuredSavedObjectsClient.find({ + const userActions = await unsecuredSavedObjectsClient.find({ type: CASE_USER_ACTION_SAVED_OBJECT, hasReference: { type, id }, page: 1, @@ -46,17 +64,22 @@ export class CaseUserActionService { sortField: 'action_at', sortOrder: 'asc', }); + + return transformFindResponseToExternalModel(userActions); } catch (error) { this.log.error(`Error on GET case user action case id: ${caseId}: ${error}`); throw error; } } - public async bulkCreate({ unsecuredSavedObjectsClient, actions }: PostCaseUserActionArgs) { + public async bulkCreate({ + unsecuredSavedObjectsClient, + actions, + }: PostCaseUserActionArgs): Promise { try { this.log.debug(`Attempting to POST a new case user action`); - return await unsecuredSavedObjectsClient.bulkCreate( + await unsecuredSavedObjectsClient.bulkCreate( actions.map((action) => ({ type: CASE_USER_ACTION_SAVED_OBJECT, ...action })) ); } catch (error) { @@ -65,3 +88,71 @@ export class CaseUserActionService { } } } + +export function transformFindResponseToExternalModel( + userActions: SavedObjectsFindResponse +): SavedObjectsFindResponse { + return { + ...userActions, + saved_objects: userActions.saved_objects.map((so) => ({ + ...so, + ...transformToExternalModel(so), + })), + }; +} + +function transformToExternalModel( + userAction: SavedObjectsFindResult +): SavedObjectsFindResult { + const { references } = userAction; + + const newValueConnectorId = getConnectorIdFromReferences(UserActionFieldType.New, userAction); + const oldValueConnectorId = getConnectorIdFromReferences(UserActionFieldType.Old, userAction); + + const caseId = findReferenceId(CASE_REF_NAME, CASE_SAVED_OBJECT, references) ?? ''; + const commentId = + findReferenceId(COMMENT_REF_NAME, CASE_COMMENT_SAVED_OBJECT, references) ?? null; + const subCaseId = findReferenceId(SUB_CASE_REF_NAME, SUB_CASE_SAVED_OBJECT, references) ?? ''; + + return { + ...userAction, + attributes: { + ...userAction.attributes, + action_id: userAction.id, + case_id: caseId, + comment_id: commentId, + sub_case_id: subCaseId, + new_val_connector_id: newValueConnectorId, + old_val_connector_id: oldValueConnectorId, + }, + }; +} + +function getConnectorIdFromReferences( + fieldType: UserActionFieldType, + userAction: SavedObjectsFindResult +): string | null { + const { + // eslint-disable-next-line @typescript-eslint/naming-convention + attributes: { action, action_field }, + references, + } = userAction; + + if (isCreateConnector(action, action_field) || isUpdateConnector(action, action_field)) { + return findConnectorIdReference(ConnectorIdReferenceName[fieldType], references)?.id ?? null; + } else if (isPush(action, action_field)) { + return ( + findConnectorIdReference(PushConnectorIdReferenceName[fieldType], references)?.id ?? null + ); + } + + return null; +} + +function findReferenceId( + name: string, + type: string, + references: SavedObjectReference[] +): string | undefined { + return references.find((ref) => ref.name === name && ref.type === type)?.id; +} diff --git a/x-pack/plugins/cases/server/services/user_actions/transform.test.ts b/x-pack/plugins/cases/server/services/user_actions/transform.test.ts new file mode 100644 index 0000000000000..2d28770617094 --- /dev/null +++ b/x-pack/plugins/cases/server/services/user_actions/transform.test.ts @@ -0,0 +1,1246 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { noneConnectorId } from '../../../common'; +import { + CONNECTOR_ID_REFERENCE_NAME, + getNoneCaseConnector, + PUSH_CONNECTOR_ID_REFERENCE_NAME, + USER_ACTION_OLD_ID_REF_NAME, + USER_ACTION_OLD_PUSH_ID_REF_NAME, +} from '../../common'; +import { createConnectorObject, createExternalService, createJiraConnector } from '../test_utils'; +import { + extractConnectorIdHelper, + extractConnectorIdFromJson, + extractConnectorId, + transformConnectorIdToReference, + transformPushConnectorIdToReference, +} from './transform'; +import { UserActionFieldType } from './types'; + +describe('user action transform utils', () => { + describe('transformConnectorIdToReference', () => { + it('returns the default none connector when the connector is undefined', () => { + expect(transformConnectorIdToReference(CONNECTOR_ID_REFERENCE_NAME).transformedConnector) + .toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('returns the default none connector when the id is undefined', () => { + expect( + transformConnectorIdToReference(CONNECTOR_ID_REFERENCE_NAME, { id: undefined }) + .transformedConnector + ).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('returns the default none connector when the id is none', () => { + expect( + transformConnectorIdToReference(CONNECTOR_ID_REFERENCE_NAME, { id: noneConnectorId }) + .transformedConnector + ).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('returns the default none connector when the id is none and other fields are defined', () => { + expect( + transformConnectorIdToReference(CONNECTOR_ID_REFERENCE_NAME, { + ...createJiraConnector(), + id: noneConnectorId, + }).transformedConnector + ).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('returns an empty array of references when the connector is undefined', () => { + expect(transformConnectorIdToReference(CONNECTOR_ID_REFERENCE_NAME).references.length).toBe( + 0 + ); + }); + + it('returns an empty array of references when the id is undefined', () => { + expect( + transformConnectorIdToReference(CONNECTOR_ID_REFERENCE_NAME, { id: undefined }).references + .length + ).toBe(0); + }); + + it('returns an empty array of references when the id is the none connector', () => { + expect( + transformConnectorIdToReference(CONNECTOR_ID_REFERENCE_NAME, { id: noneConnectorId }) + .references.length + ).toBe(0); + }); + + it('returns an empty array of references when the id is the none connector and other fields are defined', () => { + expect( + transformConnectorIdToReference(CONNECTOR_ID_REFERENCE_NAME, { + ...createJiraConnector(), + id: noneConnectorId, + }).references.length + ).toBe(0); + }); + + it('returns a jira connector', () => { + const transformedFields = transformConnectorIdToReference( + CONNECTOR_ID_REFERENCE_NAME, + createJiraConnector() + ); + expect(transformedFields.transformedConnector).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + expect(transformedFields.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); + + it('returns a jira connector with the user action reference name', () => { + const transformedFields = transformConnectorIdToReference( + USER_ACTION_OLD_ID_REF_NAME, + createJiraConnector() + ); + expect(transformedFields.transformedConnector).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + expect(transformedFields.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "oldConnectorId", + "type": "action", + }, + ] + `); + }); + }); + + describe('transformPushConnectorIdToReference', () => { + it('sets external_service to null when it is undefined', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME) + .transformedPushConnector + ).toMatchInlineSnapshot(` + Object { + "external_service": null, + } + `); + }); + + it('sets external_service to null when it is null', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, null) + .transformedPushConnector + ).toMatchInlineSnapshot(` + Object { + "external_service": null, + } + `); + }); + + it('returns an object when external_service is defined but connector_id is undefined', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, { + connector_id: undefined, + }).transformedPushConnector + ).toMatchInlineSnapshot(` + Object { + "external_service": Object {}, + } + `); + }); + + it('returns an object when external_service is defined but connector_id is null', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, { + connector_id: null, + }).transformedPushConnector + ).toMatchInlineSnapshot(` + Object { + "external_service": Object {}, + } + `); + }); + + it('returns an object when external_service is defined but connector_id is none', () => { + const otherFields = { otherField: 'hi' }; + + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, { + ...otherFields, + connector_id: noneConnectorId, + }).transformedPushConnector + ).toMatchInlineSnapshot(` + Object { + "external_service": Object { + "otherField": "hi", + }, + } + `); + }); + + it('returns an empty array of references when the external_service is undefined', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME).references.length + ).toBe(0); + }); + + it('returns an empty array of references when the external_service is null', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, null).references + .length + ).toBe(0); + }); + + it('returns an empty array of references when the connector_id is undefined', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, { + connector_id: undefined, + }).references.length + ).toBe(0); + }); + + it('returns an empty array of references when the connector_id is null', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, { + connector_id: undefined, + }).references.length + ).toBe(0); + }); + + it('returns an empty array of references when the connector_id is the none connector', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, { + connector_id: noneConnectorId, + }).references.length + ).toBe(0); + }); + + it('returns an empty array of references when the connector_id is the none connector and other fields are defined', () => { + expect( + transformPushConnectorIdToReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, { + ...createExternalService(), + connector_id: noneConnectorId, + }).references.length + ).toBe(0); + }); + + it('returns the external_service connector', () => { + const transformedFields = transformPushConnectorIdToReference( + PUSH_CONNECTOR_ID_REFERENCE_NAME, + createExternalService() + ); + expect(transformedFields.transformedPushConnector).toMatchInlineSnapshot(` + Object { + "external_service": Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + } + `); + expect(transformedFields.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); + }); + + it('returns the external_service connector with a user actions reference name', () => { + const transformedFields = transformPushConnectorIdToReference( + USER_ACTION_OLD_PUSH_ID_REF_NAME, + createExternalService() + ); + + expect(transformedFields.references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "oldPushConnectorId", + "type": "action", + }, + ] + `); + }); + }); + + describe('extractConnectorIdHelper', () => { + it('throws an error when action details has a circular reference', () => { + const circularRef = { prop: {} }; + circularRef.prop = circularRef; + + expect(() => { + extractConnectorIdHelper({ + action: 'a', + actionFields: [], + actionDetails: circularRef, + fieldType: UserActionFieldType.New, + }); + }).toThrow(); + }); + + describe('create action', () => { + it('returns no references and untransformed json when actionDetails is not a valid connector', () => { + expect( + extractConnectorIdHelper({ + action: 'create', + actionFields: ['connector'], + actionDetails: { a: 'hello' }, + fieldType: UserActionFieldType.New, + }) + ).toMatchInlineSnapshot(` + Object { + "references": Array [], + "transformedActionDetails": "{\\"a\\":\\"hello\\"}", + } + `); + }); + + it('returns no references and untransformed json when the action is create and action fields does not contain connector', () => { + expect( + extractConnectorIdHelper({ + action: 'create', + actionFields: ['', 'something', 'onnector'], + actionDetails: { a: 'hello' }, + fieldType: UserActionFieldType.New, + }) + ).toMatchInlineSnapshot(` + Object { + "references": Array [], + "transformedActionDetails": "{\\"a\\":\\"hello\\"}", + } + `); + }); + + it('returns the stringified json without the id', () => { + const jiraConnector = createConnectorObject(); + + const { transformedActionDetails } = extractConnectorIdHelper({ + action: 'create', + actionFields: ['connector'], + actionDetails: jiraConnector, + fieldType: UserActionFieldType.New, + }); + + expect(JSON.parse(transformedActionDetails)).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + }); + + it('removes the connector.id when the connector is none', () => { + const connector = { connector: getNoneCaseConnector() }; + + const { transformedActionDetails } = extractConnectorIdHelper({ + action: 'create', + actionFields: ['connector'], + actionDetails: connector, + fieldType: UserActionFieldType.New, + })!; + + const parsedJson = JSON.parse(transformedActionDetails); + + expect(parsedJson.connector).not.toHaveProperty('id'); + expect(parsedJson).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": null, + "name": "none", + "type": ".none", + }, + } + `); + }); + + it('does not return a reference when the connector is none', () => { + const connector = { connector: getNoneCaseConnector() }; + + const { references } = extractConnectorIdHelper({ + action: 'create', + actionFields: ['connector'], + actionDetails: connector, + fieldType: UserActionFieldType.New, + })!; + + expect(references).toEqual([]); + }); + + it('returns a reference to the connector.id', () => { + const connector = createConnectorObject(); + + const { references } = extractConnectorIdHelper({ + action: 'create', + actionFields: ['connector'], + actionDetails: connector, + fieldType: UserActionFieldType.New, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); + + it('returns an old reference name to the connector.id', () => { + const connector = createConnectorObject(); + + const { references } = extractConnectorIdHelper({ + action: 'create', + actionFields: ['connector'], + actionDetails: connector, + fieldType: UserActionFieldType.Old, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "oldConnectorId", + "type": "action", + }, + ] + `); + }); + + it('returns the transformed connector and the description', () => { + const details = { ...createConnectorObject(), description: 'a description' }; + + const { transformedActionDetails } = extractConnectorIdHelper({ + action: 'create', + actionFields: ['connector'], + actionDetails: details, + fieldType: UserActionFieldType.Old, + })!; + + const parsedJson = JSON.parse(transformedActionDetails); + + expect(parsedJson).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + "description": "a description", + } + `); + }); + }); + + describe('update action', () => { + it('returns no references and untransformed json when actionDetails is not a valid connector', () => { + expect( + extractConnectorIdHelper({ + action: 'update', + actionFields: ['connector'], + actionDetails: { a: 'hello' }, + fieldType: UserActionFieldType.New, + }) + ).toMatchInlineSnapshot(` + Object { + "references": Array [], + "transformedActionDetails": "{\\"a\\":\\"hello\\"}", + } + `); + }); + + it('returns no references and untransformed json when the action is update and action fields does not contain connector', () => { + expect( + extractConnectorIdHelper({ + action: 'update', + actionFields: ['', 'something', 'onnector'], + actionDetails: 5, + fieldType: UserActionFieldType.New, + }) + ).toMatchInlineSnapshot(` + Object { + "references": Array [], + "transformedActionDetails": "5", + } + `); + }); + + it('returns the stringified json without the id', () => { + const jiraConnector = createJiraConnector(); + + const { transformedActionDetails } = extractConnectorIdHelper({ + action: 'update', + actionFields: ['connector'], + actionDetails: jiraConnector, + fieldType: UserActionFieldType.New, + }); + + const transformedConnetor = JSON.parse(transformedActionDetails!); + expect(transformedConnetor).not.toHaveProperty('id'); + expect(transformedConnetor).toMatchInlineSnapshot(` + Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + } + `); + }); + + it('returns the stringified json without the id when the connector is none', () => { + const connector = getNoneCaseConnector(); + + const { transformedActionDetails } = extractConnectorIdHelper({ + action: 'update', + actionFields: ['connector'], + actionDetails: connector, + fieldType: UserActionFieldType.New, + }); + + const transformedConnetor = JSON.parse(transformedActionDetails); + expect(transformedConnetor).not.toHaveProperty('id'); + expect(transformedConnetor).toMatchInlineSnapshot(` + Object { + "fields": null, + "name": "none", + "type": ".none", + } + `); + }); + + it('returns a reference to the connector.id', () => { + const jiraConnector = createJiraConnector(); + + const { references } = extractConnectorIdHelper({ + action: 'update', + actionFields: ['connector'], + actionDetails: jiraConnector, + fieldType: UserActionFieldType.New, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); + + it('does not return a reference when the connector is none', () => { + const connector = getNoneCaseConnector(); + + const { references } = extractConnectorIdHelper({ + action: 'update', + actionFields: ['connector'], + actionDetails: connector, + fieldType: UserActionFieldType.New, + })!; + + expect(references).toEqual([]); + }); + + it('returns an old reference name to the connector.id', () => { + const jiraConnector = createJiraConnector(); + + const { references } = extractConnectorIdHelper({ + action: 'update', + actionFields: ['connector'], + actionDetails: jiraConnector, + fieldType: UserActionFieldType.Old, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "oldConnectorId", + "type": "action", + }, + ] + `); + }); + }); + + describe('push action', () => { + it('returns no references and untransformed json when actionDetails is not a valid external_service', () => { + expect( + extractConnectorIdHelper({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: { a: 'hello' }, + fieldType: UserActionFieldType.New, + }) + ).toMatchInlineSnapshot(` + Object { + "references": Array [], + "transformedActionDetails": "{\\"a\\":\\"hello\\"}", + } + `); + }); + + it('returns no references and untransformed json when the action is push-to-service and action fields does not contain pushed', () => { + expect( + extractConnectorIdHelper({ + action: 'push-to-service', + actionFields: ['', 'something', 'ushed'], + actionDetails: { a: 'hello' }, + fieldType: UserActionFieldType.New, + }) + ).toMatchInlineSnapshot(` + Object { + "references": Array [], + "transformedActionDetails": "{\\"a\\":\\"hello\\"}", + } + `); + }); + + it('returns the stringified json without the connector_id', () => { + const externalService = createExternalService(); + + const { transformedActionDetails } = extractConnectorIdHelper({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: externalService, + fieldType: UserActionFieldType.New, + }); + + const transformedExternalService = JSON.parse(transformedActionDetails); + expect(transformedExternalService).not.toHaveProperty('connector_id'); + expect(transformedExternalService).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + }); + + it('returns a reference to the connector_id', () => { + const externalService = createExternalService(); + + const { references } = extractConnectorIdHelper({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: externalService, + fieldType: UserActionFieldType.New, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); + }); + + it('returns an old reference name to the connector_id', () => { + const externalService = createExternalService(); + + const { references } = extractConnectorIdHelper({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: externalService, + fieldType: UserActionFieldType.Old, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "oldPushConnectorId", + "type": "action", + }, + ] + `); + }); + }); + }); + + describe('extractConnectorId', () => { + it('returns null when the action details has a circular reference', () => { + const circularRef = { prop: {} }; + circularRef.prop = circularRef; + + const { transformedActionDetails, references } = extractConnectorId({ + action: 'a', + actionFields: ['a'], + actionDetails: circularRef, + fieldType: UserActionFieldType.New, + }); + + expect(transformedActionDetails).toBeNull(); + expect(references).toEqual([]); + }); + + describe('fails to extract the id', () => { + it('returns a null transformed action details when it is initially null', () => { + const { transformedActionDetails, references } = extractConnectorId({ + action: 'a', + actionFields: ['a'], + actionDetails: null, + fieldType: UserActionFieldType.New, + }); + + expect(transformedActionDetails).toBeNull(); + expect(references).toEqual([]); + }); + + it('returns an undefined transformed action details when it is initially undefined', () => { + const { transformedActionDetails, references } = extractConnectorId({ + action: 'a', + actionFields: ['a'], + actionDetails: undefined, + fieldType: UserActionFieldType.New, + }); + + expect(transformedActionDetails).toBeUndefined(); + expect(references).toEqual([]); + }); + + it('returns a json encoded string and empty references when the action is not a valid connector', () => { + const { transformedActionDetails, references } = extractConnectorId({ + action: 'a', + actionFields: ['a'], + actionDetails: { a: 'hello' }, + fieldType: UserActionFieldType.New, + }); + + expect(JSON.parse(transformedActionDetails!)).toEqual({ a: 'hello' }); + expect(references).toEqual([]); + }); + + it('returns a json encoded string and empty references when the action details is an invalid object', () => { + const { transformedActionDetails, references } = extractConnectorId({ + action: 'a', + actionFields: ['a'], + actionDetails: 5 as unknown as Record, + fieldType: UserActionFieldType.New, + }); + + expect(transformedActionDetails!).toEqual('5'); + expect(references).toEqual([]); + }); + }); + + describe('create', () => { + it('extracts the connector.id from a new create jira connector to the references', () => { + const { transformedActionDetails, references } = extractConnectorId({ + action: 'create', + actionFields: ['connector'], + actionDetails: createConnectorObject(), + fieldType: UserActionFieldType.New, + }); + + const parsedJson = JSON.parse(transformedActionDetails!); + + expect(parsedJson).not.toHaveProperty('id'); + expect(parsedJson).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); + + it('extracts the connector.id from an old create jira connector to the references', () => { + const { transformedActionDetails, references } = extractConnectorId({ + action: 'create', + actionFields: ['connector'], + actionDetails: createConnectorObject(), + fieldType: UserActionFieldType.Old, + }); + + const parsedJson = JSON.parse(transformedActionDetails!); + + expect(parsedJson).not.toHaveProperty('id'); + expect(parsedJson).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "oldConnectorId", + "type": "action", + }, + ] + `); + }); + }); + + describe('update', () => { + it('extracts the connector.id from a new create jira connector to the references', () => { + const { transformedActionDetails, references } = extractConnectorId({ + action: 'update', + actionFields: ['connector'], + actionDetails: createJiraConnector(), + fieldType: UserActionFieldType.New, + }); + + const parsedJson = JSON.parse(transformedActionDetails!); + + expect(parsedJson).not.toHaveProperty('id'); + expect(parsedJson).toMatchInlineSnapshot(` + Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + } + `); + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); + + it('extracts the connector.id from an old create jira connector to the references', () => { + const { transformedActionDetails, references } = extractConnectorId({ + action: 'update', + actionFields: ['connector'], + actionDetails: createJiraConnector(), + fieldType: UserActionFieldType.Old, + }); + + const parsedJson = JSON.parse(transformedActionDetails!); + + expect(parsedJson).not.toHaveProperty('id'); + expect(parsedJson).toMatchInlineSnapshot(` + Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + } + `); + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "oldConnectorId", + "type": "action", + }, + ] + `); + }); + }); + + describe('push action', () => { + it('returns the stringified json without the connector_id', () => { + const externalService = createExternalService(); + + const { transformedActionDetails } = extractConnectorId({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: externalService, + fieldType: UserActionFieldType.New, + }); + + const transformedExternalService = JSON.parse(transformedActionDetails!); + expect(transformedExternalService).not.toHaveProperty('connector_id'); + expect(transformedExternalService).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + }); + + it('returns a reference to the connector_id', () => { + const externalService = createExternalService(); + + const { references } = extractConnectorId({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: externalService, + fieldType: UserActionFieldType.New, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); + }); + + it('returns a reference to the old action details connector_id', () => { + const externalService = createExternalService(); + + const { references } = extractConnectorId({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: externalService, + fieldType: UserActionFieldType.Old, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "oldPushConnectorId", + "type": "action", + }, + ] + `); + }); + }); + }); + + describe('extractConnectorIdFromJson', () => { + describe('fails to extract the id', () => { + it('returns no references and null transformed json when action is undefined', () => { + expect( + extractConnectorIdFromJson({ + actionFields: [], + actionDetails: undefined, + fieldType: UserActionFieldType.New, + }) + ).toEqual({ + transformedActionDetails: undefined, + references: [], + }); + }); + + it('returns no references and undefined transformed json when actionFields is undefined', () => { + expect( + extractConnectorIdFromJson({ action: 'a', fieldType: UserActionFieldType.New }) + ).toEqual({ + transformedActionDetails: undefined, + references: [], + }); + }); + + it('returns no references and undefined transformed json when actionDetails is undefined', () => { + expect( + extractConnectorIdFromJson({ + action: 'a', + actionFields: [], + fieldType: UserActionFieldType.New, + }) + ).toEqual({ + transformedActionDetails: undefined, + references: [], + }); + }); + + it('returns no references and undefined transformed json when actionDetails is null', () => { + expect( + extractConnectorIdFromJson({ + action: 'a', + actionFields: [], + actionDetails: null, + fieldType: UserActionFieldType.New, + }) + ).toEqual({ + transformedActionDetails: null, + references: [], + }); + }); + + it('throws an error when actionDetails is invalid json', () => { + expect(() => + extractConnectorIdFromJson({ + action: 'a', + actionFields: [], + actionDetails: '{a', + fieldType: UserActionFieldType.New, + }) + ).toThrow(); + }); + }); + + describe('create action', () => { + it('returns the stringified json without the id', () => { + const jiraConnector = createConnectorObject(); + + const { transformedActionDetails } = extractConnectorIdFromJson({ + action: 'create', + actionFields: ['connector'], + actionDetails: JSON.stringify(jiraConnector), + fieldType: UserActionFieldType.New, + }); + + expect(JSON.parse(transformedActionDetails!)).toMatchInlineSnapshot(` + Object { + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + }, + } + `); + }); + + it('returns a reference to the connector.id', () => { + const jiraConnector = createConnectorObject(); + + const { references } = extractConnectorIdFromJson({ + action: 'create', + actionFields: ['connector'], + actionDetails: JSON.stringify(jiraConnector), + fieldType: UserActionFieldType.New, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); + }); + + describe('update action', () => { + it('returns the stringified json without the id', () => { + const jiraConnector = createJiraConnector(); + + const { transformedActionDetails } = extractConnectorIdFromJson({ + action: 'update', + actionFields: ['connector'], + actionDetails: JSON.stringify(jiraConnector), + fieldType: UserActionFieldType.New, + }); + + const transformedConnetor = JSON.parse(transformedActionDetails!); + expect(transformedConnetor).not.toHaveProperty('id'); + expect(transformedConnetor).toMatchInlineSnapshot(` + Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "name": ".jira", + "type": ".jira", + } + `); + }); + + it('returns a reference to the connector.id', () => { + const jiraConnector = createJiraConnector(); + + const { references } = extractConnectorIdFromJson({ + action: 'update', + actionFields: ['connector'], + actionDetails: JSON.stringify(jiraConnector), + fieldType: UserActionFieldType.New, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ] + `); + }); + }); + + describe('push action', () => { + it('returns the stringified json without the connector_id', () => { + const externalService = createExternalService(); + + const { transformedActionDetails } = extractConnectorIdFromJson({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: JSON.stringify(externalService), + fieldType: UserActionFieldType.New, + }); + + const transformedExternalService = JSON.parse(transformedActionDetails!); + expect(transformedExternalService).not.toHaveProperty('connector_id'); + expect(transformedExternalService).toMatchInlineSnapshot(` + Object { + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + } + `); + }); + + it('returns a reference to the connector_id', () => { + const externalService = createExternalService(); + + const { references } = extractConnectorIdFromJson({ + action: 'push-to-service', + actionFields: ['pushed'], + actionDetails: JSON.stringify(externalService), + fieldType: UserActionFieldType.New, + })!; + + expect(references).toMatchInlineSnapshot(` + Array [ + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ] + `); + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/server/services/user_actions/transform.ts b/x-pack/plugins/cases/server/services/user_actions/transform.ts new file mode 100644 index 0000000000000..93595374208a3 --- /dev/null +++ b/x-pack/plugins/cases/server/services/user_actions/transform.ts @@ -0,0 +1,320 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as rt from 'io-ts'; +import { isString } from 'lodash'; + +import { SavedObjectReference } from '../../../../../../src/core/server'; +import { + CaseAttributes, + CaseConnector, + CaseConnectorRt, + CaseExternalServiceBasicRt, + isCreateConnector, + isPush, + isUpdateConnector, + noneConnectorId, +} from '../../../common'; +import { + CONNECTOR_ID_REFERENCE_NAME, + getNoneCaseConnector, + PUSH_CONNECTOR_ID_REFERENCE_NAME, + USER_ACTION_OLD_ID_REF_NAME, + USER_ACTION_OLD_PUSH_ID_REF_NAME, +} from '../../common'; +import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server'; +import { UserActionFieldType } from './types'; + +/** + * Extracts the connector id from a json encoded string and formats it as a saved object reference. This will remove + * the field it extracted the connector id from. + */ +export function extractConnectorIdFromJson({ + action, + actionFields, + actionDetails, + fieldType, +}: { + action?: string; + actionFields?: string[]; + actionDetails?: string | null; + fieldType: UserActionFieldType; +}): { transformedActionDetails?: string | null; references: SavedObjectReference[] } { + if (!action || !actionFields || !actionDetails) { + return { transformedActionDetails: actionDetails, references: [] }; + } + + const decodedJson = JSON.parse(actionDetails); + + return extractConnectorIdHelper({ + action, + actionFields, + actionDetails: decodedJson, + fieldType, + }); +} + +/** + * Extracts the connector id from an unencoded object and formats it as a saved object reference. + * This will remove the field it extracted the connector id from. + */ +export function extractConnectorId({ + action, + actionFields, + actionDetails, + fieldType, +}: { + action: string; + actionFields: string[]; + actionDetails?: Record | string | null; + fieldType: UserActionFieldType; +}): { + transformedActionDetails?: string | null; + references: SavedObjectReference[]; +} { + if (!actionDetails || isString(actionDetails)) { + // the action was null, undefined, or a regular string so just return it unmodified and not encoded + return { transformedActionDetails: actionDetails, references: [] }; + } + + try { + return extractConnectorIdHelper({ + action, + actionFields, + actionDetails, + fieldType, + }); + } catch (error) { + return { transformedActionDetails: encodeActionDetails(actionDetails), references: [] }; + } +} + +function encodeActionDetails(actionDetails: Record): string | null { + try { + return JSON.stringify(actionDetails); + } catch (error) { + return null; + } +} + +/** + * Internal helper function for extracting the connector id. This is only exported for usage in unit tests. + * This function handles encoding the transformed fields as a json string + */ +export function extractConnectorIdHelper({ + action, + actionFields, + actionDetails, + fieldType, +}: { + action: string; + actionFields: string[]; + actionDetails: unknown; + fieldType: UserActionFieldType; +}): { transformedActionDetails: string; references: SavedObjectReference[] } { + let transformedActionDetails: unknown = actionDetails; + let referencesToReturn: SavedObjectReference[] = []; + + try { + if (isCreateCaseConnector(action, actionFields, actionDetails)) { + const { transformedActionDetails: transformedConnectorPortion, references } = + transformConnectorFromCreateAndUpdateAction(actionDetails.connector, fieldType); + + // the above call only transforms the connector portion of the action details so let's add back + // the rest of the details and we'll overwrite the connector portion when the transformed one + transformedActionDetails = { + ...actionDetails, + ...transformedConnectorPortion, + }; + referencesToReturn = references; + } else if (isUpdateCaseConnector(action, actionFields, actionDetails)) { + const { + transformedActionDetails: { connector: transformedConnector }, + references, + } = transformConnectorFromCreateAndUpdateAction(actionDetails, fieldType); + + transformedActionDetails = transformedConnector; + referencesToReturn = references; + } else if (isPushConnector(action, actionFields, actionDetails)) { + ({ transformedActionDetails, references: referencesToReturn } = + transformConnectorFromPushAction(actionDetails, fieldType)); + } + } catch (error) { + // ignore any errors, we'll just return whatever was passed in for action details in that case + } + + return { + transformedActionDetails: JSON.stringify(transformedActionDetails), + references: referencesToReturn, + }; +} + +function isCreateCaseConnector( + action: string, + actionFields: string[], + actionDetails: unknown +): actionDetails is { connector: CaseConnector } { + try { + const unsafeCase = actionDetails as CaseAttributes; + + return ( + isCreateConnector(action, actionFields) && + unsafeCase.connector !== undefined && + CaseConnectorRt.is(unsafeCase.connector) + ); + } catch { + return false; + } +} + +export const ConnectorIdReferenceName: Record = { + [UserActionFieldType.New]: CONNECTOR_ID_REFERENCE_NAME, + [UserActionFieldType.Old]: USER_ACTION_OLD_ID_REF_NAME, +}; + +function transformConnectorFromCreateAndUpdateAction( + connector: CaseConnector, + fieldType: UserActionFieldType +): { + transformedActionDetails: { connector: unknown }; + references: SavedObjectReference[]; +} { + const { transformedConnector, references } = transformConnectorIdToReference( + ConnectorIdReferenceName[fieldType], + connector + ); + + return { + transformedActionDetails: transformedConnector, + references, + }; +} + +type ConnectorIdRefNameType = + | typeof CONNECTOR_ID_REFERENCE_NAME + | typeof USER_ACTION_OLD_ID_REF_NAME; + +export const transformConnectorIdToReference = ( + referenceName: ConnectorIdRefNameType, + connector?: { + id?: string; + } +): { + transformedConnector: { connector: unknown }; + references: SavedObjectReference[]; +} => { + const { id: connectorId, ...restConnector } = connector ?? {}; + + const references = createConnectorReference(connectorId, ACTION_SAVED_OBJECT_TYPE, referenceName); + + const { id: ignoreNoneId, ...restNoneConnector } = getNoneCaseConnector(); + const connectorFieldsToReturn = + connector && isConnectorIdValid(connectorId) ? restConnector : restNoneConnector; + + return { + transformedConnector: { + connector: connectorFieldsToReturn, + }, + references, + }; +}; + +const createConnectorReference = ( + id: string | null | undefined, + type: string, + name: string +): SavedObjectReference[] => { + return isConnectorIdValid(id) + ? [ + { + id, + type, + name, + }, + ] + : []; +}; + +const isConnectorIdValid = (id: string | null | undefined): id is string => + id != null && id !== noneConnectorId; + +function isUpdateCaseConnector( + action: string, + actionFields: string[], + actionDetails: unknown +): actionDetails is CaseConnector { + try { + return isUpdateConnector(action, actionFields) && CaseConnectorRt.is(actionDetails); + } catch { + return false; + } +} + +type CaseExternalService = rt.TypeOf; + +function isPushConnector( + action: string, + actionFields: string[], + actionDetails: unknown +): actionDetails is CaseExternalService { + try { + return isPush(action, actionFields) && CaseExternalServiceBasicRt.is(actionDetails); + } catch { + return false; + } +} + +export const PushConnectorIdReferenceName: Record = + { + [UserActionFieldType.New]: PUSH_CONNECTOR_ID_REFERENCE_NAME, + [UserActionFieldType.Old]: USER_ACTION_OLD_PUSH_ID_REF_NAME, + }; + +function transformConnectorFromPushAction( + externalService: CaseExternalService, + fieldType: UserActionFieldType +): { + transformedActionDetails: {} | null; + references: SavedObjectReference[]; +} { + const { transformedPushConnector, references } = transformPushConnectorIdToReference( + PushConnectorIdReferenceName[fieldType], + externalService + ); + + return { + transformedActionDetails: transformedPushConnector.external_service, + references, + }; +} + +type PushConnectorIdRefNameType = + | typeof PUSH_CONNECTOR_ID_REFERENCE_NAME + | typeof USER_ACTION_OLD_PUSH_ID_REF_NAME; + +export const transformPushConnectorIdToReference = ( + referenceName: PushConnectorIdRefNameType, + external_service?: { connector_id?: string | null } | null +): { + transformedPushConnector: { external_service: {} | null }; + references: SavedObjectReference[]; +} => { + const { connector_id: pushConnectorId, ...restExternalService } = external_service ?? {}; + + const references = createConnectorReference( + pushConnectorId, + ACTION_SAVED_OBJECT_TYPE, + referenceName + ); + + return { + transformedPushConnector: { external_service: external_service ? restExternalService : null }, + references, + }; +}; diff --git a/x-pack/plugins/cases/server/services/user_actions/types.ts b/x-pack/plugins/cases/server/services/user_actions/types.ts new file mode 100644 index 0000000000000..3c67535255ecc --- /dev/null +++ b/x-pack/plugins/cases/server/services/user_actions/types.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Indicates whether which user action field is being parsed, the new_value or the old_value. + */ +export enum UserActionFieldType { + New = 'New', + Old = 'Old', +} diff --git a/x-pack/plugins/cloud/server/config.ts b/x-pack/plugins/cloud/server/config.ts index 4b83071bf473a..2cc413178c3ae 100644 --- a/x-pack/plugins/cloud/server/config.ts +++ b/x-pack/plugins/cloud/server/config.ts @@ -52,5 +52,6 @@ export const config: PluginConfigDescriptor = { organization_url: true, full_story: true, }, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: configSchema, }; diff --git a/x-pack/plugins/cross_cluster_replication/server/index.ts b/x-pack/plugins/cross_cluster_replication/server/index.ts index b1803950614d8..a6a3ec0fe5753 100644 --- a/x-pack/plugins/cross_cluster_replication/server/index.ts +++ b/x-pack/plugins/cross_cluster_replication/server/index.ts @@ -17,4 +17,5 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { ui: true, }, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/components/field_data_expanded_row/choropleth_map.tsx b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/components/field_data_expanded_row/choropleth_map.tsx index c2e1e0b7dffa9..318ff655abb21 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/components/field_data_expanded_row/choropleth_map.tsx +++ b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/components/field_data_expanded_row/choropleth_map.tsx @@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { FIELD_ORIGIN, + LAYER_TYPE, SOURCE_TYPES, STYLE_TYPE, COLOR_MAP_TYPE, @@ -85,7 +86,7 @@ export const getChoroplethTopValuesLayer = ( }, isTimeAware: true, }, - type: 'VECTOR', + type: LAYER_TYPE.VECTOR, }; }; diff --git a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx index 617f5a25ebbc5..4c46b84008766 100644 --- a/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx +++ b/x-pack/plugins/drilldowns/url_drilldown/public/lib/url_drilldown.tsx @@ -129,7 +129,7 @@ export class UrlDrilldown implements Drilldown { const scope = this.getRuntimeVariables(context); - const { isValid, error } = urlDrilldownValidateUrlTemplate(config.url, scope); + const { isValid, error } = await urlDrilldownValidateUrlTemplate(config.url, scope); if (!isValid) { // eslint-disable-next-line no-console @@ -139,7 +139,7 @@ export class UrlDrilldown implements Drilldown { const doEncode = config.encodeUrl ?? true; - const url = urlDrilldownCompileUrl( + const url = await urlDrilldownCompileUrl( config.url.template, this.getRuntimeVariables(context), doEncode @@ -159,7 +159,7 @@ export class UrlDrilldown implements Drilldown => { - const url = this.buildUrl(config, context); + const url = await this.buildUrl(config, context); const validUrl = this.deps.externalUrl.validateUrl(url); if (!validUrl) { throw new Error( diff --git a/x-pack/plugins/encrypted_saved_objects/server/index.ts b/x-pack/plugins/encrypted_saved_objects/server/index.ts index 2706da22d108b..b765f1fcaf6fa 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PluginInitializerContext } from 'src/core/server'; +import type { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; import { ConfigSchema } from './config'; import { EncryptedSavedObjectsPlugin } from './plugin'; @@ -15,6 +15,9 @@ export { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart } fr export { EncryptedSavedObjectsClient } from './saved_objects'; export type { IsMigrationNeededPredicate } from './create_migration'; -export const config = { schema: ConfigSchema }; +export const config: PluginConfigDescriptor = { + schema: ConfigSchema, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], +}; export const plugin = (initializerContext: PluginInitializerContext) => new EncryptedSavedObjectsPlugin(initializerContext); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.test.tsx new file mode 100644 index 0000000000000..0b647bffb3e26 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.test.tsx @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockKibanaValues, setMockActions, setMockValues } from '../../../../__mocks__/kea_logic'; +import '../../../../__mocks__/react_router'; +import '../../../__mocks__/engine_logic.mock'; + +import React from 'react'; + +import { shallow, ReactWrapper } from 'enzyme'; + +import { EuiBasicTable } from '@elastic/eui'; + +import { mountWithIntl } from '../../../../test_helpers'; + +import { CurationsTable } from './curations_table'; + +describe('CurationsTable', () => { + const { navigateToUrl } = mockKibanaValues; + + const values = { + dataLoading: false, + curations: [ + { + id: 'cur-id-1', + last_updated: 'January 1, 1970 at 12:00PM', + queries: ['hiking'], + }, + { + id: 'cur-id-2', + last_updated: 'January 2, 1970 at 12:00PM', + queries: ['mountains', 'valleys'], + }, + ], + meta: { + page: { + current: 1, + size: 10, + total_results: 2, + }, + }, + }; + + const actions = { + deleteCuration: jest.fn(), + onPaginate: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(values); + setMockActions(actions); + }); + + it('passes loading prop based on dataLoading', () => { + setMockValues({ ...values, dataLoading: true }); + const wrapper = shallow(); + + expect(wrapper.find(EuiBasicTable).prop('loading')).toEqual(true); + }); + + describe('populated table render', () => { + let wrapper: ReactWrapper; + + beforeAll(() => { + wrapper = mountWithIntl(); + }); + + it('renders queries and last updated columns', () => { + const tableContent = wrapper.find(EuiBasicTable).text(); + + expect(tableContent).toContain('Queries'); + expect(tableContent).toContain('hiking'); + expect(tableContent).toContain('mountains, valleys'); + + expect(tableContent).toContain('Last updated'); + expect(tableContent).toContain('Jan 1, 1970 12:00 PM'); + expect(tableContent).toContain('Jan 2, 1970 12:00 PM'); + }); + + it('renders queries with curation links', () => { + expect( + wrapper.find('EuiLinkTo[data-test-subj="CurationsTableQueriesLink"]').first().prop('to') + ).toEqual('/engines/some-engine/curations/cur-id-1'); + + expect( + wrapper.find('EuiLinkTo[data-test-subj="CurationsTableQueriesLink"]').last().prop('to') + ).toEqual('/engines/some-engine/curations/cur-id-2'); + }); + + describe('action column', () => { + it('edit action navigates to curation link', () => { + wrapper.find('[data-test-subj="CurationsTableEditButton"]').first().simulate('click'); + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations/cur-id-1'); + + wrapper.find('[data-test-subj="CurationsTableEditButton"]').last().simulate('click'); + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations/cur-id-2'); + }); + + it('delete action calls deleteCuration', () => { + wrapper.find('[data-test-subj="CurationsTableDeleteButton"]').first().simulate('click'); + expect(actions.deleteCuration).toHaveBeenCalledWith('cur-id-1'); + + wrapper.find('[data-test-subj="CurationsTableDeleteButton"]').last().simulate('click'); + expect(actions.deleteCuration).toHaveBeenCalledWith('cur-id-2'); + }); + }); + }); + + describe('pagination', () => { + it('passes pagination props from meta.page', () => { + setMockValues({ + ...values, + meta: { + page: { + current: 5, + size: 10, + total_results: 50, + }, + }, + }); + const wrapper = shallow(); + + expect(wrapper.find(EuiBasicTable).prop('pagination')).toEqual({ + pageIndex: 4, + pageSize: 10, + totalItemCount: 50, + hidePerPageOptions: true, + }); + }); + + it('calls onPaginate on pagination change', () => { + const wrapper = shallow(); + wrapper.find(EuiBasicTable).simulate('change', { page: { index: 0 } }); + + expect(actions.onPaginate).toHaveBeenCalledWith(1); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.tsx new file mode 100644 index 0000000000000..ad508bea1dbc7 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/curations_table.tsx @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useValues, useActions } from 'kea'; + +import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { EDIT_BUTTON_LABEL, DELETE_BUTTON_LABEL } from '../../../../shared/constants'; +import { KibanaLogic } from '../../../../shared/kibana'; +import { EuiLinkTo } from '../../../../shared/react_router_helpers'; +import { convertMetaToPagination, handlePageChange } from '../../../../shared/table_pagination'; + +import { ENGINE_CURATION_PATH } from '../../../routes'; +import { FormattedDateTime } from '../../../utils/formatted_date_time'; +import { generateEnginePath } from '../../engine'; + +import { CurationsLogic } from '../curations_logic'; +import { Curation } from '../types'; +import { convertToDate } from '../utils'; + +export const CurationsTable: React.FC = () => { + const { dataLoading, curations, meta } = useValues(CurationsLogic); + const { onPaginate, deleteCuration } = useActions(CurationsLogic); + + const columns: Array> = [ + { + field: 'queries', + name: i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.table.column.queries', + { defaultMessage: 'Queries' } + ), + render: (queries: Curation['queries'], curation: Curation) => ( + + {queries.join(', ')} + + ), + width: '40%', + truncateText: true, + mobileOptions: { + header: true, + // Note: the below props are valid props per https://elastic.github.io/eui/#/tabular-content/tables (Responsive tables), but EUI's types have a bug reporting it as an error + // @ts-ignore + enlarge: true, + width: '100%', + truncateText: false, + }, + }, + { + field: 'last_updated', + name: i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.table.column.lastUpdated', + { defaultMessage: 'Last updated' } + ), + width: '30%', + dataType: 'string', + render: (dateString: string) => , + }, + { + width: '120px', + actions: [ + { + name: EDIT_BUTTON_LABEL, + description: i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.table.editTooltip', + { defaultMessage: 'Edit curation' } + ), + type: 'icon', + icon: 'pencil', + color: 'primary', + onClick: (curation: Curation) => { + const { navigateToUrl } = KibanaLogic.values; + const url = generateEnginePath(ENGINE_CURATION_PATH, { curationId: curation.id }); + navigateToUrl(url); + }, + 'data-test-subj': 'CurationsTableEditButton', + }, + { + name: DELETE_BUTTON_LABEL, + description: i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.table.deleteTooltip', + { defaultMessage: 'Delete curation' } + ), + type: 'icon', + icon: 'trash', + color: 'danger', + onClick: (curation: Curation) => deleteCuration(curation.id), + 'data-test-subj': 'CurationsTableDeleteButton', + }, + ], + }, + ]; + + return ( + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/index.ts index 8c9e58e6ba0f4..473162dcbd91e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/index.ts @@ -5,4 +5,5 @@ * 2.0. */ +export { CurationsTable } from './curations_table'; export { EmptyState } from './empty_state'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.test.ts index f4296d4ff2089..0d02fbe413870 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.test.ts @@ -50,6 +50,7 @@ describe('CurationsLogic', () => { dataLoading: true, curations: [], meta: DEFAULT_META, + selectedPageTab: 'overview', }; beforeEach(() => { @@ -89,6 +90,19 @@ describe('CurationsLogic', () => { }); }); }); + + describe('onSelectPageTab', () => { + it('should set the selected page tab', () => { + mount(); + + CurationsLogic.actions.onSelectPageTab('settings'); + + expect(CurationsLogic.values).toEqual({ + ...DEFAULT_VALUES, + selectedPageTab: 'settings', + }); + }); + }); }); describe('listeners', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts index a98f83396b3b8..76adfa4b6ed4d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts @@ -23,10 +23,13 @@ import { EngineLogic, generateEnginePath } from '../engine'; import { DELETE_MESSAGE, SUCCESS_MESSAGE } from './constants'; import { Curation, CurationsAPIResponse } from './types'; +type CurationsPageTabs = 'overview' | 'settings'; + interface CurationsValues { dataLoading: boolean; curations: Curation[]; meta: Meta; + selectedPageTab: CurationsPageTabs; } interface CurationsActions { @@ -35,6 +38,7 @@ interface CurationsActions { loadCurations(): void; deleteCuration(id: string): string; createCuration(queries: Curation['queries']): Curation['queries']; + onSelectPageTab(pageTab: CurationsPageTabs): { pageTab: CurationsPageTabs }; } export const CurationsLogic = kea>({ @@ -45,8 +49,15 @@ export const CurationsLogic = kea id, createCuration: (queries) => queries, + onSelectPageTab: (pageTab) => ({ pageTab }), }), reducers: () => ({ + selectedPageTab: [ + 'overview', + { + onSelectPageTab: (_, { pageTab }) => pageTab, + }, + ], dataLoading: [ true, { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx index 85827d5374179..effd03e2e7437 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx @@ -5,23 +5,23 @@ * 2.0. */ -import { mockKibanaValues, setMockActions, setMockValues } from '../../../../__mocks__/kea_logic'; +import { setMockActions, setMockValues } from '../../../../__mocks__/kea_logic'; import '../../../../__mocks__/react_router'; import '../../../__mocks__/engine_logic.mock'; import React from 'react'; -import { shallow, ReactWrapper } from 'enzyme'; +import { shallow } from 'enzyme'; -import { EuiBasicTable } from '@elastic/eui'; +import { EuiTab } from '@elastic/eui'; -import { mountWithIntl, getPageTitle } from '../../../../test_helpers'; +import { mountWithIntl, getPageHeaderTabs, getPageTitle } from '../../../../test_helpers'; -import { Curations, CurationsTable } from './curations'; +import { Curations } from './curations'; +import { CurationsOverview } from './curations_overview'; +import { CurationsSettings } from './curations_settings'; describe('Curations', () => { - const { navigateToUrl } = mockKibanaValues; - const values = { dataLoading: false, curations: [ @@ -43,12 +43,13 @@ describe('Curations', () => { total_results: 2, }, }, + selectedPageTab: 'overview', }; const actions = { loadCurations: jest.fn(), - deleteCuration: jest.fn(), onPaginate: jest.fn(), + onSelectPageTab: jest.fn(), }; beforeEach(() => { @@ -57,11 +58,38 @@ describe('Curations', () => { setMockActions(actions); }); - it('renders', () => { + it('renders with a set of tabs in the page header', () => { const wrapper = shallow(); expect(getPageTitle(wrapper)).toEqual('Curated results'); - expect(wrapper.find(CurationsTable)).toHaveLength(1); + + const tabs = getPageHeaderTabs(wrapper).find(EuiTab); + + tabs.at(0).simulate('click'); + expect(actions.onSelectPageTab).toHaveBeenNthCalledWith(1, 'overview'); + + tabs.at(1).simulate('click'); + expect(actions.onSelectPageTab).toHaveBeenNthCalledWith(2, 'settings'); + }); + + it('renders an overview view', () => { + setMockValues({ ...values, selectedPageTab: 'overview' }); + const wrapper = shallow(); + const tabs = getPageHeaderTabs(wrapper).find(EuiTab); + + expect(tabs.at(0).prop('isSelected')).toEqual(true); + + expect(wrapper.find(CurationsOverview)).toHaveLength(1); + }); + + it('renders a settings view', () => { + setMockValues({ ...values, selectedPageTab: 'settings' }); + const wrapper = shallow(); + const tabs = getPageHeaderTabs(wrapper).find(EuiTab); + + expect(tabs.at(1).prop('isSelected')).toEqual(true); + + expect(wrapper.find(CurationsSettings)).toHaveLength(1); }); describe('loading state', () => { @@ -86,91 +114,4 @@ describe('Curations', () => { expect(actions.loadCurations).toHaveBeenCalledTimes(1); }); - - describe('CurationsTable', () => { - it('passes loading prop based on dataLoading', () => { - setMockValues({ ...values, dataLoading: true }); - const wrapper = shallow(); - - expect(wrapper.find(EuiBasicTable).prop('loading')).toEqual(true); - }); - - describe('populated table render', () => { - let wrapper: ReactWrapper; - - beforeAll(() => { - wrapper = mountWithIntl(); - }); - - it('renders queries and last updated columns', () => { - const tableContent = wrapper.find(EuiBasicTable).text(); - - expect(tableContent).toContain('Queries'); - expect(tableContent).toContain('hiking'); - expect(tableContent).toContain('mountains, valleys'); - - expect(tableContent).toContain('Last updated'); - expect(tableContent).toContain('Jan 1, 1970 12:00 PM'); - expect(tableContent).toContain('Jan 2, 1970 12:00 PM'); - }); - - it('renders queries with curation links', () => { - expect( - wrapper.find('EuiLinkTo[data-test-subj="CurationsTableQueriesLink"]').first().prop('to') - ).toEqual('/engines/some-engine/curations/cur-id-1'); - - expect( - wrapper.find('EuiLinkTo[data-test-subj="CurationsTableQueriesLink"]').last().prop('to') - ).toEqual('/engines/some-engine/curations/cur-id-2'); - }); - - describe('action column', () => { - it('edit action navigates to curation link', () => { - wrapper.find('[data-test-subj="CurationsTableEditButton"]').first().simulate('click'); - expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations/cur-id-1'); - - wrapper.find('[data-test-subj="CurationsTableEditButton"]').last().simulate('click'); - expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations/cur-id-2'); - }); - - it('delete action calls deleteCuration', () => { - wrapper.find('[data-test-subj="CurationsTableDeleteButton"]').first().simulate('click'); - expect(actions.deleteCuration).toHaveBeenCalledWith('cur-id-1'); - - wrapper.find('[data-test-subj="CurationsTableDeleteButton"]').last().simulate('click'); - expect(actions.deleteCuration).toHaveBeenCalledWith('cur-id-2'); - }); - }); - }); - - describe('pagination', () => { - it('passes pagination props from meta.page', () => { - setMockValues({ - ...values, - meta: { - page: { - current: 5, - size: 10, - total_results: 50, - }, - }, - }); - const wrapper = shallow(); - - expect(wrapper.find(EuiBasicTable).prop('pagination')).toEqual({ - pageIndex: 4, - pageSize: 10, - totalItemCount: 50, - hidePerPageOptions: true, - }); - }); - - it('calls onPaginate on pagination change', () => { - const wrapper = shallow(); - wrapper.find(EuiBasicTable).simulate('change', { page: { index: 0 } }); - - expect(actions.onPaginate).toHaveBeenCalledWith(1); - }); - }); - }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx index 12497ab52baf6..9584b21424fe3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.tsx @@ -9,28 +9,47 @@ import React, { useEffect } from 'react'; import { useValues, useActions } from 'kea'; -import { EuiBasicTable, EuiBasicTableColumn, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { EDIT_BUTTON_LABEL, DELETE_BUTTON_LABEL } from '../../../../shared/constants'; -import { KibanaLogic } from '../../../../shared/kibana'; -import { EuiButtonTo, EuiLinkTo } from '../../../../shared/react_router_helpers'; -import { convertMetaToPagination, handlePageChange } from '../../../../shared/table_pagination'; +import { EuiButtonTo } from '../../../../shared/react_router_helpers'; -import { ENGINE_CURATIONS_NEW_PATH, ENGINE_CURATION_PATH } from '../../../routes'; -import { FormattedDateTime } from '../../../utils/formatted_date_time'; +import { ENGINE_CURATIONS_NEW_PATH } from '../../../routes'; import { generateEnginePath } from '../../engine'; import { AppSearchPageTemplate } from '../../layout'; -import { EmptyState } from '../components'; import { CURATIONS_OVERVIEW_TITLE, CREATE_NEW_CURATION_TITLE } from '../constants'; import { CurationsLogic } from '../curations_logic'; -import { Curation } from '../types'; -import { getCurationsBreadcrumbs, convertToDate } from '../utils'; +import { getCurationsBreadcrumbs } from '../utils'; + +import { CurationsOverview } from './curations_overview'; +import { CurationsSettings } from './curations_settings'; export const Curations: React.FC = () => { - const { dataLoading, curations, meta } = useValues(CurationsLogic); - const { loadCurations } = useActions(CurationsLogic); + const { dataLoading, curations, meta, selectedPageTab } = useValues(CurationsLogic); + const { loadCurations, onSelectPageTab } = useActions(CurationsLogic); + + const pageTabs = [ + { + label: i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.overviewPageTabLabel', + { + defaultMessage: 'Overview', + } + ), + isSelected: selectedPageTab === 'overview', + onClick: () => onSelectPageTab('overview'), + }, + { + label: i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.settingsPageTabLabel', + { + defaultMessage: 'Settings', + } + ), + isSelected: selectedPageTab === 'settings', + onClick: () => onSelectPageTab('settings'), + }, + ]; useEffect(() => { loadCurations(); @@ -50,105 +69,12 @@ export const Curations: React.FC = () => { {CREATE_NEW_CURATION_TITLE} , ], + tabs: pageTabs, }} isLoading={dataLoading && !curations.length} - isEmptyState={!curations.length} - emptyState={} > - - - + {selectedPageTab === 'overview' && } + {selectedPageTab === 'settings' && } ); }; - -export const CurationsTable: React.FC = () => { - const { dataLoading, curations, meta } = useValues(CurationsLogic); - const { onPaginate, deleteCuration } = useActions(CurationsLogic); - - const columns: Array> = [ - { - field: 'queries', - name: i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.table.column.queries', - { defaultMessage: 'Queries' } - ), - render: (queries: Curation['queries'], curation: Curation) => ( - - {queries.join(', ')} - - ), - width: '40%', - truncateText: true, - mobileOptions: { - header: true, - // Note: the below props are valid props per https://elastic.github.io/eui/#/tabular-content/tables (Responsive tables), but EUI's types have a bug reporting it as an error - // @ts-ignore - enlarge: true, - width: '100%', - truncateText: false, - }, - }, - { - field: 'last_updated', - name: i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.table.column.lastUpdated', - { defaultMessage: 'Last updated' } - ), - width: '30%', - dataType: 'string', - render: (dateString: string) => , - }, - { - width: '120px', - actions: [ - { - name: EDIT_BUTTON_LABEL, - description: i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.table.editTooltip', - { defaultMessage: 'Edit curation' } - ), - type: 'icon', - icon: 'pencil', - color: 'primary', - onClick: (curation: Curation) => { - const { navigateToUrl } = KibanaLogic.values; - const url = generateEnginePath(ENGINE_CURATION_PATH, { curationId: curation.id }); - navigateToUrl(url); - }, - 'data-test-subj': 'CurationsTableEditButton', - }, - { - name: DELETE_BUTTON_LABEL, - description: i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.table.deleteTooltip', - { defaultMessage: 'Delete curation' } - ), - type: 'icon', - icon: 'trash', - color: 'danger', - onClick: (curation: Curation) => deleteCuration(curation.id), - 'data-test-subj': 'CurationsTableDeleteButton', - }, - ], - }, - ]; - - return ( - - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx new file mode 100644 index 0000000000000..a034c3b2a0689 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../__mocks__/kea_logic'; +import '../../../../__mocks__/react_router'; +import '../../../__mocks__/engine_logic.mock'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { CurationsTable, EmptyState } from '../components'; + +import { CurationsOverview } from './curations_overview'; + +describe('CurationsOverview', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders an empty message when there are no curations', () => { + setMockValues({ curations: [] }); + const wrapper = shallow(); + + expect(wrapper.is(EmptyState)).toBe(true); + }); + + it('renders a curations table when there are curations present', () => { + setMockValues({ + curations: [ + { + id: 'cur-id-1', + }, + { + id: 'cur-id-2', + }, + ], + }); + const wrapper = shallow(); + + expect(wrapper.find(CurationsTable)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx new file mode 100644 index 0000000000000..ec67d06da4769 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useValues } from 'kea'; + +import { EuiPanel } from '@elastic/eui'; + +import { CurationsTable, EmptyState } from '../components'; +import { CurationsLogic } from '../curations_logic'; + +export const CurationsOverview: React.FC = () => { + const { curations } = useValues(CurationsLogic); + + return curations.length ? ( + + + + ) : ( + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings.test.tsx new file mode 100644 index 0000000000000..855570829cce4 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings.test.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import '../../../../__mocks__/react_router'; +import '../../../__mocks__/engine_logic.mock'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { CurationsSettings } from './curations_settings'; + +describe('CurationsSettings', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders empty', () => { + const wrapper = shallow(); + + expect(wrapper.isEmptyRender()).toBe(true); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings.tsx new file mode 100644 index 0000000000000..4bff7f3b2ef5e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_settings.tsx @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +export const CurationsSettings: React.FC = () => { + return null; +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx index 75044bfcc8fb7..6bcbe9b06391e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx @@ -21,7 +21,7 @@ import { DOCUMENTS_TITLE } from './constants'; import { SearchExperience } from './search_experience'; export const Documents: React.FC = () => { - const { isMetaEngine, isEngineEmpty } = useValues(EngineLogic); + const { isMetaEngine, hasNoDocuments } = useValues(EngineLogic); const { myRole } = useValues(AppLogic); return ( @@ -32,7 +32,7 @@ export const Documents: React.FC = () => { rightSideItems: myRole.canManageEngineDocuments && !isMetaEngine ? [] : [], }} - isEmptyState={isEngineEmpty} + isEmptyState={hasNoDocuments} emptyState={} > {isMetaEngine && ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts index bd15f50fe78e3..28739a2799332 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.test.ts @@ -49,8 +49,8 @@ describe('EngineLogic', () => { dataLoading: true, engine: {}, engineName: '', - isEngineEmpty: true, - isEngineSchemaEmpty: true, + hasNoDocuments: true, + hasEmptySchema: true, isMetaEngine: false, isSampleEngine: false, hasSchemaErrors: false, @@ -64,8 +64,8 @@ describe('EngineLogic', () => { const DEFAULT_VALUES_WITH_ENGINE = { ...DEFAULT_VALUES, engine: mockEngineData, - isEngineEmpty: false, - isEngineSchemaEmpty: false, + hasNoDocuments: false, + hasEmptySchema: false, }; beforeEach(() => { @@ -255,8 +255,8 @@ describe('EngineLogic', () => { expect(EngineLogic.actions.onPollStart).toHaveBeenCalled(); }); - it('polls for engine data if the current engine is empty', () => { - mount({ engine: {} }); + it('polls for engine data if the current engine has no documents', () => { + mount({ engine: { ...mockEngineData, document_count: 0 } }); jest.spyOn(EngineLogic.actions, 'initializeEngine'); EngineLogic.actions.pollEmptyEngine(); @@ -267,8 +267,8 @@ describe('EngineLogic', () => { expect(EngineLogic.actions.initializeEngine).toHaveBeenCalledTimes(2); }); - it('cancels the poll if the current engine changed from empty to non-empty', () => { - mount({ engine: mockEngineData }); + it('cancels the poll if the current engine has documents', () => { + mount({ engine: { ...mockEngineData, document_count: 1 } }); jest.spyOn(EngineLogic.actions, 'stopPolling'); jest.spyOn(EngineLogic.actions, 'initializeEngine'); @@ -312,7 +312,7 @@ describe('EngineLogic', () => { }); describe('selectors', () => { - describe('isEngineEmpty', () => { + describe('hasNoDocuments', () => { it('returns true if the engine contains no documents', () => { const engine = { ...mockEngineData, document_count: 0 }; mount({ engine }); @@ -320,7 +320,7 @@ describe('EngineLogic', () => { expect(EngineLogic.values).toEqual({ ...DEFAULT_VALUES_WITH_ENGINE, engine, - isEngineEmpty: true, + hasNoDocuments: true, }); }); @@ -329,12 +329,12 @@ describe('EngineLogic', () => { expect(EngineLogic.values).toEqual({ ...DEFAULT_VALUES, - isEngineEmpty: true, + hasNoDocuments: true, }); }); }); - describe('isEngineSchemaEmpty', () => { + describe('hasEmptySchema', () => { it('returns true if the engine schema contains no fields', () => { const engine = { ...mockEngineData, schema: {} }; mount({ engine }); @@ -342,7 +342,7 @@ describe('EngineLogic', () => { expect(EngineLogic.values).toEqual({ ...DEFAULT_VALUES_WITH_ENGINE, engine, - isEngineSchemaEmpty: true, + hasEmptySchema: true, }); }); @@ -351,7 +351,7 @@ describe('EngineLogic', () => { expect(EngineLogic.values).toEqual({ ...DEFAULT_VALUES, - isEngineSchemaEmpty: true, + hasEmptySchema: true, }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts index c20cc763f3c90..aa5e15a3265b1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts @@ -19,8 +19,8 @@ interface EngineValues { dataLoading: boolean; engine: Partial; engineName: string; - isEngineEmpty: boolean; - isEngineSchemaEmpty: boolean; + hasNoDocuments: boolean; + hasEmptySchema: boolean; isMetaEngine: boolean; isSampleEngine: boolean; hasSchemaErrors: boolean; @@ -94,8 +94,8 @@ export const EngineLogic = kea>({ ], }, selectors: ({ selectors }) => ({ - isEngineEmpty: [() => [selectors.engine], (engine) => !engine.document_count], - isEngineSchemaEmpty: [ + hasNoDocuments: [() => [selectors.engine], (engine) => !engine.document_count], + hasEmptySchema: [ () => [selectors.engine], (engine) => Object.keys(engine.schema || {}).length === 0, ], @@ -149,7 +149,7 @@ export const EngineLogic = kea>({ if (values.intervalId) return; // Ensure we only have one poll at a time const id = window.setInterval(() => { - if (values.isEngineEmpty && values.isEngineSchemaEmpty) { + if (values.hasNoDocuments) { actions.initializeEngine(); // Re-fetch engine data when engine is empty } else { actions.stopPolling(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx index 01472987e4d48..be416b69b1aa9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx @@ -20,7 +20,7 @@ describe('EngineOverview', () => { const values = { dataLoading: false, myRole: {}, - isEngineEmpty: true, + hasNoDocuments: true, isMetaEngine: false, }; @@ -40,7 +40,7 @@ describe('EngineOverview', () => { describe('EngineOverviewMetrics', () => { it('renders when the engine has documents', () => { - setMockValues({ ...values, isEngineEmpty: false }); + setMockValues({ ...values, hasNoDocuments: false }); const wrapper = shallow(); expect(wrapper.find(EngineOverviewMetrics)).toHaveLength(1); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx index e966709dc1084..f6c4031823ea5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx @@ -20,10 +20,10 @@ export const EngineOverview: React.FC = () => { const { myRole: { canManageEngineDocuments, canViewEngineCredentials }, } = useValues(AppLogic); - const { isEngineEmpty, isMetaEngine } = useValues(EngineLogic); + const { hasNoDocuments, isMetaEngine } = useValues(EngineLogic); const canAddDocuments = canManageEngineDocuments && canViewEngineCredentials; - const showEngineOverview = !isEngineEmpty || !canAddDocuments || isMetaEngine; + const showEngineOverview = !hasNoDocuments || !canAddDocuments || isMetaEngine; return showEngineOverview ? : ; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.ts index 49a09b8a7a3f5..5ff153c3beb64 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.ts @@ -321,26 +321,25 @@ export const ResultSettingsLogic = kea { const { loadFieldData } = useActions(SearchUILogic); - const { isEngineSchemaEmpty } = useValues(EngineLogic); + const { hasEmptySchema } = useValues(EngineLogic); useEffect(() => { loadFieldData(); @@ -34,7 +34,7 @@ export const SearchUI: React.FC = () => { } > diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx index 3fbae0a564c17..2ecb6bffc8212 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx @@ -69,13 +69,13 @@ export const ErrorStatePrompt: React.FC = () => {
  • diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/get_page_header.tsx b/x-pack/plugins/enterprise_search/public/applications/test_helpers/get_page_header.tsx index a251188b5cd90..94440ad4e61a7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/test_helpers/get_page_header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/get_page_header.tsx @@ -9,7 +9,7 @@ import React, { Fragment } from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; -import { EuiPageHeaderProps } from '@elastic/eui'; +import { EuiPageHeaderProps, EuiTab } from '@elastic/eui'; /* * Given an AppSearchPageTemplate or WorkplaceSearchPageTemplate, these @@ -35,13 +35,30 @@ export const getPageHeaderActions = (wrapper: ShallowWrapper) => { return shallow(
    - {actions.map((action: React.ReactNode, i) => ( + {actions.map((action, i) => ( {action} ))}
    ); }; +export const getPageHeaderTabs = (wrapper: ShallowWrapper) => { + // The tabs prop of EuiPageHeader takes an `Array` + // instead of an array of EuiTab jsx components + // These are then rendered inside of EuiPageHeader as EuiTabs + // See https://elastic.github.io/eui/#/layout/page-header#tabs-in-the-page-header + + const tabs = getPageHeader(wrapper).tabs || []; + + return shallow( +
    + {tabs.map((tabProps, i) => ( + + ))} +
    + ); +}; + export const getPageHeaderChildren = (wrapper: ShallowWrapper) => { const children = getPageHeader(wrapper).children || null; diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/index.ts b/x-pack/plugins/enterprise_search/public/applications/test_helpers/index.ts index 7903b4a31c8a9..35836d5526615 100644 --- a/x-pack/plugins/enterprise_search/public/applications/test_helpers/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/index.ts @@ -16,6 +16,7 @@ export { getPageDescription, getPageHeaderActions, getPageHeaderChildren, + getPageHeaderTabs, } from './get_page_header'; // Misc diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts index 5f515fc99769c..28e796c256396 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts @@ -25,6 +25,7 @@ export const contentSources = [ allowsReauth: true, boost: 1, activities: [], + isOauth1: false, }, { id: '124', @@ -40,6 +41,7 @@ export const contentSources = [ allowsReauth: true, boost: 0.5, activities: [], + isOauth1: true, }, ]; @@ -303,6 +305,7 @@ export const sourceConfigData = { privateSourcesEnabled: false, categories: ['wiki', 'atlassian', 'intranet'], configuredFields: { + isOauth1: false, clientId: 'CyztADsSECRETCSAUCEh1a', clientSecret: 'GSjJxqSECRETCSAUCEksHk', baseUrl: 'https://mine.atlassian.net', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.test.tsx index 9af91107d7304..9aa0286b2bef0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.test.tsx @@ -25,6 +25,7 @@ describe('SourceConfigFields', () => { it('renders with all items, hiding API Keys', () => { const wrapper = shallow( { it('shows API keys', () => { const wrapper = shallow( - + ); expect(wrapper.find(ApiKey)).toHaveLength(2); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.tsx index 236d475b8f687..e33e7817b5209 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.tsx @@ -20,6 +20,7 @@ import { ApiKey } from '../api_key'; import { CredentialItem } from '../credential_item'; interface SourceConfigFieldsProps { + isOauth1?: boolean; clientId?: string; clientSecret?: string; publicKey?: string; @@ -28,14 +29,13 @@ interface SourceConfigFieldsProps { } export const SourceConfigFields: React.FC = ({ + isOauth1, clientId, clientSecret, publicKey, consumerKey, baseUrl, }) => { - const showApiKey = (publicKey || consumerKey) && !clientId; - const credentialItem = (label: string, item?: string) => item && ; @@ -58,10 +58,10 @@ export const SourceConfigFields: React.FC = ({ return ( <> - {showApiKey && keyElement} - {credentialItem(CLIENT_ID_LABEL, clientId)} + {isOauth1 && keyElement} + {!isOauth1 && credentialItem(CLIENT_ID_LABEL, clientId)} - {credentialItem(CLIENT_SECRET_LABEL, clientSecret)} + {!isOauth1 && credentialItem(CLIENT_SECRET_LABEL, clientSecret)} {credentialItem(BASE_URL_LABEL, baseUrl)} diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.scss b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.scss deleted file mode 100644 index bd061d6d00760..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.scss +++ /dev/null @@ -1,137 +0,0 @@ -.user-icon { - border-radius: 50%; - overflow: hidden; - width: 70px; - height: 70px; - display: inline-flex; - justify-content: center; - align-items: center; - flex-shrink: 0; - position: relative; - font-weight: 500; - background: $euiColorPrimary; - color: $euiColorEmptyShade; - - &:not(.user-icon--small) { - font-size: 1.75rem; - } - - &--small { - width: 30px; - height: 30px; - font-size: .875rem; - margin-right: .5rem; - } - - &__text { - text-shadow: 0 1px 2px rgba($euiColorInk, .08); - justify-content: center; - align-items: center; - font-size: 1.125rem; - color: $euiColorEmptyShade; - font-weight: 500; - - .user-icon--small & { - font-size: .87rem; - } - } - - &__image { - max-width: 100%; - width: 100%; - height: auto; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } -} - -.group-avatars { - display: flex; - flex-direction: row; - justify-content: flex-start; - padding-top: 4px; - - &__additional { - line-height: 2; - vertical-align: middle; - padding-left: 4px; - } - - .group-user-icon { - display: flex; - justify-content: center; - align-items: center; - position: relative; - overflow: hidden; - width: 32px; - height: 32px; - - & > * { - pointer-events: none; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } - - &__text { - padding-bottom: 2px; - z-index: 2; - line-height: 1; - font-weight: 500; - color: $euiColorEmptyShade; - font-size: .875rem; - text-shadow: 0 1px 2px rgba($euiColorInk, .08); - } - - &__image { - width: 24px; - height: 24px; - } - } -} - -.groups-tooltip { - position: relative; - display: inline-block; - - &:hover &__container { - visibility: visible; - } - - &__container { - visibility: hidden; - position: absolute; - display: flex; - flex-direction: column; - align-items: flex-start; - box-shadow: 0 0 12px rgba($euiColorInk, .15); - background: $euiColorGhost; - text-align: left; - text-overflow: ellipsis; - min-width: 125px; - padding: 6px 10px 6px 10px; - border-radius: 3px; - z-index: 5; - top: 100%; - margin-left: -10px; - } - - &__text { - line-height: 1.5; - white-space: nowrap; - } - - &__text:before { - content:''; - display:block; - width:0; - height:0; - position:absolute; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 6px solid $euiColorGhost; - top: -6px; - left: 16px; - } -} diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.test.tsx deleted file mode 100644 index 5ce83b641cf8f..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.test.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { users } from '../../../__mocks__/users.mock'; - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { UserIcon } from './user_icon'; - -describe('SourcesTable', () => { - it('renders with picture', () => { - const wrapper = shallow(); - - expect(wrapper.find('.user-icon')).toHaveLength(1); - expect(wrapper.find('.avatar__image')).toHaveLength(1); - }); - - it('renders without picture', () => { - const user = { - ...users[0], - pictureUrl: null, - }; - const wrapper = shallow(); - - expect(wrapper.find('.user-icon')).toHaveLength(1); - expect(wrapper.find('.avatar__text')).toHaveLength(1); - }); - - it('renders fallback "alt" value when name not present', () => { - const user = { - ...users[0], - name: null, - }; - const wrapper = shallow(); - - expect(wrapper.find('img').prop('alt')).toEqual(user.email); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.tsx deleted file mode 100644 index 5985f30683a20..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { User } from '../../../types'; - -import './user_icon.scss'; - -export const UserIcon: React.FC = ({ name, pictureUrl, color, initials, email }) => ( -
    - {pictureUrl ? ( - {name - ) : ( - {initials} - )} -
    -); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts index d8fcb414cff75..c524bd4f7617a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts @@ -108,6 +108,7 @@ export interface ContentSourceDetails extends ContentSource { allowsReauth: boolean; boost: number; activities: SourceActivity[]; + isOauth1: boolean; } interface DescriptionList { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.test.tsx index 5ff80a7683db6..c675a57ab18d8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.test.tsx @@ -27,6 +27,9 @@ describe('AccountSettings', () => { const mockCurrentUser = (user?: unknown) => (getCurrentUser as jest.Mock).mockReturnValue(Promise.resolve(user)); + const mockCurrentUserError = () => + (getCurrentUser as jest.Mock).mockReturnValue(Promise.reject()); + beforeAll(() => { mockCurrentUser(); }); @@ -44,6 +47,13 @@ describe('AccountSettings', () => { expect(wrapper.isEmptyRender()).toBe(true); }); + it('does not render if the getCurrentUser promise returns error', async () => { + mockCurrentUserError(); + const wrapper = await shallow(); + + expect(wrapper.isEmptyRender()).toBe(true); + }); + it('renders the security UI components when the user exists', async () => { mockCurrentUser({ username: 'mock user' }); (getPersonalInfo as jest.Mock).mockReturnValue(
    ); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx index fb5a3e34a9db7..b26650875f3ef 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx @@ -20,7 +20,12 @@ export const AccountSettings: React.FC = () => { const [currentUser, setCurrentUser] = useState(null); useEffect(() => { - security.authc.getCurrentUser().then(setCurrentUser); + security.authc + .getCurrentUser() + .then(setCurrentUser) + .catch(() => { + setCurrentUser(null); + }); }, [security.authc]); const PersonalInfo = useMemo(() => security.uiApi.components.getPersonalInfo, [security.uiApi]); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx index f723391a01cea..585477fed058e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx @@ -45,7 +45,6 @@ import { SOURCE_SETTINGS_DESCRIPTION, SOURCE_NAME_LABEL, SOURCE_CONFIG_TITLE, - SOURCE_CONFIG_DESCRIPTION, SOURCE_CONFIG_LINK, SOURCE_REMOVE_TITLE, SOURCE_REMOVE_DESCRIPTION, @@ -78,6 +77,7 @@ export const SourceSettings: React.FC = () => { custom: isCustom, isIndexedSource, areThumbnailsConfigEnabled, + isOauth1, indexing: { enabled, features: { @@ -99,10 +99,9 @@ export const SourceSettings: React.FC = () => { getSourceConfigData(serviceType); }, []); - const { - configuration: { isPublicKey }, - editPath, - } = staticSourceData.find((source) => source.serviceType === serviceType) as SourceDataItem; + const { editPath } = staticSourceData.find( + (source) => source.serviceType === serviceType + ) as SourceDataItem; const [inputValue, setValue] = useState(name); const [confirmModalVisible, setModalVisibility] = useState(false); @@ -206,12 +205,13 @@ export const SourceSettings: React.FC = () => { {showConfig && ( - + diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/constants.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/constants.ts index 001f06261de4b..b90d6abe38702 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/constants.ts @@ -306,13 +306,6 @@ export const SOURCE_CONFIG_TITLE = i18n.translate( } ); -export const SOURCE_CONFIG_DESCRIPTION = i18n.translate( - 'xpack.enterpriseSearch.workplaceSearch.sources.config.description', - { - defaultMessage: 'Edit content source connector settings to change.', - } -); - export const SYNC_MANAGEMENT_TITLE = i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.contentSources.syncManagementTitle', { @@ -358,7 +351,7 @@ export const SYNC_MANAGEMENT_CONTENT_EXTRACTION_LABEL = i18n.translate( export const SOURCE_CONFIG_LINK = i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.sources.config.link', { - defaultMessage: 'Edit content source connector settings', + defaultMessage: 'Edit connector settings', } ); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.test.tsx deleted file mode 100644 index 6c8dbbde2e69f..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { users } from '../../../__mocks__/users.mock'; - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - -import { UserIcon } from '../../../components/shared/user_icon'; - -import { UserOptionItem } from './user_option_item'; - -const user = users[0]; - -describe('UserOptionItem', () => { - it('renders', () => { - const wrapper = shallow(); - - expect(wrapper.find(UserIcon)).toHaveLength(1); - expect(wrapper.find(EuiFlexGroup)).toHaveLength(1); - expect(wrapper.find(EuiFlexItem)).toHaveLength(2); - }); - - it('falls back to email when name not present', () => { - const wrapper = shallow(); - const nameItem = wrapper.find(EuiFlexItem).last(); - - expect(nameItem.prop('children')).toEqual(user.email); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.tsx deleted file mode 100644 index b64cc18ce3081..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - -import { UserIcon } from '../../../components/shared/user_icon'; -import { User } from '../../../types'; - -interface UserOptionItemProps { - user: User; -} - -export const UserOptionItem: React.FC = ({ user }) => ( - - - - - {user.name || user.email} - -); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx index 61300bac47734..cb07c196e7ab8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { EuiSpacer, EuiTitle, EuiText, EuiButton, EuiLink } from '@elastic/eui'; +import { EuiSpacer, EuiTitle, EuiText, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -32,18 +32,16 @@ export const SetupGuide: React.FC = () => { - - {i18n.translate('xpack.enterpriseSearch.workplaceSearch.setupGuide.imageAlt', - + {i18n.translate('xpack.enterpriseSearch.workplaceSearch.setupGuide.imageAlt',

    diff --git a/x-pack/plugins/enterprise_search/server/index.ts b/x-pack/plugins/enterprise_search/server/index.ts index ecd068c8bdbd9..dae584a883bd7 100644 --- a/x-pack/plugins/enterprise_search/server/index.ts +++ b/x-pack/plugins/enterprise_search/server/index.ts @@ -37,4 +37,5 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { host: true, }, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; diff --git a/x-pack/plugins/fleet/common/constants/output.ts b/x-pack/plugins/fleet/common/constants/output.ts index 80c7e56dbb52f..9a236001aca25 100644 --- a/x-pack/plugins/fleet/common/constants/output.ts +++ b/x-pack/plugins/fleet/common/constants/output.ts @@ -13,8 +13,10 @@ export const outputType = { Elasticsearch: 'elasticsearch', } as const; +export const DEFAULT_OUTPUT_ID = 'default'; + export const DEFAULT_OUTPUT: NewOutput = { - name: 'default', + name: DEFAULT_OUTPUT_ID, is_default: true, type: outputType.Elasticsearch, hosts: [''], diff --git a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts index f262521461b98..119bb04af5ca8 100644 --- a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts +++ b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts @@ -11,7 +11,8 @@ import type { PackagePolicy, FullAgentPolicyInput, FullAgentPolicyInputStream } import { DEFAULT_OUTPUT } from '../constants'; export const storedPackagePoliciesToAgentInputs = ( - packagePolicies: PackagePolicy[] + packagePolicies: PackagePolicy[], + outputId: string = DEFAULT_OUTPUT.name ): FullAgentPolicyInput[] => { const fullInputs: FullAgentPolicyInput[] = []; @@ -32,7 +33,7 @@ export const storedPackagePoliciesToAgentInputs = ( data_stream: { namespace: packagePolicy.namespace || 'default', }, - use_output: DEFAULT_OUTPUT.name, + use_output: outputId, ...(input.compiled_input || {}), ...(input.streams.length ? { diff --git a/x-pack/plugins/fleet/common/types/index.ts b/x-pack/plugins/fleet/common/types/index.ts index 0deda3bf32657..bd970fc2cd83e 100644 --- a/x-pack/plugins/fleet/common/types/index.ts +++ b/x-pack/plugins/fleet/common/types/index.ts @@ -8,7 +8,11 @@ export * from './models'; export * from './rest_spec'; -import type { PreconfiguredAgentPolicy, PreconfiguredPackage } from './models/preconfiguration'; +import type { + PreconfiguredAgentPolicy, + PreconfiguredPackage, + PreconfiguredOutput, +} from './models/preconfiguration'; export interface FleetConfigType { enabled: boolean; @@ -26,6 +30,7 @@ export interface FleetConfigType { }; agentPolicies?: PreconfiguredAgentPolicy[]; packages?: PreconfiguredPackage[]; + outputs?: PreconfiguredOutput[]; agentIdVerificationEnabled?: boolean; } diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index f64467ca674fb..3f9e43e72c51d 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -23,6 +23,8 @@ export interface NewAgentPolicy { monitoring_enabled?: MonitoringType; unenroll_timeout?: number; is_preconfigured?: boolean; + data_output_id?: string; + monitoring_output_id?: string; } export interface AgentPolicy extends NewAgentPolicy { @@ -71,12 +73,14 @@ export interface FullAgentPolicyOutputPermissions { }; } +export type FullAgentPolicyOutput = Pick & { + [key: string]: any; +}; + export interface FullAgentPolicy { id: string; outputs: { - [key: string]: Pick & { - [key: string]: any; - }; + [key: string]: FullAgentPolicyOutput; }; output_permissions?: { [output: string]: FullAgentPolicyOutputPermissions; diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 66852bc965b07..371304765a5f8 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -361,6 +361,18 @@ export type PackageListItem = Installable & { id: string; }; +export interface IntegrationCardItem { + uiInternalPathUrl: string; + release?: 'beta' | 'experimental' | 'ga'; + description: string; + name: string; + title: string; + version: string; + icons: PackageSpecIcon[]; + integration: string; + id: string; +} + export type PackagesGroupedByStatus = Record, PackageList>; export type PackageInfo = | Installable> diff --git a/x-pack/plugins/fleet/common/types/models/output.ts b/x-pack/plugins/fleet/common/types/models/output.ts index c1dc2a4b4e058..4f70460e89ff8 100644 --- a/x-pack/plugins/fleet/common/types/models/output.ts +++ b/x-pack/plugins/fleet/common/types/models/output.ts @@ -17,11 +17,13 @@ export interface NewOutput { hosts?: string[]; ca_sha256?: string; api_key?: string; - config?: Record; config_yaml?: string; + is_preconfigured?: boolean; } -export type OutputSOAttributes = NewOutput; +export type OutputSOAttributes = NewOutput & { + output_id?: string; +}; export type Output = NewOutput & { id: string; diff --git a/x-pack/plugins/fleet/common/types/models/preconfiguration.ts b/x-pack/plugins/fleet/common/types/models/preconfiguration.ts index 6087c910510cc..17f9b946885b1 100644 --- a/x-pack/plugins/fleet/common/types/models/preconfiguration.ts +++ b/x-pack/plugins/fleet/common/types/models/preconfiguration.ts @@ -11,6 +11,7 @@ import type { NewPackagePolicyInput, } from './package_policy'; import type { NewAgentPolicy } from './agent_policy'; +import type { Output } from './output'; export type InputsOverride = Partial & { vars?: Array; @@ -29,3 +30,7 @@ export interface PreconfiguredAgentPolicy extends Omit; + +export interface PreconfiguredOutput extends Omit { + config?: Record; +} diff --git a/x-pack/plugins/fleet/kibana.json b/x-pack/plugins/fleet/kibana.json index f9ad1b0b966a4..c4782156b1982 100644 --- a/x-pack/plugins/fleet/kibana.json +++ b/x-pack/plugins/fleet/kibana.json @@ -8,7 +8,7 @@ "server": true, "ui": true, "configPath": ["xpack", "fleet"], - "requiredPlugins": ["licensing", "data", "encryptedSavedObjects", "navigation"], + "requiredPlugins": ["licensing", "data", "encryptedSavedObjects", "navigation", "customIntegrations"], "optionalPlugins": ["security", "features", "cloud", "usageCollection", "home", "globalSearch"], "extraPublicDirs": ["common"], "requiredBundles": ["kibanaReact", "esUiShared", "home", "infra", "kibanaUtils"] diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx index d3a6bb7561d39..9f125533f36c2 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx @@ -102,6 +102,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ { field: 'name', sortable: true, + truncateText: true, name: i18n.translate('xpack.fleet.policyDetails.packagePoliciesTable.nameColumnTitle', { defaultMessage: 'Name', }), diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index d887076568a68..35092cb67f7ef 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -726,7 +726,7 @@ const UpgradeStatusCallout: React.FunctionComponent<{ > 0) setDatasetValues(values.sort()); } catch (e) { setDatasetValues([AGENT_DATASET]); } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx index b423f3a8a57b3..805d2fab45240 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx @@ -6,7 +6,7 @@ */ import React, { memo, useState, useEffect, useCallback } from 'react'; -import { EuiPopover, EuiFilterButton, EuiFilterSelectItem } from '@elastic/eui'; +import { EuiPopover, EuiFilterButton, EuiFilterSelectItem, EuiIcon, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useStartServices } from '../../../../../hooks'; @@ -57,6 +57,29 @@ export const LogLevelFilter: React.FunctionComponent<{ fetchValues(); }, [data.autocomplete]); + const noLogsFound = ( +

    +
    + + +

    + {i18n.translate('xpack.fleet.agentLogs.logLevelEmpty', { + defaultMessage: 'No Logs Found', + })} +

    +
    +
    + ); + const filterSelect = levelValues.map((level) => ( + onToggleLevel(level)} + > + {level} + + )); + return ( - {levelValues.map((level) => ( - onToggleLevel(level)} - > - {level} - - ))} + {levelValues.length === 0 ? noLogsFound : filterSelect} ); }); diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_links.tsx b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_links.tsx index 82a058906cee5..032554a4ec439 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_links.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_links.tsx @@ -6,7 +6,6 @@ */ import { useStartServices } from '../../../hooks/use_core'; -import { PLUGIN_ID } from '../../../constants'; import { epmRouteService } from '../../../services'; import type { PackageSpecIcon, PackageSpecScreenshot, RegistryImage } from '../../../../common'; @@ -16,7 +15,6 @@ const removeRelativePath = (relativePath: string): string => export function useLinks() { const { http } = useStartServices(); return { - toAssets: (path: string) => http.basePath.prepend(`/plugins/${PLUGIN_ID}/assets/${path}`), toSharedAssets: (path: string) => http.basePath.prepend(`/plugins/kibanaReact/assets/${path}`), toPackageImage: ( img: PackageSpecIcon | PackageSpecScreenshot | RegistryImage, diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_local_search.tsx b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_local_search.tsx index fc2966697418a..a8ed849f50a8a 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_local_search.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_local_search.tsx @@ -8,12 +8,12 @@ import { Search as LocalSearch, AllSubstringsIndexStrategy } from 'js-search'; import { useEffect, useRef } from 'react'; -import type { PackageList } from '../../../types'; +import type { IntegrationCardItem } from '../../../../common/types/models'; export const searchIdField = 'id'; -export const fieldsToSearch = ['name', 'title']; +export const fieldsToSearch = ['name', 'title', 'description']; -export function useLocalSearch(packageList: PackageList) { +export function useLocalSearch(packageList: IntegrationCardItem[]) { const localSearchRef = useRef(null); useEffect(() => { diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_package_install.tsx b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_package_install.tsx index edbe06f33b18e..a59d4422348fb 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_package_install.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_package_install.tsx @@ -96,6 +96,7 @@ function usePackageInstall({ notifications }: { notifications: NotificationsStar }); history.push(settingsPath); } + notifications.toasts.addSuccess({ title: toMountPoint( { + return ( +
    + +
    + ); +}; + +AssetsFacetGroup.args = args; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.stories.tsx new file mode 100644 index 0000000000000..69c70bba5be1d --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.stories.tsx @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import type { SavedObject } from 'src/core/public'; + +import type { Installation } from '../../../../../../common'; + +import type { PackageCardProps } from './package_card'; +import { PackageCard } from './package_card'; + +export default { + title: 'Sections/EPM/Package Card', + description: 'A card representing a package available in Fleet', +}; + +type Args = Omit & { width: number }; + +const args: Args = { + width: 250, + title: 'Title', + description: 'Description', + name: 'beats', + release: 'ga', + id: 'id', + version: '1.0.0', + uiInternalPathUrl: '/', + icons: [], + integration: '', +}; + +const argTypes = { + release: { + control: { + type: 'radio', + options: ['ga', 'beta', 'experimental'], + }, + }, +}; + +export const NotInstalled = ({ width, ...props }: Args) => ( +
    + {/* + // @ts-ignore */} + +
    +); + +export const Installed = ({ width, ...props }: Args) => { + const savedObject: SavedObject = { + id: props.id, + // @ts-expect-error + type: props.type || '', + attributes: { + name: props.name, + version: props.version, + install_version: props.version, + es_index_patterns: {}, + installed_kibana: [], + installed_es: [], + install_status: 'installed', + install_source: 'registry', + install_started_at: '2020-01-01T00:00:00.000Z', + }, + references: [], + }; + + return ( +
    + {/* + // @ts-ignore */} + +
    + ); +}; + +NotInstalled.args = args; +NotInstalled.argTypes = argTypes; +Installed.args = args; +Installed.argTypes = argTypes; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx index c12e67fdb5718..8c7cd47e950f0 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx @@ -9,13 +9,12 @@ import React from 'react'; import styled from 'styled-components'; import { EuiCard } from '@elastic/eui'; -import type { PackageListItem } from '../../../types'; -import { useLink } from '../../../hooks'; -import { PackageIcon } from '../../../components'; +import { CardIcon } from '../../../../../components/package_icon'; +import type { IntegrationCardItem } from '../../../../../../common/types/models/epm'; -import { RELEASE_BADGE_LABEL, RELEASE_BADGE_DESCRIPTION } from './release_badge'; +import { RELEASE_BADGE_DESCRIPTION, RELEASE_BADGE_LABEL } from './release_badge'; -type PackageCardProps = PackageListItem; +export type PackageCardProps = IntegrationCardItem; // adding the `href` causes EuiCard to use a `a` instead of a `button` // `a` tags use `euiLinkColor` which results in blueish Badge text @@ -28,25 +27,21 @@ export function PackageCard({ name, title, version, - release, - status, icons, integration, - ...restProps + uiInternalPathUrl, + release, }: PackageCardProps) { - const { getHref } = useLink(); - let urlVersion = version; - // if this is an installed package, link to the version installed - if ('savedObject' in restProps) { - urlVersion = restProps.savedObject.attributes.version || version; - } + const betaBadgeLabel = release && release !== 'ga' ? RELEASE_BADGE_LABEL[release] : undefined; + const betaBadgeLabelTooltipContent = + release && release !== 'ga' ? RELEASE_BADGE_DESCRIPTION[release] : undefined; return ( } - href={getHref('integration_details_overview', { - pkgkey: `${name}-${urlVersion}`, - ...(integration ? { integration } : {}), - })} - betaBadgeLabel={release && release !== 'ga' ? RELEASE_BADGE_LABEL[release] : undefined} - betaBadgeTooltipContent={ - release && release !== 'ga' ? RELEASE_BADGE_DESCRIPTION[release] : undefined - } + href={uiInternalPathUrl} + betaBadgeLabel={betaBadgeLabel} + betaBadgeTooltipContent={betaBadgeLabelTooltipContent} /> ); } diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx new file mode 100644 index 0000000000000..737a83d5f5da8 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.stories.tsx @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { action } from '@storybook/addon-actions'; + +import type { SavedObject } from 'src/core/public'; + +import type { Installation } from '../../../../../../common'; + +import type { IntegrationCardItem } from '../../../../../../common'; + +import type { ListProps } from './package_list_grid'; +import { PackageListGrid } from './package_list_grid'; + +export default { + component: PackageListGrid, + title: 'Sections/EPM/Package List Grid', +}; + +type Args = Pick; + +const args: Args = { + title: 'Installed integrations', + isLoading: false, + showMissingIntegrationMessage: false, +}; + +const savedObject: SavedObject = { + id: 'id', + type: 'integration', + attributes: { + name: 'savedObject', + version: '1.2.3', + install_version: '1.2.3', + es_index_patterns: {}, + installed_kibana: [], + installed_es: [], + install_status: 'installed', + install_source: 'registry', + install_started_at: '2020-01-01T00:00:00.000Z', + }, + references: [], +}; + +export const EmptyList = (props: Args) => ( + +); + +export const List = (props: Args) => ( + +); + +EmptyList.args = args; +List.args = args; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx index 6bbd479c5c2ba..ac83cc83b6849 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx @@ -23,16 +23,17 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { useStartServices } from '../../../../../hooks'; import { Loading } from '../../../components'; -import type { PackageList } from '../../../types'; import { useLocalSearch, searchIdField } from '../../../hooks'; +import type { IntegrationCardItem } from '../../../../../../common/types/models'; + import { PackageCard } from './package_card'; -interface ListProps { +export interface ListProps { isLoading?: boolean; controls?: ReactNode; title: string; - list: PackageList; + list: IntegrationCardItem[]; initialSearch?: string; setSelectedCategory: (category: string) => void; onSearchChange: (search: string) => void; @@ -77,7 +78,7 @@ export function PackageListGrid({ } else { const filteredList = searchTerm ? list.filter((item) => - (localSearchRef.current!.search(searchTerm) as PackageList) + (localSearchRef.current!.search(searchTerm) as IntegrationCardItem[]) .map((match) => match[searchIdField]) .includes(item[searchIdField]) ) @@ -141,7 +142,7 @@ function ControlsColumn({ controls, title }: ControlsColumnProps) { } interface GridColumnProps { - list: PackageList; + list: IntegrationCardItem[]; showMissingIntegrationMessage?: boolean; } diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/requirements.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/requirements.stories.tsx new file mode 100644 index 0000000000000..205d739d48696 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/requirements.stories.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { Requirements as Component } from './requirements'; + +export default { + component: Component, + title: 'Sections/EPM/Requirements', +}; + +interface Args { + width: number; +} + +const args: Args = { + width: 250, +}; + +export const Requirements = ({ width }: Args) => { + return ( +
    + +
    + ); +}; + +Requirements.args = args; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx index 31a3e2164a247..d70b6c68016be 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx @@ -241,38 +241,6 @@ describe('when on integration detail', () => { 'http://localhost/mock/app/integrations/edit-integration/e8a37031-2907-44f6-89d2-98bd493f60dc' ); }); - - it('should NOT show link for agent count if it is zero', async () => { - await mockedApi.waitForApi(); - const firstRowAgentCount = renderResult.getAllByTestId('rowAgentCount')[0]; - expect(firstRowAgentCount.textContent).toEqual('0'); - expect(firstRowAgentCount.tagName).not.toEqual('A'); - }); - - it('should show add agent button if agent count is zero', async () => { - await mockedApi.waitForApi(); - const firstRowAgentCount = renderResult.getAllByTestId('rowAgentCount')[0]; - expect(firstRowAgentCount.textContent).toEqual('0'); - - const addAgentButton = renderResult.getAllByTestId('addAgentButton')[0]; - expect(addAgentButton).not.toBeNull(); - }); - - it('should show link for agent count if greater than zero', async () => { - await mockedApi.waitForApi(); - const secondRowAgentCount = renderResult.getAllByTestId('rowAgentCount')[1]; - expect(secondRowAgentCount.textContent).toEqual('100'); - expect(secondRowAgentCount.tagName).toEqual('A'); - }); - - it('should NOT show add agent button if agent count is greater than zero', async () => { - await mockedApi.waitForApi(); - const secondRowAgentCount = renderResult.getAllByTestId('rowAgentCount')[1]; - expect(secondRowAgentCount.textContent).toEqual('100'); - - const addAgentButton = renderResult.getAllByTestId('addAgentButton')[1]; - expect(addAgentButton).toBeUndefined(); - }); }); }); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx index fadcbdd70c28d..82436eb4d3f51 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx @@ -305,7 +305,7 @@ export function Detail() { {packageInfo.version} {updateAvailable ? ( - + ) : null} diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.test.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.test.tsx new file mode 100644 index 0000000000000..8872c61299093 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.test.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { act } from '@testing-library/react'; + +import { createIntegrationsTestRendererMock } from '../../../../../../../../mock'; + +import { PackagePolicyAgentsCell } from './package_policy_agents_cell'; + +function renderCell({ agentCount = 0, agentPolicyId = '123', onAddAgent = () => {} }) { + const renderer = createIntegrationsTestRendererMock(); + + return renderer.render( + + ); +} + +describe('PackagePolicyAgentsCell', () => { + test('it should display add agent if count is 0', async () => { + const utils = renderCell({ agentCount: 0 }); + await act(async () => { + expect(utils.queryByText('Add agent')).toBeInTheDocument(); + }); + }); + + test('it should display only count if count > 0', async () => { + const utils = renderCell({ agentCount: 9999 }); + await act(async () => { + expect(utils.queryByText('Add agent')).not.toBeInTheDocument(); + expect(utils.queryByText('9999')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.tsx new file mode 100644 index 0000000000000..37543e7e5ae1b --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiButton } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { LinkedAgentCount } from '../../../../../../components'; + +export const PackagePolicyAgentsCell = ({ + agentPolicyId, + agentCount = 0, + onAddAgent, +}: { + agentPolicyId: string; + agentCount?: number; + onAddAgent: () => void; +}) => { + if (agentCount > 0) { + return ( + + ); + } + + return ( + + + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx index 92b4012011fc8..42eb68099970a 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx @@ -13,19 +13,16 @@ import type { EuiTableFieldDataColumnType, } from '@elastic/eui'; import { - EuiButtonIcon, EuiBasicTable, EuiLink, EuiFlexGroup, EuiFlexItem, - EuiToolTip, EuiText, EuiButton, EuiSpacer, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedRelative, FormattedMessage } from '@kbn/i18n/react'; -import styled from 'styled-components'; import { InstallStatus } from '../../../../../types'; import type { GetAgentPoliciesResponseItem, InMemoryPackagePolicy } from '../../../../../types'; @@ -41,10 +38,10 @@ import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../../constants'; import { AgentEnrollmentFlyout, AgentPolicySummaryLine, - LinkedAgentCount, PackagePolicyActionsMenu, } from '../../../../../components'; +import { PackagePolicyAgentsCell } from './components/package_policy_agents_cell'; import { usePackagePoliciesWithAgentPolicy } from './use_package_policies_with_agent_policy'; import { Persona } from './persona'; @@ -58,10 +55,6 @@ interface InMemoryPackagePolicyAndAgentPolicy { agentPolicy: GetAgentPoliciesResponseItem; } -const AddAgentButton = styled(EuiButtonIcon)` - margin-left: ${(props) => props.theme.eui.euiSizeS}; -`; - const IntegrationDetailsLink = memo<{ packagePolicy: InMemoryPackagePolicyAndAgentPolicy['packagePolicy']; }>(({ packagePolicy }) => { @@ -266,51 +259,6 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps return ; }, }, - { - field: '', - name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.agentCount', { - defaultMessage: 'Agents', - }), - truncateText: true, - align: 'left', - width: '8ch', - render({ packagePolicy, agentPolicy }: InMemoryPackagePolicyAndAgentPolicy) { - const count = agentPolicy?.agents ?? 0; - - return ( - <> - - {count === 0 && ( - - setFlyoutOpenForPolicyId(agentPolicy.id)} - data-test-subj="addAgentButton" - aria-label={i18n.translate( - 'xpack.fleet.epm.packageDetails.integrationList.addAgent', - { - defaultMessage: 'Add Agent', - } - )} - /> - - )} - - ); - }, - }, { field: 'packagePolicy.updated_by', name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedBy', { @@ -335,6 +283,21 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps ); }, }, + { + field: '', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.agentCount', { + defaultMessage: 'Agents', + }), + render({ agentPolicy }: InMemoryPackagePolicyAndAgentPolicy) { + return ( + setFlyoutOpenForPolicyId(agentPolicy.id)} + /> + ); + }, + }, { field: '', name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.actions', { diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/install_button.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/install_button.tsx new file mode 100644 index 0000000000000..f2813058afe5a --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/install_button.tsx @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiButton } from '@elastic/eui'; +import React, { Fragment, useCallback, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import type { PackageInfo, UpgradePackagePolicyDryRunResponse } from '../../../../../types'; +import { InstallStatus } from '../../../../../types'; +import { + useCapabilities, + useGetPackageInstallStatus, + useInstallPackage, +} from '../../../../../hooks'; + +import { ConfirmPackageInstall } from './confirm_package_install'; + +type InstallationButtonProps = Pick & { + disabled?: boolean; + dryRunData?: UpgradePackagePolicyDryRunResponse | null; + isUpgradingPackagePolicies?: boolean; + latestVersion?: string; + numOfAssets: number; + packagePolicyIds?: string[]; + setIsUpgradingPackagePolicies?: React.Dispatch>; +}; +export function InstallButton(props: InstallationButtonProps) { + const { name, numOfAssets, title, version } = props; + const hasWriteCapabilites = useCapabilities().write; + const installPackage = useInstallPackage(); + const getPackageInstallStatus = useGetPackageInstallStatus(); + const { status: installationStatus } = getPackageInstallStatus(name); + + const isInstalling = installationStatus === InstallStatus.installing; + const [isInstallModalVisible, setIsInstallModalVisible] = useState(false); + + const toggleInstallModal = useCallback(() => { + setIsInstallModalVisible(!isInstallModalVisible); + }, [isInstallModalVisible]); + + const handleClickInstall = useCallback(() => { + installPackage({ name, version, title }); + toggleInstallModal(); + }, [installPackage, name, title, toggleInstallModal, version]); + + const installModal = ( + + ); + + return hasWriteCapabilites ? ( + + + {isInstalling ? ( + + ) : ( + + )} + + + {isInstallModalVisible && installModal} + + ) : null; +} diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/installation_button.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/installation_button.tsx deleted file mode 100644 index eab28a051f061..0000000000000 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/installation_button.tsx +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton } from '@elastic/eui'; -import React, { Fragment, useCallback, useMemo, useState } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; - -import type { PackageInfo } from '../../../../../types'; -import { InstallStatus } from '../../../../../types'; -import { - useCapabilities, - useUninstallPackage, - useGetPackageInstallStatus, - useInstallPackage, -} from '../../../../../hooks'; - -import { ConfirmPackageUninstall } from './confirm_package_uninstall'; -import { ConfirmPackageInstall } from './confirm_package_install'; - -type InstallationButtonProps = Pick & { - disabled?: boolean; - isUpdate?: boolean; - latestVersion?: string; -}; -export function InstallationButton(props: InstallationButtonProps) { - const { assets, name, title, version, disabled = true, isUpdate = false, latestVersion } = props; - const hasWriteCapabilites = useCapabilities().write; - const installPackage = useInstallPackage(); - const uninstallPackage = useUninstallPackage(); - const getPackageInstallStatus = useGetPackageInstallStatus(); - const { status: installationStatus } = getPackageInstallStatus(name); - - const isInstalling = installationStatus === InstallStatus.installing; - const isRemoving = installationStatus === InstallStatus.uninstalling; - const isInstalled = installationStatus === InstallStatus.installed; - const showUninstallButton = isInstalled || isRemoving; - const [isModalVisible, setModalVisible] = useState(false); - const toggleModal = useCallback(() => { - setModalVisible(!isModalVisible); - }, [isModalVisible]); - - const handleClickInstall = useCallback(() => { - installPackage({ name, version, title }); - toggleModal(); - }, [installPackage, name, title, toggleModal, version]); - - const handleClickUpdate = useCallback(() => { - installPackage({ name, version, title, fromUpdate: true }); - }, [installPackage, name, title, version]); - - const handleClickUninstall = useCallback(() => { - uninstallPackage({ name, version, title, redirectToVersion: latestVersion ?? version }); - toggleModal(); - }, [uninstallPackage, name, title, toggleModal, version, latestVersion]); - - // counts the number of assets in the package - const numOfAssets = useMemo( - () => - Object.entries(assets).reduce( - (acc, [serviceName, serviceNameValue]) => - acc + - Object.entries(serviceNameValue).reduce( - (acc2, [assetName, assetNameValue]) => acc2 + assetNameValue.length, - 0 - ), - 0 - ), - [assets] - ); - - const installButton = ( - - {isInstalling ? ( - - ) : ( - - )} - - ); - - const updateButton = ( - - - - ); - - const uninstallButton = ( - - {isRemoving ? ( - - ) : ( - - )} - - ); - - const uninstallModal = ( - - ); - - const installModal = ( - - ); - - return hasWriteCapabilites ? ( - - {isUpdate ? updateButton : showUninstallButton ? uninstallButton : installButton} - {isModalVisible && (isInstalled ? uninstallModal : installModal)} - - ) : null; -} diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx index 98cc172197d44..07c95e0d77ec7 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx @@ -5,30 +5,42 @@ * 2.0. */ -import React, { memo } from 'react'; +import React, { memo, useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; import semverLt from 'semver/functions/lt'; -import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiText, EuiSpacer, EuiLink } from '@elastic/eui'; +import { + EuiCallOut, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiSpacer, + EuiLink, +} from '@elastic/eui'; -import type { PackageInfo } from '../../../../../types'; +import { i18n } from '@kbn/i18n'; + +import type { PackageInfo, UpgradePackagePolicyDryRunResponse } from '../../../../../types'; import { InstallStatus } from '../../../../../types'; -import { useGetPackagePolicies, useGetPackageInstallStatus, useLink } from '../../../../../hooks'; +import { + useGetPackagePolicies, + useGetPackageInstallStatus, + useLink, + sendUpgradePackagePolicyDryRun, +} from '../../../../../hooks'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../../constants'; -import { UpdateIcon } from '../components'; -import { InstallationButton } from './installation_button'; +import { InstallButton } from './install_button'; +import { UpdateButton } from './update_button'; +import { UninstallButton } from './uninstall_button'; const SettingsTitleCell = styled.td` padding-right: ${(props) => props.theme.eui.spacerSizes.xl}; padding-bottom: ${(props) => props.theme.eui.spacerSizes.m}; `; -const UpdatesAvailableMsgContainer = styled.span` - padding-left: ${(props) => props.theme.eui.spacerSizes.s}; -`; - const NoteLabel = () => ( ( /> ); -const UpdatesAvailableMsg = () => ( - - +const UpdatesAvailableMsg = ({ latestVersion }: { latestVersion: string }) => ( + - + ); const LatestVersionLink = ({ name, version }: { name: string; version: string }) => { @@ -68,14 +86,35 @@ interface Props { export const SettingsPage: React.FC = memo(({ packageInfo }: Props) => { const { name, title, removable, latestVersion, version } = packageInfo; + const [dryRunData, setDryRunData] = useState(); + const [isUpgradingPackagePolicies, setIsUpgradingPackagePolicies] = useState(false); const getPackageInstallStatus = useGetPackageInstallStatus(); const { data: packagePoliciesData } = useGetPackagePolicies({ - perPage: 0, + perPage: 1000, page: 1, kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${name}`, }); + const { status: installationStatus, version: installedVersion } = getPackageInstallStatus(name); const packageHasUsages = !!packagePoliciesData?.total; + + const packagePolicyIds = useMemo( + () => packagePoliciesData?.items.map(({ id }) => id), + [packagePoliciesData] + ); + + useEffect(() => { + const fetchDryRunData = async () => { + if (packagePolicyIds && packagePolicyIds.length) { + const { data } = await sendUpgradePackagePolicyDryRun(packagePolicyIds, latestVersion); + + setDryRunData(data); + } + }; + + fetchDryRunData(); + }, [latestVersion, packagePolicyIds]); + const updateAvailable = installedVersion && semverLt(installedVersion, latestVersion) ? true : false; @@ -88,6 +127,20 @@ export const SettingsPage: React.FC = memo(({ packageInfo }: Props) => { const isUpdating = installationStatus === InstallStatus.installing && installedVersion; + const numOfAssets = useMemo( + () => + Object.entries(packageInfo.assets).reduce( + (acc, [serviceName, serviceNameValue]) => + acc + + Object.entries(serviceNameValue).reduce( + (acc2, [assetName, assetNameValue]) => acc2 + assetNameValue.length, + 0 + ), + 0 + ), + [packageInfo.assets] + ); + return ( @@ -129,7 +182,6 @@ export const SettingsPage: React.FC = memo(({ packageInfo }: Props) => { {installedVersion} - {updateAvailable && } @@ -147,15 +199,21 @@ export const SettingsPage: React.FC = memo(({ packageInfo }: Props) => { - {updateAvailable && ( -

    - -

    + {(updateAvailable || isUpgradingPackagePolicies) && ( + <> + + +

    + +

    + )}
    )} @@ -189,8 +247,9 @@ export const SettingsPage: React.FC = memo(({ packageInfo }: Props) => {

    -

    @@ -220,8 +279,9 @@ export const SettingsPage: React.FC = memo(({ packageInfo }: Props) => {

    - diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/uninstall_button.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/uninstall_button.tsx new file mode 100644 index 0000000000000..00b6ccc2f7912 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/uninstall_button.tsx @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiButton } from '@elastic/eui'; +import React, { useCallback, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { InstallStatus } from '../../../../../types'; +import type { PackageInfo } from '../../../../../types'; + +import { + useCapabilities, + useGetPackageInstallStatus, + useUninstallPackage, +} from '../../../../../hooks'; + +import { ConfirmPackageUninstall } from './confirm_package_uninstall'; + +interface UninstallButtonProps extends Pick { + disabled?: boolean; + latestVersion?: string; + numOfAssets: number; +} + +export const UninstallButton: React.FunctionComponent = ({ + disabled = false, + latestVersion, + name, + numOfAssets, + title, + version, +}) => { + const hasWriteCapabilites = useCapabilities().write; + const uninstallPackage = useUninstallPackage(); + const getPackageInstallStatus = useGetPackageInstallStatus(); + const { status: installationStatus } = getPackageInstallStatus(name); + const isRemoving = installationStatus === InstallStatus.uninstalling; + + const [isUninstallModalVisible, setIsUninstallModalVisible] = useState(false); + + const handleClickUninstall = useCallback(() => { + uninstallPackage({ name, version, title, redirectToVersion: latestVersion ?? version }); + setIsUninstallModalVisible(false); + }, [uninstallPackage, name, title, version, latestVersion]); + + const uninstallModal = ( + setIsUninstallModalVisible(false)} + onConfirm={handleClickUninstall} + /> + ); + + return hasWriteCapabilites ? ( + <> + setIsUninstallModalVisible(true)} + color="danger" + disabled={disabled || isRemoving ? true : false} + > + {isRemoving ? ( + + ) : ( + + )} + + {isUninstallModalVisible && uninstallModal} + + ) : null; +}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/update_button.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/update_button.tsx new file mode 100644 index 0000000000000..8cdb3ece30621 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/update_button.tsx @@ -0,0 +1,310 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useHistory } from 'react-router-dom'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiButton, + EuiCheckbox, + EuiCallOut, + EuiConfirmModal, + EuiSpacer, +} from '@elastic/eui'; +import { sumBy } from 'lodash'; + +import type { + GetAgentPoliciesResponse, + PackageInfo, + UpgradePackagePolicyDryRunResponse, +} from '../../../../../types'; +import { InstallStatus } from '../../../../../types'; +import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../constants'; +import { + sendGetAgentPolicies, + useInstallPackage, + useGetPackageInstallStatus, + sendUpgradePackagePolicy, + useStartServices, + useCapabilities, + useLink, +} from '../../../../../hooks'; +import { toMountPoint } from '../../../../../../../../../../../src/plugins/kibana_react/public'; + +interface UpdateButtonProps extends Pick { + dryRunData?: UpgradePackagePolicyDryRunResponse | null; + packagePolicyIds?: string[]; + isUpgradingPackagePolicies?: boolean; + setIsUpgradingPackagePolicies?: React.Dispatch>; +} + +/* + + Updating an integration to a new version entails a bit of logic. We allow the user to choose whether they'd like to + simultaneously upgrade any package policies that include the current version of the integration. For example, if + a user is running four agent policies that include the `nginx-0.2.4` package and they update to `nginx-0.7.0`, they + can elect to also deploy the new integration version to any agent running one of those four agent policies. + + If the user does not elect to upgrade their running policies, we simply install the latest version of the package and + navigate to the new version's settings page, e.g. `/detail/nginx-0.7.0/settings`. + + If the user _does_ elect to upgrade their running policies, we display a confirmation modal. In this modal, we'll report the + number of agents and policies that will be affected by the upgrade, and if there are any conflicts. In the case of a conflict + between versions, an upgrade for a given package policy will be skipped and the user will need to manually recreate their policy + to resolve any breaking changes between versions. Once the user confirms, we first install the latest version of the integration, + then we make a call to the "upgrade policies" API endpoint with a list of all package policy ID's that include the current version + of the integration. This API endpoint will complete the upgrade process in bulk for each package policy provided. Upon completion, + we navigate to the new version's settings page, as above. + +*/ + +export const UpdateButton: React.FunctionComponent = ({ + dryRunData, + isUpgradingPackagePolicies = false, + name, + packagePolicyIds = [], + setIsUpgradingPackagePolicies = () => {}, + title, + version, +}) => { + const history = useHistory(); + const { getPath } = useLink(); + + const { notifications } = useStartServices(); + const hasWriteCapabilites = useCapabilities().write; + + const installPackage = useInstallPackage(); + const getPackageInstallStatus = useGetPackageInstallStatus(); + const { status: installationStatus } = getPackageInstallStatus(name); + const isInstalling = installationStatus === InstallStatus.installing; + + const [isUpdateModalVisible, setIsUpdateModalVisible] = useState(false); + const [upgradePackagePolicies, setUpgradePackagePolicies] = useState(true); + const [agentPolicyData, setAgentPolicyData] = useState(); + + useEffect(() => { + const fetchAgentPolicyData = async () => { + if (packagePolicyIds && packagePolicyIds.length > 0) { + const { data } = await sendGetAgentPolicies({ + perPage: 1000, + page: 1, + // Fetch all agent policies that include one of the eligible package policies + kuery: `${AGENT_POLICY_SAVED_OBJECT_TYPE}.package_policies:${packagePolicyIds + .map((id) => `"${id}"`) + .join(' or ')}`, + }); + + setAgentPolicyData(data); + } + }; + + fetchAgentPolicyData(); + }, [packagePolicyIds]); + + const packagePolicyCount = useMemo(() => packagePolicyIds.length, [packagePolicyIds]); + const agentCount = useMemo( + () => sumBy(agentPolicyData?.items, ({ agents }) => agents ?? 0), + [agentPolicyData] + ); + const conflictCount = useMemo( + () => dryRunData?.filter((item) => item.hasErrors).length, + [dryRunData] + ); + + const handleUpgradePackagePoliciesChange = useCallback(() => { + setUpgradePackagePolicies((prev) => !prev); + }, []); + + const navigateToNewSettingsPage = useCallback(() => { + const settingsPath = getPath('integration_details_settings', { + pkgkey: `${name}-${version}`, + }); + history.push(settingsPath); + }, [history, getPath, name, version]); + + const handleClickUpdate = useCallback(async () => { + await installPackage({ name, version, title, fromUpdate: true }); + }, [installPackage, name, title, version]); + + const handleClickUpgradePolicies = useCallback(async () => { + if (isUpgradingPackagePolicies) { + return; + } + + setIsUpgradingPackagePolicies(true); + + await installPackage({ name, version, title }); + + await sendUpgradePackagePolicy( + // Only upgrade policies that don't have conflicts + packagePolicyIds.filter( + (id) => !dryRunData?.find((dryRunRecord) => dryRunRecord.diff?.[0].id === id)?.hasErrors + ) + ); + + setIsUpgradingPackagePolicies(false); + setIsUpdateModalVisible(false); + + notifications.toasts.addSuccess({ + title: toMountPoint( + + ), + text: toMountPoint( + + ), + }); + + navigateToNewSettingsPage(); + }, [ + dryRunData, + installPackage, + isUpgradingPackagePolicies, + name, + navigateToNewSettingsPage, + notifications.toasts, + packagePolicyIds, + setIsUpgradingPackagePolicies, + title, + version, + ]); + + const updateModal = ( + { + setIsUpdateModalVisible(false); + }} + cancelButtonText={i18n.translate( + 'xpack.fleet.integrations.settings.confirmUpdateModal.cancel', + { defaultMessage: 'Cancel' } + )} + onConfirm={handleClickUpgradePolicies} + confirmButtonText={i18n.translate( + 'xpack.fleet.integrations.settings.confirmUpdateModal.confirm', + { defaultMessage: 'Upgrade {packageName} and policies', values: { packageName: title } } + )} + title={i18n.translate('xpack.fleet.integrations.settings.confirmUpdateModal.updateTitle', { + defaultMessage: 'Upgrade {packageName} and policies', + values: { packageName: title }, + })} + > + <> + {conflictCount && conflictCount > 0 ? ( + <> + + + + {' '} + + + + + + ) : null} + + + + ), + agentCountText: ( + + + + ), + }} + /> + + + ); + + return hasWriteCapabilites ? ( + <> + + + setIsUpdateModalVisible(true) : handleClickUpdate + } + > + + + + {packagePolicyCount > 0 && ( + + + + )} + + + {isUpdateModalVisible && updateModal} + + ) : null; +}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx index e4d81f1d04118..daa0520ebc041 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx @@ -8,8 +8,18 @@ import { EuiFacetButton, EuiFacetGroup } from '@elastic/eui'; import React from 'react'; +import { i18n } from '@kbn/i18n'; + import { Loading } from '../../../../components'; -import type { CategorySummaryItem, CategorySummaryList } from '../../../../types'; +import type { CategoryCount } from '../../../../../../../../../../src/plugins/custom_integrations/common'; +import { CATEGORY_DISPLAY } from '../../../../../../../../../../src/plugins/custom_integrations/common'; + +interface ALL_CATEGORY { + id: ''; + count: number; +} + +export type CategoryFacet = CategoryCount | ALL_CATEGORY; export function CategoryFacets({ isLoading, @@ -18,26 +28,41 @@ export function CategoryFacets({ onCategoryChange, }: { isLoading?: boolean; - categories: CategorySummaryList; + categories: CategoryFacet[]; selectedCategory: string; - onCategoryChange: (category: CategorySummaryItem) => unknown; + onCategoryChange: (category: CategoryFacet) => unknown; }) { const controls = ( {isLoading ? ( ) : ( - categories.map((category) => ( - onCategoryChange(category)} - > - {category.title} - - )) + categories.map((category) => { + let title; + + if (category.id === 'updates_available') { + title = i18n.translate('xpack.fleet.epmList.updatesAvailableFilterLinkText', { + defaultMessage: 'Updates available', + }); + } else if (category.id === '') { + title = i18n.translate('xpack.fleet.epmList.allPackagesFilterLinkText', { + defaultMessage: 'All', + }); + } else { + title = CATEGORY_DISPLAY[category.id]; + } + return ( + onCategoryChange(category)} + > + {title} + + ); + }) )} ); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx index 5e94fbda2c22a..48a9dc0f6b63c 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx @@ -11,18 +11,35 @@ import semverLt from 'semver/functions/lt'; import { i18n } from '@kbn/i18n'; import { installationStatuses } from '../../../../../../../common/constants'; +import type { DynamicPage, DynamicPagePathValues, StaticPage } from '../../../../constants'; import { INTEGRATIONS_ROUTING_PATHS, INTEGRATIONS_SEARCH_QUERYPARAM, pagePathGetters, } from '../../../../constants'; -import { useGetCategories, useGetPackages, useBreadcrumbs } from '../../../../hooks'; +import { + useGetCategories, + useGetPackages, + useBreadcrumbs, + useGetAddableCustomIntegrations, + useLink, +} from '../../../../hooks'; import { doesPackageHaveIntegrations } from '../../../../services'; import { DefaultLayout } from '../../../../layouts'; -import type { CategorySummaryItem, PackageList } from '../../../../types'; +import type { PackageList } from '../../../../types'; import { PackageListGrid } from '../../components/package_list_grid'; +import type { CustomIntegration } from '../../../../../../../../../../src/plugins/custom_integrations/common'; + +import type { PackageListItem } from '../../../../types'; + +import type { IntegrationCardItem } from '../../../../../../../common/types/models'; + +import type { Category } from '../../../../../../../../../../src/plugins/custom_integrations/common'; + +import { mergeAndReplaceCategoryCounts } from './util'; import { CategoryFacets } from './category_facets'; +import type { CategoryFacet } from './category_facets'; export interface CategoryParams { category?: string; @@ -36,10 +53,43 @@ function getParams(params: CategoryParams, search: string) { return { selectedCategory, searchParam }; } -function categoryExists(category: string, categories: CategorySummaryItem[]) { +function categoryExists(category: string, categories: CategoryFacet[]) { return categories.some((c) => c.id === category); } +function mapToCard( + getAbsolutePath: (p: string) => string, + getHref: (page: StaticPage | DynamicPage, values?: DynamicPagePathValues) => string, + item: CustomIntegration | PackageListItem +): IntegrationCardItem { + let uiInternalPathUrl; + if (item.type === 'ui_link') { + uiInternalPathUrl = getAbsolutePath(item.uiInternalPath); + } else { + let urlVersion = item.version; + if ('savedObject' in item) { + urlVersion = item.savedObject.attributes.version || item.version; + } + const url = getHref('integration_details_overview', { + pkgkey: `${item.name}-${urlVersion}`, + ...(item.integration ? { integration: item.integration } : {}), + }); + uiInternalPathUrl = url; + } + + return { + id: `${item.type === 'ui_link' ? 'ui_link' : 'epr'}-${item.id}`, + description: item.description, + icons: !item.icons || !item.icons.length ? [] : item.icons, + integration: 'integration' in item ? item.integration || '' : '', + name: 'name' in item ? item.name || '' : '', + title: item.title, + version: 'version' in item ? item.version || '' : '', + release: 'release' in item ? item.release : undefined, + uiInternalPathUrl, + }; +} + export const EPMHomePage: React.FC = memo(() => { return ( @@ -89,6 +139,7 @@ const InstalledPackages: React.FC = memo(() => { const { data: allPackages, isLoading: isLoadingPackages } = useGetPackages({ experimental: true, }); + const { getHref, getAbsolutePath } = useLink(); const { selectedCategory, searchParam } = getParams( useParams(), @@ -103,7 +154,7 @@ const InstalledPackages: React.FC = memo(() => { history.push(url); } function setSearchTerm(search: string) { - // Use .replace so the browser's back button is tied to single keystroke + // Use .replace so the browser's back button is not tied to single keystroke history.replace( pagePathGetters.integrations_installed({ category: selectedCategory, @@ -135,20 +186,14 @@ const InstalledPackages: React.FC = memo(() => { [] ); - const categories = useMemo( + const categories: CategoryFacet[] = useMemo( () => [ { id: '', - title: i18n.translate('xpack.fleet.epmList.allFilterLinkText', { - defaultMessage: 'All', - }), count: allInstalledPackages.length, }, { id: 'updates_available', - title: i18n.translate('xpack.fleet.epmList.updatesAvailableFilterLinkText', { - defaultMessage: 'Updates available', - }), count: updatablePackages.length, }, ], @@ -166,10 +211,16 @@ const InstalledPackages: React.FC = memo(() => { setSelectedCategory(id)} + onCategoryChange={({ id }: CategoryFacet) => setSelectedCategory(id)} /> ); + const cards = ( + selectedCategory === 'updates_available' ? updatablePackages : allInstalledPackages + ).map((item) => { + return mapToCard(getAbsolutePath, getHref, item); + }); + return ( { onSearchChange={setSearchTerm} initialSearch={searchParam} title={title} - list={selectedCategory === 'updates_available' ? updatablePackages : allInstalledPackages} + list={cards} /> ); }); @@ -190,6 +241,8 @@ const AvailablePackages: React.FC = memo(() => { useLocation().search ); const history = useHistory(); + const { getHref, getAbsolutePath } = useLink(); + function setSelectedCategory(categoryId: string) { const url = pagePathGetters.integrations_all({ category: categoryId, @@ -198,7 +251,7 @@ const AvailablePackages: React.FC = memo(() => { history.push(url); } function setSearchTerm(search: string) { - // Use .replace so the browser's back button is tied to single keystroke + // Use .replace so the browser's back button is not tied to single keystroke history.replace( pagePathGetters.integrations_all({ category: selectedCategory, searchTerm: search })[1] ); @@ -213,16 +266,27 @@ const AvailablePackages: React.FC = memo(() => { const { data: categoriesRes, isLoading: isLoadingCategories } = useGetCategories({ include_policy_templates: true, }); - const packages = useMemo( + const eprPackages = useMemo( () => packageListToIntegrationsList(categoryPackagesRes?.response || []), [categoryPackagesRes] ); - const allPackages = useMemo( + const allEprPackages = useMemo( () => packageListToIntegrationsList(allCategoryPackagesRes?.response || []), [allCategoryPackagesRes] ); + const { loading: isLoadingAddableCustomIntegrations, value: addableCustomIntegrations } = + useGetAddableCustomIntegrations(); + const filteredAddableIntegrations = addableCustomIntegrations + ? addableCustomIntegrations.filter((integration: CustomIntegration) => { + if (!selectedCategory) { + return true; + } + return integration.categories.indexOf(selectedCategory as Category) >= 0; + }) + : []; + const title = useMemo( () => i18n.translate('xpack.fleet.epmList.allTitle', { @@ -231,19 +295,39 @@ const AvailablePackages: React.FC = memo(() => { [] ); - const categories = useMemo( - () => [ + const eprAndCustomPackages: Array = [ + ...eprPackages, + ...filteredAddableIntegrations, + ]; + eprAndCustomPackages.sort((a, b) => { + return a.title.localeCompare(b.title); + }); + + const categories = useMemo(() => { + const eprAndCustomCategories: CategoryFacet[] = + isLoadingCategories || + isLoadingAddableCustomIntegrations || + !addableCustomIntegrations || + !categoriesRes + ? [] + : mergeAndReplaceCategoryCounts( + categoriesRes.response as CategoryFacet[], + addableCustomIntegrations + ); + return [ { id: '', - title: i18n.translate('xpack.fleet.epmList.allPackagesFilterLinkText', { - defaultMessage: 'All', - }), - count: allPackages?.length || 0, + count: (allEprPackages?.length || 0) + (addableCustomIntegrations?.length || 0), }, - ...(categoriesRes ? categoriesRes.response : []), - ], - [allPackages?.length, categoriesRes] - ); + ...(eprAndCustomCategories ? eprAndCustomCategories : []), + ] as CategoryFacet[]; + }, [ + allEprPackages?.length, + addableCustomIntegrations, + categoriesRes, + isLoadingAddableCustomIntegrations, + isLoadingCategories, + ]); if (!categoryExists(selectedCategory, categories)) { history.replace(pagePathGetters.integrations_all({ category: '', searchTerm: searchParam })[1]); @@ -252,22 +336,26 @@ const AvailablePackages: React.FC = memo(() => { const controls = categories ? ( { + onCategoryChange={({ id }: CategoryFacet) => { setSelectedCategory(id); }} /> ) : null; + const cards = eprAndCustomPackages.map((item) => { + return mapToCard(getAbsolutePath, getHref, item); + }); + return ( { + const match = merged.find((c) => { + return c.id === category; + }); + + if (match) { + match.count += count; + } else { + merged.push({ + id: category as Category, + count, + }); + } + }; + + eprCounts.forEach((facet) => { + addIfMissing(facet.id, facet.count); + }); + addableIntegrations.forEach((integration) => { + integration.categories.forEach((cat) => { + addIfMissing(cat, 1); + }); + }); + + merged.sort((a, b) => { + return a.id.localeCompare(b.id); + }); + + return merged; +} diff --git a/x-pack/plugins/fleet/public/components/package_icon.tsx b/x-pack/plugins/fleet/public/components/package_icon.tsx index df0bd9864b60f..85ae7971f46c2 100644 --- a/x-pack/plugins/fleet/public/components/package_icon.tsx +++ b/x-pack/plugins/fleet/public/components/package_icon.tsx @@ -17,3 +17,14 @@ export const PackageIcon: React.FunctionComponent; }; + +export const CardIcon: React.FunctionComponent> = ( + props +) => { + const { icons } = props; + if (icons && icons.length === 1 && icons[0].type === 'eui') { + return ; + } else { + return ; + } +}; diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx index eefa3c870f283..ee7d5f97fcbac 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx @@ -69,7 +69,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ > , ] @@ -117,7 +117,10 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ disabled={!hasWriteCapabilities} icon="trash" onClick={() => { - deletePackagePoliciesPrompt([packagePolicy.id], refreshAgentPolicy); + deletePackagePoliciesPrompt([packagePolicy.id], () => { + setIsActionsMenuOpen(false); + refreshAgentPolicy(); + }); }} > { getPath: (page: StaticPage | DynamicPage, values: DynamicPagePathValues = {}): string => { return getSeparatePaths(page, values)[1]; }, + getAbsolutePath: (path: string): string => { + return core.http.basePath.prepend(`${path}`); + }, getAssetsPath: (path: string) => core.http.basePath.prepend(`/plugins/${PLUGIN_ID}/assets/${path}`), getHref: (page: StaticPage | DynamicPage, values?: DynamicPagePathValues) => { diff --git a/x-pack/plugins/fleet/public/hooks/use_package_icon_type.ts b/x-pack/plugins/fleet/public/hooks/use_package_icon_type.ts index c194d9914acff..a86c68c00c646 100644 --- a/x-pack/plugins/fleet/public/hooks/use_package_icon_type.ts +++ b/x-pack/plugins/fleet/public/hooks/use_package_icon_type.ts @@ -46,7 +46,7 @@ export const usePackageIconType = ({ setIconType(CACHED_ICONS.get(cacheKey) || ''); return; } - const svgIcons = (paramIcons || iconList)?.filter( + const svgIcons = (paramIcons && paramIcons.length ? paramIcons : iconList)?.filter( (iconDef) => iconDef.type === 'image/svg+xml' ); const localIconSrc = diff --git a/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts b/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts index 7b3007a61d248..33ef9afd3d8fd 100644 --- a/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts +++ b/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts @@ -33,6 +33,14 @@ export const useGetAgentPolicies = (query?: GetAgentPoliciesRequest['query']) => }); }; +export const sendGetAgentPolicies = (query?: GetAgentPoliciesRequest['query']) => { + return sendRequest({ + path: agentPolicyRouteService.getListPath(), + method: 'get', + query, + }); +}; + export const useGetOneAgentPolicy = (agentPolicyId: string | undefined) => { return useConditionalRequest({ path: agentPolicyId ? agentPolicyRouteService.getInfoPath(agentPolicyId) : undefined, diff --git a/x-pack/plugins/fleet/public/hooks/use_request/epm.ts b/x-pack/plugins/fleet/public/hooks/use_request/epm.ts index 8599b4f2c703c..650667000409a 100644 --- a/x-pack/plugins/fleet/public/hooks/use_request/epm.ts +++ b/x-pack/plugins/fleet/public/hooks/use_request/epm.ts @@ -5,6 +5,8 @@ * 2.0. */ +import useAsync from 'react-use/lib/useAsync'; + import { epmRouteService } from '../../services'; import type { GetCategoriesRequest, @@ -18,8 +20,15 @@ import type { } from '../../types'; import type { GetStatsResponse } from '../../../common'; +import { getCustomIntegrations } from '../../services/custom_integrations'; + import { useRequest, sendRequest } from './use_request'; +export function useGetAddableCustomIntegrations() { + const customIntegrations = getCustomIntegrations(); + return useAsync(customIntegrations.getAppendCustomIntegrations, []); +} + export const useGetCategories = (query: GetCategoriesRequest['query'] = {}) => { return useRequest({ path: epmRouteService.getCategoriesPath(), diff --git a/x-pack/plugins/fleet/public/hooks/use_request/package_policy.ts b/x-pack/plugins/fleet/public/hooks/use_request/package_policy.ts index d39b15a3b3bfa..f8d14647439b2 100644 --- a/x-pack/plugins/fleet/public/hooks/use_request/package_policy.ts +++ b/x-pack/plugins/fleet/public/hooks/use_request/package_policy.ts @@ -66,14 +66,23 @@ export const sendGetOnePackagePolicy = (packagePolicyId: string) => { }); }; -export function sendUpgradePackagePolicyDryRun(packagePolicyIds: string[]) { +export function sendUpgradePackagePolicyDryRun( + packagePolicyIds: string[], + packageVersion?: string +) { + const body: { packagePolicyIds: string[]; dryRun: boolean; packageVersion?: string } = { + packagePolicyIds, + dryRun: true, + }; + + if (packageVersion) { + body.packageVersion = packageVersion; + } + return sendRequest({ path: packagePolicyRouteService.getUpgradePath(), method: 'post', - body: JSON.stringify({ - packagePolicyIds, - dryRun: true, - }), + body: JSON.stringify(body), }); } diff --git a/x-pack/plugins/fleet/public/mock/plugin_dependencies.ts b/x-pack/plugins/fleet/public/mock/plugin_dependencies.ts index 5d1567936bcb0..5f3ee5c188b45 100644 --- a/x-pack/plugins/fleet/public/mock/plugin_dependencies.ts +++ b/x-pack/plugins/fleet/public/mock/plugin_dependencies.ts @@ -9,6 +9,7 @@ import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; import { licensingMock } from '../../../licensing/public/mocks'; import { homePluginMock } from '../../../../../src/plugins/home/public/mocks'; import { navigationPluginMock } from '../../../../../src/plugins/navigation/public/mocks'; +import { customIntegrationsMock } from '../../../../../src/plugins/custom_integrations/public/mocks'; import type { MockedFleetSetupDeps, MockedFleetStartDeps } from './types'; @@ -17,6 +18,7 @@ export const createSetupDepsMock = (): MockedFleetSetupDeps => { licensing: licensingMock.createSetup(), data: dataPluginMock.createSetupContract(), home: homePluginMock.createSetupContract(), + customIntegrations: customIntegrationsMock.createSetup(), }; }; diff --git a/x-pack/plugins/fleet/public/plugin.ts b/x-pack/plugins/fleet/public/plugin.ts index 2c723a3269737..b5a1983b6c974 100644 --- a/x-pack/plugins/fleet/public/plugin.ts +++ b/x-pack/plugins/fleet/public/plugin.ts @@ -17,6 +17,8 @@ import { i18n } from '@kbn/i18n'; import type { NavigationPublicPluginStart } from 'src/plugins/navigation/public'; import { DEFAULT_APP_CATEGORIES, AppNavLinkStatus } from '../../../../src/core/public'; +import type { CustomIntegrationsSetup } from '../../../../src/plugins/custom_integrations/public'; + import type { DataPublicPluginSetup, DataPublicPluginStart, @@ -47,6 +49,8 @@ import { LazyCustomLogsAssetsExtension } from './lazy_custom_logs_assets_extensi export { FleetConfigType } from '../common/types'; +import { setCustomIntegrations } from './services/custom_integrations'; + // We need to provide an object instead of void so that dependent plugins know when Fleet // is disabled. // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -66,6 +70,7 @@ export interface FleetSetupDeps { home?: HomePublicPluginSetup; cloud?: CloudSetup; globalSearch?: GlobalSearchPluginSetup; + customIntegrations: CustomIntegrationsSetup; } export interface FleetStartDeps { @@ -94,6 +99,8 @@ export class FleetPlugin implements Plugin { +export function isElasticsearchVersionConflictError(error: Error): boolean { return isESClientError(error) && error.meta.statusCode === 409; -}; +} diff --git a/x-pack/plugins/fleet/server/index.ts b/x-pack/plugins/fleet/server/index.ts index 21cdf659f2f5a..accd5e040f4f0 100644 --- a/x-pack/plugins/fleet/server/index.ts +++ b/x-pack/plugins/fleet/server/index.ts @@ -9,7 +9,11 @@ import { schema } from '@kbn/config-schema'; import type { TypeOf } from '@kbn/config-schema'; import type { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; -import { PreconfiguredPackagesSchema, PreconfiguredAgentPoliciesSchema } from './types'; +import { + PreconfiguredPackagesSchema, + PreconfiguredAgentPoliciesSchema, + PreconfiguredOutputsSchema, +} from './types'; import { FleetPlugin } from './plugin'; @@ -38,7 +42,8 @@ export const config: PluginConfigDescriptor = { epm: true, agents: true, }, - deprecations: ({ renameFromRoot, unused, unusedFromRoot }) => [ + deprecations: ({ deprecate, renameFromRoot, unused, unusedFromRoot }) => [ + deprecate('enabled', '8.0.0'), // Fleet plugin was named ingestManager before renameFromRoot('xpack.ingestManager.enabled', 'xpack.fleet.enabled'), renameFromRoot('xpack.ingestManager.registryUrl', 'xpack.fleet.registryUrl'), @@ -113,6 +118,7 @@ export const config: PluginConfigDescriptor = { }), packages: PreconfiguredPackagesSchema, agentPolicies: PreconfiguredAgentPoliciesSchema, + outputs: PreconfiguredOutputsSchema, agentIdVerificationEnabled: schema.boolean({ defaultValue: true }), }), }; diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts index a7cf606e92c0b..b3197d918d231 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts @@ -136,7 +136,7 @@ export const createAgentPolicyHandler: RequestHandler< }); } - await agentPolicyService.createFleetPolicyChangeAction(soClient, agentPolicy.id); + await agentPolicyService.createFleetServerPolicy(soClient, agentPolicy.id); const body: CreateAgentPolicyResponse = { item: agentPolicy, diff --git a/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts b/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts index 0e22f544ddfa3..bd82989a9e828 100644 --- a/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts @@ -11,17 +11,17 @@ import type { PostFleetSetupResponse } from '../../../common'; import { RegistryError } from '../../errors'; import { createAppContextStartContractMock, xpackMocks } from '../../mocks'; import { appContextService } from '../../services/app_context'; -import { setupIngestManager } from '../../services/setup'; +import { setupFleet } from '../../services/setup'; import { fleetSetupHandler } from './handlers'; jest.mock('../../services/setup', () => { return { - setupIngestManager: jest.fn(), + setupFleet: jest.fn(), }; }); -const mockSetupIngestManager = setupIngestManager as jest.MockedFunction; +const mockSetupFleet = setupFleet as jest.MockedFunction; describe('FleetSetupHandler', () => { let context: ReturnType; @@ -45,7 +45,7 @@ describe('FleetSetupHandler', () => { }); it('POST /setup succeeds w/200 and body of resolved value', async () => { - mockSetupIngestManager.mockImplementation(() => + mockSetupFleet.mockImplementation(() => Promise.resolve({ isInitialized: true, nonFatalErrors: [], @@ -59,9 +59,7 @@ describe('FleetSetupHandler', () => { }); it('POST /setup fails w/500 on custom error', async () => { - mockSetupIngestManager.mockImplementation(() => - Promise.reject(new Error('SO method mocked to throw')) - ); + mockSetupFleet.mockImplementation(() => Promise.reject(new Error('SO method mocked to throw'))); await fleetSetupHandler(context, request, response); expect(response.customError).toHaveBeenCalledTimes(1); @@ -74,7 +72,7 @@ describe('FleetSetupHandler', () => { }); it('POST /setup fails w/502 on RegistryError', async () => { - mockSetupIngestManager.mockImplementation(() => + mockSetupFleet.mockImplementation(() => Promise.reject(new RegistryError('Registry method mocked to throw')) ); diff --git a/x-pack/plugins/fleet/server/routes/setup/handlers.ts b/x-pack/plugins/fleet/server/routes/setup/handlers.ts index fe1e30f9f05d6..6311b9d970d35 100644 --- a/x-pack/plugins/fleet/server/routes/setup/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/setup/handlers.ts @@ -9,7 +9,7 @@ import type { RequestHandler } from 'src/core/server'; import { appContextService } from '../../services'; import type { GetFleetStatusResponse, PostFleetSetupResponse } from '../../../common'; -import { setupIngestManager } from '../../services/setup'; +import { setupFleet } from '../../services/setup'; import { hasFleetServers } from '../../services/fleet_server'; import { defaultIngestErrorHandler } from '../../errors'; @@ -46,7 +46,7 @@ export const fleetSetupHandler: RequestHandler = async (context, request, respon try { const soClient = context.core.savedObjects.client; const esClient = context.core.elasticsearch.client.asCurrentUser; - const setupStatus = await setupIngestManager(soClient, esClient); + const setupStatus = await setupFleet(soClient, esClient); const body: PostFleetSetupResponse = { ...setupStatus, nonFatalErrors: setupStatus.nonFatalErrors.map((e) => { diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 5c117909432b0..83188e0047044 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -156,6 +156,8 @@ const getSavedObjectTypes = ( revision: { type: 'integer' }, monitoring_enabled: { type: 'keyword', index: false }, is_preconfigured: { type: 'keyword' }, + data_output_id: { type: 'keyword' }, + monitoring_output_id: { type: 'keyword' }, }, }, migrations: { @@ -196,6 +198,7 @@ const getSavedObjectTypes = ( }, mappings: { properties: { + output_id: { type: 'keyword', index: false }, name: { type: 'keyword' }, type: { type: 'keyword' }, is_default: { type: 'boolean' }, @@ -203,6 +206,7 @@ const getSavedObjectTypes = ( ca_sha256: { type: 'keyword', index: false }, config: { type: 'flattened' }, config_yaml: { type: 'text' }, + is_preconfigured: { type: 'boolean', index: false }, }, }, migrations: { diff --git a/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap b/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap new file mode 100644 index 0000000000000..970bccbafa634 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap @@ -0,0 +1,292 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getFullAgentPolicy should support a different data output 1`] = ` +Object { + "agent": Object { + "monitoring": Object { + "enabled": true, + "logs": false, + "metrics": true, + "namespace": "default", + "use_output": "default", + }, + }, + "fleet": Object { + "hosts": Array [ + "http://fleetserver:8220", + ], + }, + "id": "agent-policy", + "inputs": Array [], + "output_permissions": Object { + "data-output-id": Object { + "_elastic_agent_checks": Object { + "cluster": Array [ + "monitor", + ], + }, + "_fallback": Object { + "cluster": Array [ + "monitor", + ], + "indices": Array [ + Object { + "names": Array [ + "logs-*", + "metrics-*", + "traces-*", + "synthetics-*", + ".logs-endpoint.diagnostic.collection-*", + ], + "privileges": Array [ + "auto_configure", + "create_doc", + ], + }, + ], + }, + }, + "default": Object { + "_elastic_agent_checks": Object { + "cluster": Array [ + "monitor", + ], + "indices": Array [ + Object { + "names": Array [ + "metrics-elastic_agent-default", + "metrics-elastic_agent.elastic_agent-default", + "metrics-elastic_agent.apm_server-default", + "metrics-elastic_agent.filebeat-default", + "metrics-elastic_agent.fleet_server-default", + "metrics-elastic_agent.metricbeat-default", + "metrics-elastic_agent.osquerybeat-default", + "metrics-elastic_agent.packetbeat-default", + "metrics-elastic_agent.endpoint_security-default", + "metrics-elastic_agent.auditbeat-default", + "metrics-elastic_agent.heartbeat-default", + ], + "privileges": Array [ + "auto_configure", + "create_doc", + ], + }, + ], + }, + }, + }, + "outputs": Object { + "data-output-id": Object { + "api_key": undefined, + "ca_sha256": undefined, + "hosts": Array [ + "http://es-data.co:9201", + ], + "type": "elasticsearch", + }, + "default": Object { + "api_key": undefined, + "ca_sha256": undefined, + "hosts": Array [ + "http://127.0.0.1:9201", + ], + "type": "elasticsearch", + }, + }, + "revision": 1, +} +`; + +exports[`getFullAgentPolicy should support a different monitoring output 1`] = ` +Object { + "agent": Object { + "monitoring": Object { + "enabled": true, + "logs": false, + "metrics": true, + "namespace": "default", + "use_output": "monitoring-output-id", + }, + }, + "fleet": Object { + "hosts": Array [ + "http://fleetserver:8220", + ], + }, + "id": "agent-policy", + "inputs": Array [], + "output_permissions": Object { + "default": Object { + "_elastic_agent_checks": Object { + "cluster": Array [ + "monitor", + ], + }, + "_fallback": Object { + "cluster": Array [ + "monitor", + ], + "indices": Array [ + Object { + "names": Array [ + "logs-*", + "metrics-*", + "traces-*", + "synthetics-*", + ".logs-endpoint.diagnostic.collection-*", + ], + "privileges": Array [ + "auto_configure", + "create_doc", + ], + }, + ], + }, + }, + "monitoring-output-id": Object { + "_elastic_agent_checks": Object { + "cluster": Array [ + "monitor", + ], + "indices": Array [ + Object { + "names": Array [ + "metrics-elastic_agent-default", + "metrics-elastic_agent.elastic_agent-default", + "metrics-elastic_agent.apm_server-default", + "metrics-elastic_agent.filebeat-default", + "metrics-elastic_agent.fleet_server-default", + "metrics-elastic_agent.metricbeat-default", + "metrics-elastic_agent.osquerybeat-default", + "metrics-elastic_agent.packetbeat-default", + "metrics-elastic_agent.endpoint_security-default", + "metrics-elastic_agent.auditbeat-default", + "metrics-elastic_agent.heartbeat-default", + ], + "privileges": Array [ + "auto_configure", + "create_doc", + ], + }, + ], + }, + }, + }, + "outputs": Object { + "default": Object { + "api_key": undefined, + "ca_sha256": undefined, + "hosts": Array [ + "http://127.0.0.1:9201", + ], + "type": "elasticsearch", + }, + "monitoring-output-id": Object { + "api_key": undefined, + "ca_sha256": undefined, + "hosts": Array [ + "http://es-monitoring.co:9201", + ], + "type": "elasticsearch", + }, + }, + "revision": 1, +} +`; + +exports[`getFullAgentPolicy should support both different outputs for data and monitoring 1`] = ` +Object { + "agent": Object { + "monitoring": Object { + "enabled": true, + "logs": false, + "metrics": true, + "namespace": "default", + "use_output": "monitoring-output-id", + }, + }, + "fleet": Object { + "hosts": Array [ + "http://fleetserver:8220", + ], + }, + "id": "agent-policy", + "inputs": Array [], + "output_permissions": Object { + "data-output-id": Object { + "_elastic_agent_checks": Object { + "cluster": Array [ + "monitor", + ], + }, + "_fallback": Object { + "cluster": Array [ + "monitor", + ], + "indices": Array [ + Object { + "names": Array [ + "logs-*", + "metrics-*", + "traces-*", + "synthetics-*", + ".logs-endpoint.diagnostic.collection-*", + ], + "privileges": Array [ + "auto_configure", + "create_doc", + ], + }, + ], + }, + }, + "monitoring-output-id": Object { + "_elastic_agent_checks": Object { + "cluster": Array [ + "monitor", + ], + "indices": Array [ + Object { + "names": Array [ + "metrics-elastic_agent-default", + "metrics-elastic_agent.elastic_agent-default", + "metrics-elastic_agent.apm_server-default", + "metrics-elastic_agent.filebeat-default", + "metrics-elastic_agent.fleet_server-default", + "metrics-elastic_agent.metricbeat-default", + "metrics-elastic_agent.osquerybeat-default", + "metrics-elastic_agent.packetbeat-default", + "metrics-elastic_agent.endpoint_security-default", + "metrics-elastic_agent.auditbeat-default", + "metrics-elastic_agent.heartbeat-default", + ], + "privileges": Array [ + "auto_configure", + "create_doc", + ], + }, + ], + }, + }, + }, + "outputs": Object { + "data-output-id": Object { + "api_key": undefined, + "ca_sha256": undefined, + "hosts": Array [ + "http://es-data.co:9201", + ], + "type": "elasticsearch", + }, + "monitoring-output-id": Object { + "api_key": undefined, + "ca_sha256": undefined, + "hosts": Array [ + "http://es-monitoring.co:9201", + ], + "type": "elasticsearch", + }, + }, + "revision": 1, +} +`; diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts new file mode 100644 index 0000000000000..8df1234982ee6 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts @@ -0,0 +1,256 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { savedObjectsClientMock } from 'src/core/server/mocks'; + +import type { AgentPolicy, Output } from '../../types'; + +import { agentPolicyService } from '../agent_policy'; +import { agentPolicyUpdateEventHandler } from '../agent_policy_update'; + +import { getFullAgentPolicy } from './full_agent_policy'; + +const mockedAgentPolicyService = agentPolicyService as jest.Mocked; + +function mockAgentPolicy(data: Partial) { + mockedAgentPolicyService.get.mockResolvedValue({ + id: 'agent-policy', + status: 'active', + package_policies: [], + is_managed: false, + namespace: 'default', + revision: 1, + name: 'Policy', + updated_at: '2020-01-01', + updated_by: 'qwerty', + ...data, + }); +} + +jest.mock('../settings', () => { + return { + getSettings: () => { + return { + id: '93f74c0-e876-11ea-b7d3-8b2acec6f75c', + fleet_server_hosts: ['http://fleetserver:8220'], + }; + }, + }; +}); + +jest.mock('../agent_policy'); + +jest.mock('../output', () => { + return { + outputService: { + getDefaultOutputId: () => 'test-id', + get: (soClient: any, id: string): Output => { + switch (id) { + case 'data-output-id': + return { + id: 'data-output-id', + is_default: false, + name: 'Data output', + // @ts-ignore + type: 'elasticsearch', + hosts: ['http://es-data.co:9201'], + }; + case 'monitoring-output-id': + return { + id: 'monitoring-output-id', + is_default: false, + name: 'Monitoring output', + // @ts-ignore + type: 'elasticsearch', + hosts: ['http://es-monitoring.co:9201'], + }; + default: + return { + id: 'test-id', + is_default: true, + name: 'default', + // @ts-ignore + type: 'elasticsearch', + hosts: ['http://127.0.0.1:9201'], + }; + } + }, + }, + }; +}); + +jest.mock('../agent_policy_update'); +jest.mock('../agents'); +jest.mock('../package_policy'); + +function getAgentPolicyUpdateMock() { + return agentPolicyUpdateEventHandler as unknown as jest.Mock< + typeof agentPolicyUpdateEventHandler + >; +} + +describe('getFullAgentPolicy', () => { + beforeEach(() => { + getAgentPolicyUpdateMock().mockClear(); + mockedAgentPolicyService.get.mockReset(); + }); + + it('should return a policy without monitoring if monitoring is not enabled', async () => { + mockAgentPolicy({ + revision: 1, + }); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy).toMatchObject({ + id: 'agent-policy', + outputs: { + default: { + type: 'elasticsearch', + hosts: ['http://127.0.0.1:9201'], + ca_sha256: undefined, + api_key: undefined, + }, + }, + inputs: [], + revision: 1, + fleet: { + hosts: ['http://fleetserver:8220'], + }, + agent: { + monitoring: { + enabled: false, + logs: false, + metrics: false, + }, + }, + }); + }); + + it('should return a policy with monitoring if monitoring is enabled for logs', async () => { + mockAgentPolicy({ + namespace: 'default', + revision: 1, + monitoring_enabled: ['logs'], + }); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy).toMatchObject({ + id: 'agent-policy', + outputs: { + default: { + type: 'elasticsearch', + hosts: ['http://127.0.0.1:9201'], + ca_sha256: undefined, + api_key: undefined, + }, + }, + inputs: [], + revision: 1, + fleet: { + hosts: ['http://fleetserver:8220'], + }, + agent: { + monitoring: { + namespace: 'default', + use_output: 'default', + enabled: true, + logs: true, + metrics: false, + }, + }, + }); + }); + + it('should return a policy with monitoring if monitoring is enabled for metrics', async () => { + mockAgentPolicy({ + namespace: 'default', + revision: 1, + monitoring_enabled: ['metrics'], + }); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy).toMatchObject({ + id: 'agent-policy', + outputs: { + default: { + type: 'elasticsearch', + hosts: ['http://127.0.0.1:9201'], + ca_sha256: undefined, + api_key: undefined, + }, + }, + inputs: [], + revision: 1, + fleet: { + hosts: ['http://fleetserver:8220'], + }, + agent: { + monitoring: { + namespace: 'default', + use_output: 'default', + enabled: true, + logs: false, + metrics: true, + }, + }, + }); + }); + + it('should support a different monitoring output', async () => { + mockAgentPolicy({ + namespace: 'default', + revision: 1, + monitoring_enabled: ['metrics'], + monitoring_output_id: 'monitoring-output-id', + }); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy).toMatchSnapshot(); + }); + + it('should support a different data output', async () => { + mockAgentPolicy({ + namespace: 'default', + revision: 1, + monitoring_enabled: ['metrics'], + data_output_id: 'data-output-id', + }); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy).toMatchSnapshot(); + }); + + it('should support both different outputs for data and monitoring ', async () => { + mockAgentPolicy({ + namespace: 'default', + revision: 1, + monitoring_enabled: ['metrics'], + data_output_id: 'data-output-id', + monitoring_output_id: 'monitoring-output-id', + }); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy).toMatchSnapshot(); + }); + + it('should use "default" as the default policy id', async () => { + mockAgentPolicy({ + id: 'policy', + status: 'active', + package_policies: [], + is_managed: false, + namespace: 'default', + revision: 1, + data_output_id: 'test-id', + monitoring_output_id: 'test-id', + }); + + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy?.outputs.default).toBeDefined(); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts new file mode 100644 index 0000000000000..4e8b3a2c1952e --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts @@ -0,0 +1,229 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SavedObjectsClientContract } from 'kibana/server'; +import { safeLoad } from 'js-yaml'; + +import type { + FullAgentPolicy, + PackagePolicy, + Settings, + Output, + FullAgentPolicyOutput, +} from '../../types'; +import { agentPolicyService } from '../agent_policy'; +import { outputService } from '../output'; +import { + storedPackagePoliciesToAgentPermissions, + DEFAULT_PERMISSIONS, +} from '../package_policies_to_agent_permissions'; +import { storedPackagePoliciesToAgentInputs, dataTypes, outputType } from '../../../common'; +import type { FullAgentPolicyOutputPermissions } from '../../../common'; +import { getSettings } from '../settings'; +import { PACKAGE_POLICY_DEFAULT_INDEX_PRIVILEGES, DEFAULT_OUTPUT } from '../../constants'; + +const MONITORING_DATASETS = [ + 'elastic_agent', + 'elastic_agent.elastic_agent', + 'elastic_agent.apm_server', + 'elastic_agent.filebeat', + 'elastic_agent.fleet_server', + 'elastic_agent.metricbeat', + 'elastic_agent.osquerybeat', + 'elastic_agent.packetbeat', + 'elastic_agent.endpoint_security', + 'elastic_agent.auditbeat', + 'elastic_agent.heartbeat', +]; + +export async function getFullAgentPolicy( + soClient: SavedObjectsClientContract, + id: string, + options?: { standalone: boolean } +): Promise { + let agentPolicy; + const standalone = options?.standalone; + + try { + agentPolicy = await agentPolicyService.get(soClient, id); + } catch (err) { + if (!err.isBoom || err.output.statusCode !== 404) { + throw err; + } + } + + if (!agentPolicy) { + return null; + } + + const defaultOutputId = await outputService.getDefaultOutputId(soClient); + if (!defaultOutputId) { + throw new Error('Default output is not setup'); + } + + const dataOutputId = agentPolicy.data_output_id || defaultOutputId; + const monitoringOutputId = agentPolicy.monitoring_output_id || defaultOutputId; + + const outputs = await Promise.all( + Array.from(new Set([dataOutputId, monitoringOutputId])).map((outputId) => + outputService.get(soClient, outputId) + ) + ); + + const dataOutput = outputs.find((output) => output.id === dataOutputId); + if (!dataOutput) { + throw new Error(`Data output not found ${dataOutputId}`); + } + const monitoringOutput = outputs.find((output) => output.id === monitoringOutputId); + if (!monitoringOutput) { + throw new Error(`Monitoring output not found ${monitoringOutputId}`); + } + + const fullAgentPolicy: FullAgentPolicy = { + id: agentPolicy.id, + outputs: { + ...outputs.reduce((acc, output) => { + acc[getOutputIdForAgentPolicy(output)] = transformOutputToFullPolicyOutput(output); + + return acc; + }, {}), + }, + inputs: storedPackagePoliciesToAgentInputs( + agentPolicy.package_policies as PackagePolicy[], + getOutputIdForAgentPolicy(dataOutput) + ), + revision: agentPolicy.revision, + ...(agentPolicy.monitoring_enabled && agentPolicy.monitoring_enabled.length > 0 + ? { + agent: { + monitoring: { + namespace: agentPolicy.namespace, + use_output: getOutputIdForAgentPolicy(monitoringOutput), + enabled: true, + logs: agentPolicy.monitoring_enabled.includes(dataTypes.Logs), + metrics: agentPolicy.monitoring_enabled.includes(dataTypes.Metrics), + }, + }, + } + : { + agent: { + monitoring: { enabled: false, logs: false, metrics: false }, + }, + }), + }; + + const dataPermissions = (await storedPackagePoliciesToAgentPermissions( + soClient, + agentPolicy.package_policies + )) || { _fallback: DEFAULT_PERMISSIONS }; + + dataPermissions._elastic_agent_checks = { + cluster: DEFAULT_PERMISSIONS.cluster, + }; + + // TODO: fetch this from the elastic agent package https://github.com/elastic/kibana/issues/107738 + const monitoringNamespace = fullAgentPolicy.agent?.monitoring.namespace; + const monitoringPermissions: FullAgentPolicyOutputPermissions = + monitoringOutputId === dataOutputId + ? dataPermissions + : { + _elastic_agent_checks: { + cluster: DEFAULT_PERMISSIONS.cluster, + }, + }; + if ( + fullAgentPolicy.agent?.monitoring.enabled && + monitoringNamespace && + monitoringOutput && + monitoringOutput.type === outputType.Elasticsearch + ) { + let names: string[] = []; + if (fullAgentPolicy.agent.monitoring.logs) { + names = names.concat( + MONITORING_DATASETS.map((dataset) => `logs-${dataset}-${monitoringNamespace}`) + ); + } + if (fullAgentPolicy.agent.monitoring.metrics) { + names = names.concat( + MONITORING_DATASETS.map((dataset) => `metrics-${dataset}-${monitoringNamespace}`) + ); + } + + monitoringPermissions._elastic_agent_checks.indices = [ + { + names, + privileges: PACKAGE_POLICY_DEFAULT_INDEX_PRIVILEGES, + }, + ]; + } + + // Only add permissions if output.type is "elasticsearch" + fullAgentPolicy.output_permissions = Object.keys(fullAgentPolicy.outputs).reduce< + NonNullable + >((outputPermissions, outputId) => { + const output = fullAgentPolicy.outputs[outputId]; + if (output && output.type === outputType.Elasticsearch) { + outputPermissions[outputId] = + outputId === getOutputIdForAgentPolicy(dataOutput) + ? dataPermissions + : monitoringPermissions; + } + return outputPermissions; + }, {}); + + // only add settings if not in standalone + if (!standalone) { + let settings: Settings; + try { + settings = await getSettings(soClient); + } catch (error) { + throw new Error('Default settings is not setup'); + } + if (settings.fleet_server_hosts && settings.fleet_server_hosts.length) { + fullAgentPolicy.fleet = { + hosts: settings.fleet_server_hosts, + }; + } + } + return fullAgentPolicy; +} + +function transformOutputToFullPolicyOutput( + output: Output, + standalone = false +): FullAgentPolicyOutput { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { config_yaml, type, hosts, ca_sha256, api_key } = output; + const configJs = config_yaml ? safeLoad(config_yaml) : {}; + const newOutput: FullAgentPolicyOutput = { + type, + hosts, + ca_sha256, + api_key, + ...configJs, + }; + + if (standalone) { + delete newOutput.api_key; + newOutput.username = 'ES_USERNAME'; + newOutput.password = 'ES_PASSWORD'; + } + + return newOutput; +} + +/** + * Get id used in full agent policy (sent to the agents) + * we use "default" for the default policy to avoid breaking changes + */ +function getOutputIdForAgentPolicy(output: Output) { + if (output.is_default) { + return DEFAULT_OUTPUT.name; + } + + return output.id; +} diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/index.ts b/x-pack/plugins/fleet/server/services/agent_policies/index.ts similarity index 72% rename from x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/index.ts rename to x-pack/plugins/fleet/server/services/agent_policies/index.ts index e4c8858321e14..b793ed26a08b5 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/index.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/index.ts @@ -5,5 +5,4 @@ * 2.0. */ -export { timelinesMigrations } from './timelines'; -export { notesMigrations } from './notes'; +export { getFullAgentPolicy } from './full_agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index 59e0f6fd7840e..5617f8ef7bd7c 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -7,13 +7,16 @@ import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; -import type { AgentPolicy, NewAgentPolicy, Output } from '../types'; +import type { AgentPolicy, FullAgentPolicy, NewAgentPolicy } from '../types'; import { agentPolicyService } from './agent_policy'; import { agentPolicyUpdateEventHandler } from './agent_policy_update'; import { getAgentsByKuery } from './agents'; import { packagePolicyService } from './package_policy'; +import { appContextService } from './app_context'; +import { outputService } from './output'; +import { getFullAgentPolicy } from './agent_policies'; function getSavedObjectMock(agentPolicyAttributes: any) { const mock = savedObjectsClientMock.create(); @@ -47,27 +50,18 @@ function getSavedObjectMock(agentPolicyAttributes: any) { return mock; } -jest.mock('./output', () => { - return { - outputService: { - getDefaultOutputId: () => 'test-id', - get: (): Output => { - return { - id: 'test-id', - is_default: true, - name: 'default', - // @ts-ignore - type: 'elasticsearch', - hosts: ['http://127.0.0.1:9201'], - }; - }, - }, - }; -}); - +jest.mock('./output'); jest.mock('./agent_policy_update'); jest.mock('./agents'); jest.mock('./package_policy'); +jest.mock('./app_context'); +jest.mock('./agent_policies/full_agent_policy'); + +const mockedAppContextService = appContextService as jest.Mocked; +const mockedOutputService = outputService as jest.Mocked; +const mockedGetFullAgentPolicy = getFullAgentPolicy as jest.Mock< + ReturnType +>; function getAgentPolicyUpdateMock() { return agentPolicyUpdateEventHandler as unknown as jest.Mock< @@ -186,106 +180,17 @@ describe('agent policy', () => { }); }); - describe('getFullAgentPolicy', () => { - it('should return a policy without monitoring if monitoring is not enabled', async () => { + describe('bumpAllAgentPoliciesForOutput', () => { + it('should call agentPolicyUpdateEventHandler with updated event once', async () => { const soClient = getSavedObjectMock({ revision: 1, + monitoring_enabled: ['metrics'], }); - const agentPolicy = await agentPolicyService.getFullAgentPolicy(soClient, 'agent-policy'); - - expect(agentPolicy).toMatchObject({ - id: 'agent-policy', - outputs: { - default: { - type: 'elasticsearch', - hosts: ['http://127.0.0.1:9201'], - ca_sha256: undefined, - api_key: undefined, - }, - }, - inputs: [], - revision: 1, - fleet: { - hosts: ['http://fleetserver:8220'], - }, - agent: { - monitoring: { - enabled: false, - logs: false, - metrics: false, - }, - }, - }); - }); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - it('should return a policy with monitoring if monitoring is enabled for logs', async () => { - const soClient = getSavedObjectMock({ - namespace: 'default', - revision: 1, - monitoring_enabled: ['logs'], - }); - const agentPolicy = await agentPolicyService.getFullAgentPolicy(soClient, 'agent-policy'); - - expect(agentPolicy).toMatchObject({ - id: 'agent-policy', - outputs: { - default: { - type: 'elasticsearch', - hosts: ['http://127.0.0.1:9201'], - ca_sha256: undefined, - api_key: undefined, - }, - }, - inputs: [], - revision: 1, - fleet: { - hosts: ['http://fleetserver:8220'], - }, - agent: { - monitoring: { - namespace: 'default', - use_output: 'default', - enabled: true, - logs: true, - metrics: false, - }, - }, - }); - }); + await agentPolicyService.bumpAllAgentPoliciesForOutput(soClient, esClient, 'output-id-123'); - it('should return a policy with monitoring if monitoring is enabled for metrics', async () => { - const soClient = getSavedObjectMock({ - namespace: 'default', - revision: 1, - monitoring_enabled: ['metrics'], - }); - const agentPolicy = await agentPolicyService.getFullAgentPolicy(soClient, 'agent-policy'); - - expect(agentPolicy).toMatchObject({ - id: 'agent-policy', - outputs: { - default: { - type: 'elasticsearch', - hosts: ['http://127.0.0.1:9201'], - ca_sha256: undefined, - api_key: undefined, - }, - }, - inputs: [], - revision: 1, - fleet: { - hosts: ['http://fleetserver:8220'], - }, - agent: { - monitoring: { - namespace: 'default', - use_output: 'default', - enabled: true, - logs: false, - metrics: true, - }, - }, - }); + expect(agentPolicyUpdateEventHandler).toHaveBeenCalledTimes(1); }); }); @@ -321,4 +226,64 @@ describe('agent policy', () => { expect(calledWith[2]).toHaveProperty('is_managed', true); }); }); + + describe('createFleetServerPolicy', () => { + beforeEach(() => { + mockedGetFullAgentPolicy.mockReset(); + }); + it('should not create a .fleet-policy document if we cannot get the full policy', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + mockedAppContextService.getInternalUserESClient.mockReturnValue(esClient); + mockedOutputService.getDefaultOutputId.mockResolvedValue('default-output'); + mockedGetFullAgentPolicy.mockResolvedValue(null); + + soClient.get.mockResolvedValue({ + attributes: {}, + id: 'policy123', + type: 'mocked', + references: [], + }); + await agentPolicyService.createFleetServerPolicy(soClient, 'policy123'); + + expect(esClient.create).not.toBeCalled(); + }); + + it('should create a .fleet-policy document if we can get the full policy', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + mockedAppContextService.getInternalUserESClient.mockReturnValue(esClient); + mockedOutputService.getDefaultOutputId.mockResolvedValue('default-output'); + mockedGetFullAgentPolicy.mockResolvedValue({ + id: 'policy123', + revision: 1, + inputs: [ + { + id: 'input-123', + }, + ], + } as FullAgentPolicy); + + soClient.get.mockResolvedValue({ + attributes: {}, + id: 'policy123', + type: 'mocked', + references: [], + }); + await agentPolicyService.createFleetServerPolicy(soClient, 'policy123'); + + expect(esClient.create).toBeCalledWith( + expect.objectContaining({ + index: '.fleet-policies', + body: expect.objectContaining({ + '@timestamp': expect.anything(), + data: { id: 'policy123', inputs: [{ id: 'input-123' }], revision: 1 }, + default_fleet_server: false, + policy_id: 'policy123', + revision_idx: 1, + }), + }) + ); + }); + }); }); diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 38fb07754bdd3..6ebe890aeaef2 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -6,7 +6,6 @@ */ import { uniq, omit } from 'lodash'; -import { safeLoad } from 'js-yaml'; import uuid from 'uuid/v4'; import type { ElasticsearchClient, @@ -21,7 +20,6 @@ import { AGENT_POLICY_SAVED_OBJECT_TYPE, AGENT_SAVED_OBJECT_TYPE, PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, - PACKAGE_POLICY_DEFAULT_INDEX_PRIVILEGES, } from '../constants'; import type { PackagePolicy, @@ -33,52 +31,27 @@ import type { ListWithKuery, NewPackagePolicy, } from '../types'; -import { - agentPolicyStatuses, - storedPackagePoliciesToAgentInputs, - dataTypes, - packageToPackagePolicy, - AGENT_POLICY_INDEX, -} from '../../common'; +import { agentPolicyStatuses, packageToPackagePolicy, AGENT_POLICY_INDEX } from '../../common'; import type { DeleteAgentPolicyResponse, - Settings, FleetServerPolicy, Installation, Output, DeletePackagePoliciesResponse, } from '../../common'; import { AgentPolicyNameExistsError, HostedAgentPolicyRestrictionRelatedError } from '../errors'; -import { - storedPackagePoliciesToAgentPermissions, - DEFAULT_PERMISSIONS, -} from '../services/package_policies_to_agent_permissions'; import { getPackageInfo } from './epm/packages'; import { getAgentsByKuery } from './agents'; import { packagePolicyService } from './package_policy'; import { outputService } from './output'; import { agentPolicyUpdateEventHandler } from './agent_policy_update'; -import { getSettings } from './settings'; import { normalizeKuery, escapeSearchQueryPhrase } from './saved_object'; import { appContextService } from './app_context'; +import { getFullAgentPolicy } from './agent_policies'; const SAVED_OBJECT_TYPE = AGENT_POLICY_SAVED_OBJECT_TYPE; -const MONITORING_DATASETS = [ - 'elastic_agent', - 'elastic_agent.elastic_agent', - 'elastic_agent.apm_server', - 'elastic_agent.filebeat', - 'elastic_agent.fleet_server', - 'elastic_agent.metricbeat', - 'elastic_agent.osquerybeat', - 'elastic_agent.packetbeat', - 'elastic_agent.endpoint_security', - 'elastic_agent.auditbeat', - 'elastic_agent.heartbeat', -]; - class AgentPolicyService { private triggerAgentPolicyUpdatedEvent = async ( soClient: SavedObjectsClientContract, @@ -456,7 +429,7 @@ class AgentPolicyService { throw new Error('Copied agent policy not found'); } - await this.createFleetPolicyChangeAction(soClient, newAgentPolicy.id); + await this.createFleetServerPolicy(soClient, newAgentPolicy.id); return updatedAgentPolicy; } @@ -472,6 +445,38 @@ class AgentPolicyService { return res; } + public async bumpAllAgentPoliciesForOutput( + soClient: SavedObjectsClientContract, + esClient: ElasticsearchClient, + outputId: string, + options?: { user?: AuthenticatedUser } + ): Promise> { + const currentPolicies = await soClient.find({ + type: SAVED_OBJECT_TYPE, + fields: ['revision', 'data_output_id', 'monitoring_output_id'], + searchFields: ['data_output_id', 'monitoring_output_id'], + search: escapeSearchQueryPhrase(outputId), + }); + const bumpedPolicies = currentPolicies.saved_objects.map((policy) => { + policy.attributes = { + ...policy.attributes, + revision: policy.attributes.revision + 1, + updated_at: new Date().toISOString(), + updated_by: options?.user ? options.user.username : 'system', + }; + return policy; + }); + const res = await soClient.bulkUpdate(bumpedPolicies); + + await Promise.all( + currentPolicies.saved_objects.map((policy) => + this.triggerAgentPolicyUpdatedEvent(soClient, esClient, 'updated', policy.id) + ) + ); + + return res; + } + public async bumpAllAgentPolicies( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, @@ -650,10 +655,11 @@ class AgentPolicyService { }; } - public async createFleetPolicyChangeAction( + public async createFleetServerPolicy( soClient: SavedObjectsClientContract, agentPolicyId: string ) { + // Use internal ES client so we have permissions to write to .fleet* indices const esClient = appContextService.getInternalUserESClient(); const defaultOutputId = await outputService.getDefaultOutputId(soClient); @@ -661,14 +667,6 @@ class AgentPolicyService { return; } - await this.createFleetPolicyChangeFleetServer(soClient, esClient, agentPolicyId); - } - - public async createFleetPolicyChangeFleetServer( - soClient: SavedObjectsClientContract, - esClient: ElasticsearchClient, - agentPolicyId: string - ) { const policy = await agentPolicyService.get(soClient, agentPolicyId); const fullPolicy = await agentPolicyService.getFullAgentPolicy(soClient, agentPolicyId); if (!policy || !fullPolicy || !fullPolicy.revision) { @@ -724,139 +722,7 @@ class AgentPolicyService { id: string, options?: { standalone: boolean } ): Promise { - let agentPolicy; - const standalone = options?.standalone; - - try { - agentPolicy = await this.get(soClient, id); - } catch (err) { - if (!err.isBoom || err.output.statusCode !== 404) { - throw err; - } - } - - if (!agentPolicy) { - return null; - } - - const defaultOutputId = await outputService.getDefaultOutputId(soClient); - if (!defaultOutputId) { - throw new Error('Default output is not setup'); - } - const defaultOutput = await outputService.get(soClient, defaultOutputId); - - const fullAgentPolicy: FullAgentPolicy = { - id: agentPolicy.id, - outputs: { - // TEMPORARY as we only support a default output - ...[defaultOutput].reduce( - // eslint-disable-next-line @typescript-eslint/naming-convention - (outputs, { config_yaml, name, type, hosts, ca_sha256, api_key }) => { - const configJs = config_yaml ? safeLoad(config_yaml) : {}; - outputs[name] = { - type, - hosts, - ca_sha256, - api_key, - ...configJs, - }; - - if (options?.standalone) { - delete outputs[name].api_key; - outputs[name].username = 'ES_USERNAME'; - outputs[name].password = 'ES_PASSWORD'; - } - - return outputs; - }, - {} - ), - }, - inputs: storedPackagePoliciesToAgentInputs(agentPolicy.package_policies as PackagePolicy[]), - revision: agentPolicy.revision, - ...(agentPolicy.monitoring_enabled && agentPolicy.monitoring_enabled.length > 0 - ? { - agent: { - monitoring: { - namespace: agentPolicy.namespace, - use_output: defaultOutput.name, - enabled: true, - logs: agentPolicy.monitoring_enabled.includes(dataTypes.Logs), - metrics: agentPolicy.monitoring_enabled.includes(dataTypes.Metrics), - }, - }, - } - : { - agent: { - monitoring: { enabled: false, logs: false, metrics: false }, - }, - }), - }; - - const permissions = (await storedPackagePoliciesToAgentPermissions( - soClient, - agentPolicy.package_policies - )) || { _fallback: DEFAULT_PERMISSIONS }; - - permissions._elastic_agent_checks = { - cluster: DEFAULT_PERMISSIONS.cluster, - }; - - // TODO: fetch this from the elastic agent package - const monitoringOutput = fullAgentPolicy.agent?.monitoring.use_output; - const monitoringNamespace = fullAgentPolicy.agent?.monitoring.namespace; - if ( - fullAgentPolicy.agent?.monitoring.enabled && - monitoringNamespace && - monitoringOutput && - fullAgentPolicy.outputs[monitoringOutput]?.type === 'elasticsearch' - ) { - let names: string[] = []; - if (fullAgentPolicy.agent.monitoring.logs) { - names = names.concat( - MONITORING_DATASETS.map((dataset) => `logs-${dataset}-${monitoringNamespace}`) - ); - } - if (fullAgentPolicy.agent.monitoring.metrics) { - names = names.concat( - MONITORING_DATASETS.map((dataset) => `metrics-${dataset}-${monitoringNamespace}`) - ); - } - - permissions._elastic_agent_checks.indices = [ - { - names, - privileges: PACKAGE_POLICY_DEFAULT_INDEX_PRIVILEGES, - }, - ]; - } - - // Only add permissions if output.type is "elasticsearch" - fullAgentPolicy.output_permissions = Object.keys(fullAgentPolicy.outputs).reduce< - NonNullable - >((outputPermissions, outputName) => { - const output = fullAgentPolicy.outputs[outputName]; - if (output && output.type === 'elasticsearch') { - outputPermissions[outputName] = permissions; - } - return outputPermissions; - }, {}); - - // only add settings if not in standalone - if (!standalone) { - let settings: Settings; - try { - settings = await getSettings(soClient); - } catch (error) { - throw new Error('Default settings is not setup'); - } - if (settings.fleet_server_hosts && settings.fleet_server_hosts.length) { - fullAgentPolicy.fleet = { - hosts: settings.fleet_server_hosts, - }; - } - } - return fullAgentPolicy; + return getFullAgentPolicy(soClient, id, options); } } diff --git a/x-pack/plugins/fleet/server/services/agent_policy_update.ts b/x-pack/plugins/fleet/server/services/agent_policy_update.ts index 9703467d84c18..51bf068b8b111 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_update.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_update.ts @@ -43,11 +43,11 @@ export async function agentPolicyUpdateEventHandler( name: 'Default', agentPolicyId, }); - await agentPolicyService.createFleetPolicyChangeAction(internalSoClient, agentPolicyId); + await agentPolicyService.createFleetServerPolicy(internalSoClient, agentPolicyId); } if (action === 'updated') { - await agentPolicyService.createFleetPolicyChangeAction(internalSoClient, agentPolicyId); + await agentPolicyService.createFleetServerPolicy(internalSoClient, agentPolicyId); } if (action === 'deleted') { diff --git a/x-pack/plugins/fleet/server/services/agents/setup.ts b/x-pack/plugins/fleet/server/services/agents/setup.ts index 81ae6b177783d..2b680dee1146e 100644 --- a/x-pack/plugins/fleet/server/services/agents/setup.ts +++ b/x-pack/plugins/fleet/server/services/agents/setup.ts @@ -11,12 +11,9 @@ import { SO_SEARCH_LIMIT } from '../../constants'; import { agentPolicyService } from '../agent_policy'; /** - * During the migration from 7.9 to 7.10 we introduce a new agent action POLICY_CHANGE per policy - * this function ensure that action exist for each policy - * - * @param soClient + * Ensure a .fleet-policy document exist for each agent policy so Fleet server can retrieve it */ -export async function ensureAgentActionPolicyChangeExists( +export async function ensureFleetServerAgentPoliciesExists( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient ) { @@ -32,7 +29,7 @@ export async function ensureAgentActionPolicyChangeExists( )); if (!policyChangeActionExist) { - return agentPolicyService.createFleetPolicyChangeAction(soClient, agentPolicy.id); + return agentPolicyService.createFleetServerPolicy(soClient, agentPolicy.id); } }) ); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/cleanup.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/cleanup.test.ts new file mode 100644 index 0000000000000..482e42a46060e --- /dev/null +++ b/x-pack/plugins/fleet/server/services/epm/packages/cleanup.test.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SavedObjectsClientContract } from 'kibana/server'; +import { savedObjectsClientMock } from 'src/core/server/mocks'; + +import type { PackagePolicyServiceInterface } from '../../package_policy'; +import * as storage from '../archive/storage'; +import { packagePolicyService } from '../../package_policy'; + +import { removeOldAssets } from './cleanup'; + +jest.mock('../..', () => ({ + appContextService: { + getLogger: () => ({ + info: jest.fn(), + }), + }, +})); + +jest.mock('../../package_policy'); + +describe(' Cleanup old assets', () => { + let soClient: jest.Mocked; + const packagePolicyServiceMock = + packagePolicyService as jest.Mocked; + let removeArchiveEntriesMock: jest.MockedFunction; + + function mockFindVersions(versions: string[]) { + soClient.find.mockResolvedValue({ + page: 0, + per_page: 0, + total: 0, + saved_objects: [], + aggregations: { + versions: { + buckets: versions.map((v) => ({ key: '0.3.3' })), + }, + }, + }); + } + + beforeEach(() => { + soClient = savedObjectsClientMock.create(); + packagePolicyServiceMock.list.mockClear(); + removeArchiveEntriesMock = jest.spyOn(storage, 'removeArchiveEntries') as any; + removeArchiveEntriesMock.mockClear(); + }); + it('should remove old assets from 2 versions if none of the policies are using it', async () => { + mockFindVersions(['0.3.3', '0.3.4']); + packagePolicyServiceMock.list.mockResolvedValue({ total: 0, items: [], page: 0, perPage: 0 }); + soClient.createPointInTimeFinder = jest.fn().mockResolvedValue({ + close: jest.fn(), + find: function* asyncGenerator() { + yield { saved_objects: [{ id: '1' }, { id: '2' }] }; + }, + }); + + await removeOldAssets({ soClient, pkgName: 'apache', currentVersion: '1.0.0' }); + + expect(removeArchiveEntriesMock).toHaveBeenCalledWith({ + savedObjectsClient: soClient, + refs: [ + { id: '1', type: 'epm-packages-assets' }, + { id: '2', type: 'epm-packages-assets' }, + ], + }); + expect(removeArchiveEntriesMock).toHaveBeenCalledTimes(2); + }); + + it('should not remove old assets if used by policies', async () => { + mockFindVersions(['0.3.3']); + packagePolicyServiceMock.list.mockResolvedValue({ total: 1, items: [], page: 0, perPage: 0 }); + + await removeOldAssets({ soClient, pkgName: 'apache', currentVersion: '1.0.0' }); + + expect(removeArchiveEntriesMock).not.toHaveBeenCalled(); + }); + + it('should remove old assets from all pages', async () => { + mockFindVersions(['0.3.3']); + packagePolicyServiceMock.list.mockResolvedValue({ total: 0, items: [], page: 0, perPage: 0 }); + soClient.createPointInTimeFinder = jest.fn().mockResolvedValue({ + close: jest.fn(), + find: function* asyncGenerator() { + yield { saved_objects: [{ id: '1' }, { id: '2' }] }; + yield { saved_objects: [{ id: '3' }] }; + }, + }); + + await removeOldAssets({ soClient, pkgName: 'apache', currentVersion: '1.0.0' }); + + expect(removeArchiveEntriesMock).toHaveBeenCalledWith({ + savedObjectsClient: soClient, + refs: [ + { id: '1', type: 'epm-packages-assets' }, + { id: '2', type: 'epm-packages-assets' }, + ], + }); + expect(removeArchiveEntriesMock).toHaveBeenCalledWith({ + savedObjectsClient: soClient, + refs: [{ id: '3', type: 'epm-packages-assets' }], + }); + expect(removeArchiveEntriesMock).toHaveBeenCalledTimes(2); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/cleanup.ts b/x-pack/plugins/fleet/server/services/epm/packages/cleanup.ts new file mode 100644 index 0000000000000..d70beb53eddab --- /dev/null +++ b/x-pack/plugins/fleet/server/services/epm/packages/cleanup.ts @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SavedObjectsClientContract } from 'src/core/server'; + +import { removeArchiveEntries } from '../archive/storage'; + +import { ASSETS_SAVED_OBJECT_TYPE, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../common'; +import type { PackageAssetReference } from '../../../../common'; +import { packagePolicyService } from '../../package_policy'; +import { appContextService } from '../..'; + +export async function removeOldAssets(options: { + soClient: SavedObjectsClientContract; + pkgName: string; + currentVersion: string; +}) { + const { soClient, pkgName, currentVersion } = options; + + // find all assets of older versions + const aggs = { + versions: { terms: { field: `${ASSETS_SAVED_OBJECT_TYPE}.attributes.package_version` } }, + }; + const oldVersionsAgg = await soClient.find({ + type: ASSETS_SAVED_OBJECT_TYPE, + filter: `${ASSETS_SAVED_OBJECT_TYPE}.attributes.package_name:${pkgName} AND ${ASSETS_SAVED_OBJECT_TYPE}.attributes.package_version<${currentVersion}`, + aggs, + page: 0, + perPage: 0, + }); + + const oldVersions = oldVersionsAgg.aggregations.versions.buckets.map( + (obj: { key: string }) => obj.key + ); + + for (const oldVersion of oldVersions) { + await removeAssetsFromVersion(soClient, pkgName, oldVersion); + } +} + +async function removeAssetsFromVersion( + soClient: SavedObjectsClientContract, + pkgName: string, + oldVersion: string +) { + // check if any policies are using this package version + const { total } = await packagePolicyService.list(soClient, { + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${pkgName} AND ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.version:${oldVersion}`, + page: 0, + perPage: 0, + }); + // don't delete if still being used + if (total > 0) { + appContextService + .getLogger() + .info(`Package "${pkgName}-${oldVersion}" still being used by policies`); + return; + } + + // check if old version has assets + const finder = await soClient.createPointInTimeFinder({ + type: ASSETS_SAVED_OBJECT_TYPE, + filter: `${ASSETS_SAVED_OBJECT_TYPE}.attributes.package_name:${pkgName} AND ${ASSETS_SAVED_OBJECT_TYPE}.attributes.package_version:${oldVersion}`, + perPage: 1000, + fields: ['id'], + }); + + for await (const assets of finder.find()) { + const refs = assets.saved_objects.map( + (obj) => ({ id: obj.id, type: ASSETS_SAVED_OBJECT_TYPE } as PackageAssetReference) + ); + + await removeArchiveEntries({ savedObjectsClient: soClient, refs }); + } + await finder.close(); +} diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index 2568f40594f10..bd1968f03c263 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -38,6 +38,7 @@ import { isUnremovablePackage, getInstallation, getInstallationObject } from './ import { removeInstallation } from './remove'; import { getPackageSavedObjects } from './get'; import { _installPackage } from './_install_package'; +import { removeOldAssets } from './cleanup'; export async function isPackageInstalled(options: { savedObjectsClient: SavedObjectsClientContract; @@ -267,7 +268,12 @@ async function installPackageFromRegistry({ installType, installSource: 'registry', }) - .then((assets) => { + .then(async (assets) => { + await removeOldAssets({ + soClient: savedObjectsClient, + pkgName: packageInfo.name, + currentVersion: packageInfo.version, + }); return { assets, status: 'installed', installType }; }) .catch(async (err: Error) => { diff --git a/x-pack/plugins/fleet/server/services/epm/registry/requests.test.ts b/x-pack/plugins/fleet/server/services/epm/registry/requests.test.ts index 01fd4ad143d18..61f6cc164eb30 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/requests.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/requests.test.ts @@ -15,7 +15,7 @@ const { Response, FetchError } = jest.requireActual('node-fetch'); const fetchMock = require('node-fetch') as jest.Mock; jest.setTimeout(120 * 1000); -describe('setupIngestManager', () => { +describe('Registry request', () => { beforeEach(async () => {}); afterEach(async () => { diff --git a/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts index 379bc8fa39bff..bbaf9c9479eb4 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts @@ -190,11 +190,7 @@ async function migrateAgentPolicies() { // @ts-expect-error value is number | TotalHits if (res.body.hits.total.value === 0) { - return agentPolicyService.createFleetPolicyChangeFleetServer( - soClient, - esClient, - agentPolicy.id - ); + return agentPolicyService.createFleetServerPolicy(soClient, agentPolicy.id); } }) ); diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index 26e3955607ada..8103794fb0805 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -5,8 +5,10 @@ * 2.0. */ -import { outputService } from './output'; +import { savedObjectsClientMock } from '../../../../../src/core/server/mocks'; +import type { OutputSOAttributes } from '../types'; +import { outputService, outputIdToUuid } from './output'; import { appContextService } from './app_context'; jest.mock('./app_context'); @@ -34,7 +36,97 @@ const CONFIG_WITHOUT_ES_HOSTS = { }, }; +function getMockedSoClient() { + const soClient = savedObjectsClientMock.create(); + soClient.get.mockImplementation(async (type: string, id: string) => { + switch (id) { + case outputIdToUuid('output-test'): { + return { + id: outputIdToUuid('output-test'), + type: 'ingest-outputs', + references: [], + attributes: { + output_id: 'output-test', + }, + }; + } + default: + throw new Error('not found'); + } + }); + + return soClient; +} + describe('Output Service', () => { + describe('create', () => { + it('work with a predefined id', async () => { + const soClient = getMockedSoClient(); + soClient.create.mockResolvedValue({ + id: outputIdToUuid('output-test'), + type: 'ingest-output', + attributes: {}, + references: [], + }); + await outputService.create( + soClient, + { + is_default: false, + name: 'Test', + type: 'elasticsearch', + }, + { id: 'output-test' } + ); + + expect(soClient.create).toBeCalled(); + + // ID should always be the same for a predefined id + expect(soClient.create.mock.calls[0][2]?.id).toEqual(outputIdToUuid('output-test')); + expect((soClient.create.mock.calls[0][1] as OutputSOAttributes).output_id).toEqual( + 'output-test' + ); + }); + }); + + describe('get', () => { + it('work with a predefined id', async () => { + const soClient = getMockedSoClient(); + const output = await outputService.get(soClient, 'output-test'); + + expect(soClient.get).toHaveBeenCalledWith('ingest-outputs', outputIdToUuid('output-test')); + + expect(output.id).toEqual('output-test'); + }); + }); + + describe('getDefaultOutputId', () => { + it('work with a predefined id', async () => { + const soClient = getMockedSoClient(); + soClient.find.mockResolvedValue({ + page: 1, + per_page: 100, + total: 1, + saved_objects: [ + { + id: outputIdToUuid('output-test'), + type: 'ingest-outputs', + references: [], + score: 0, + attributes: { + output_id: 'output-test', + is_default: true, + }, + }, + ], + }); + const defaultId = await outputService.getDefaultOutputId(soClient); + + expect(soClient.find).toHaveBeenCalled(); + + expect(defaultId).toEqual('output-test'); + }); + }); + describe('getDefaultESHosts', () => { afterEach(() => { mockedAppContextService.getConfig.mockReset(); diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index 8c6bc7eca0401..5a7ba1e2c1223 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -5,7 +5,8 @@ * 2.0. */ -import type { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObject, SavedObjectsClientContract } from 'src/core/server'; +import uuid from 'uuid/v5'; import type { NewOutput, Output, OutputSOAttributes } from '../types'; import { DEFAULT_OUTPUT, OUTPUT_SAVED_OBJECT_TYPE } from '../constants'; @@ -17,8 +18,33 @@ const SAVED_OBJECT_TYPE = OUTPUT_SAVED_OBJECT_TYPE; const DEFAULT_ES_HOSTS = ['http://localhost:9200']; +// differentiate +function isUUID(val: string) { + return ( + typeof val === 'string' && + val.match(/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/) + ); +} + +export function outputIdToUuid(id: string) { + if (isUUID(id)) { + return id; + } + + // UUID v5 need a namespace (uuid.DNS), changing this params will result in loosing the ability to generate predicable uuid + return uuid(id, uuid.DNS); +} + +function outputSavedObjectToOutput(so: SavedObject) { + const { output_id: outputId, ...atributes } = so.attributes; + return { + id: outputId ?? so.id, + ...atributes, + }; +} + class OutputService { - public async getDefaultOutput(soClient: SavedObjectsClientContract) { + private async _getDefaultOutputsSO(soClient: SavedObjectsClientContract) { return await soClient.find({ type: OUTPUT_SAVED_OBJECT_TYPE, searchFields: ['is_default'], @@ -27,7 +53,7 @@ class OutputService { } public async ensureDefaultOutput(soClient: SavedObjectsClientContract) { - const outputs = await this.getDefaultOutput(soClient); + const outputs = await this._getDefaultOutputsSO(soClient); if (!outputs.saved_objects.length) { const newDefaultOutput = { @@ -39,10 +65,7 @@ class OutputService { return await this.create(soClient, newDefaultOutput); } - return { - id: outputs.saved_objects[0].id, - ...outputs.saved_objects[0].attributes, - }; + return outputSavedObjectToOutput(outputs.saved_objects[0]); } public getDefaultESHosts(): string[] { @@ -60,49 +83,84 @@ class OutputService { } public async getDefaultOutputId(soClient: SavedObjectsClientContract) { - const outputs = await this.getDefaultOutput(soClient); + const outputs = await this._getDefaultOutputsSO(soClient); if (!outputs.saved_objects.length) { return null; } - return outputs.saved_objects[0].id; + return outputSavedObjectToOutput(outputs.saved_objects[0]).id; } public async create( soClient: SavedObjectsClientContract, output: NewOutput, - options?: { id?: string } + options?: { id?: string; overwrite?: boolean } ): Promise { - const data = { ...output }; + const data: OutputSOAttributes = { ...output }; + + // ensure only default output exists + if (data.is_default) { + const defaultOuput = await this.getDefaultOutputId(soClient); + if (defaultOuput) { + throw new Error(`A default output already exists (${defaultOuput})`); + } + } if (data.hosts) { data.hosts = data.hosts.map(normalizeHostsForAgents); } - const newSo = await soClient.create( - SAVED_OBJECT_TYPE, - data as Output, - options - ); + if (options?.id) { + data.output_id = options?.id; + } + + const newSo = await soClient.create(SAVED_OBJECT_TYPE, data, { + ...options, + id: options?.id ? outputIdToUuid(options.id) : undefined, + }); return { - id: newSo.id, + id: options?.id ?? newSo.id, ...newSo.attributes, }; } + public async bulkGet( + soClient: SavedObjectsClientContract, + ids: string[], + { ignoreNotFound = false } = { ignoreNotFound: true } + ) { + const res = await soClient.bulkGet( + ids.map((id) => ({ id: outputIdToUuid(id), type: SAVED_OBJECT_TYPE })) + ); + + return res.saved_objects + .map((so) => { + if (so.error) { + if (!ignoreNotFound || so.error.statusCode !== 404) { + throw so.error; + } + return undefined; + } + + return outputSavedObjectToOutput(so); + }) + .filter((output): output is Output => typeof output !== 'undefined'); + } + public async get(soClient: SavedObjectsClientContract, id: string): Promise { - const outputSO = await soClient.get(SAVED_OBJECT_TYPE, id); + const outputSO = await soClient.get(SAVED_OBJECT_TYPE, outputIdToUuid(id)); if (outputSO.error) { throw new Error(outputSO.error.message); } - return { - id: outputSO.id, - ...outputSO.attributes, - }; + return outputSavedObjectToOutput(outputSO); + } + + public async delete(soClient: SavedObjectsClientContract, id: string) { + return soClient.delete(SAVED_OBJECT_TYPE, outputIdToUuid(id)); } public async update(soClient: SavedObjectsClientContract, id: string, data: Partial) { @@ -111,8 +169,11 @@ class OutputService { if (updateData.hosts) { updateData.hosts = updateData.hosts.map(normalizeHostsForAgents); } - - const outputSO = await soClient.update(SAVED_OBJECT_TYPE, id, updateData); + const outputSO = await soClient.update( + SAVED_OBJECT_TYPE, + outputIdToUuid(id), + updateData + ); if (outputSO.error) { throw new Error(outputSO.error.message); @@ -127,12 +188,7 @@ class OutputService { }); return { - items: outputs.saved_objects.map((outputSO) => { - return { - id: outputSO.id, - ...outputSO.attributes, - }; - }), + items: outputs.saved_objects.map(outputSavedObjectToOutput), total: outputs.total, page: 1, perPage: 1000, diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index c806b37f88153..d84d50e00b8a9 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -65,6 +65,7 @@ import { getAssetsData } from './epm/packages/assets'; import { compileTemplate } from './epm/agent/agent'; import { normalizeKuery } from './saved_object'; import { appContextService } from '.'; +import { removeOldAssets } from './epm/packages/cleanup'; export type InputsOverride = Partial & { vars?: Array; @@ -575,6 +576,11 @@ class PackagePolicyService { name: packagePolicy.name, success: true, }); + await removeOldAssets({ + soClient, + pkgName: packageInfo.name, + currentVersion: packageInfo.version, + }); } catch (error) { result.push({ id, diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts index 86fdd2f0aa800..43887bc2787f4 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts @@ -9,7 +9,7 @@ import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/serve import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; -import type { PreconfiguredAgentPolicy } from '../../common/types'; +import type { PreconfiguredAgentPolicy, PreconfiguredOutput } from '../../common/types'; import type { AgentPolicy, NewPackagePolicy, Output } from '../types'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../constants'; @@ -19,9 +19,15 @@ import * as agentPolicy from './agent_policy'; import { ensurePreconfiguredPackagesAndPolicies, comparePreconfiguredPolicyToCurrent, + ensurePreconfiguredOutputs, + cleanPreconfiguredOutputs, } from './preconfiguration'; +import { outputService } from './output'; jest.mock('./agent_policy_update'); +jest.mock('./output'); + +const mockedOutputService = outputService as jest.Mocked; const mockInstalledPackages = new Map(); const mockConfiguredPolicies = new Map(); @@ -156,12 +162,17 @@ jest.mock('./app_context', () => ({ })); const spyAgentPolicyServiceUpdate = jest.spyOn(agentPolicy.agentPolicyService, 'update'); +const spyAgentPolicyServicBumpAllAgentPoliciesForOutput = jest.spyOn( + agentPolicy.agentPolicyService, + 'bumpAllAgentPoliciesForOutput' +); describe('policy preconfiguration', () => { beforeEach(() => { mockInstalledPackages.clear(); mockConfiguredPolicies.clear(); spyAgentPolicyServiceUpdate.mockClear(); + spyAgentPolicyServicBumpAllAgentPoliciesForOutput.mockClear(); }); it('should perform a no-op when passed no policies or packages', async () => { @@ -480,3 +491,168 @@ describe('comparePreconfiguredPolicyToCurrent', () => { expect(hasChanged).toBe(false); }); }); + +describe('output preconfiguration', () => { + beforeEach(() => { + mockedOutputService.create.mockReset(); + mockedOutputService.update.mockReset(); + mockedOutputService.getDefaultESHosts.mockReturnValue(['http://default-es:9200']); + mockedOutputService.bulkGet.mockImplementation(async (soClient, id): Promise => { + return [ + { + id: 'existing-output-1', + is_default: false, + name: 'Output 1', + // @ts-ignore + type: 'elasticsearch', + hosts: ['http://es.co:80'], + is_preconfigured: true, + }, + ]; + }); + }); + + it('should create preconfigured output that does not exists', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + await ensurePreconfiguredOutputs(soClient, esClient, [ + { + id: 'non-existing-output-1', + name: 'Output 1', + type: 'elasticsearch', + is_default: false, + hosts: ['http://test.fr'], + }, + ]); + + expect(mockedOutputService.create).toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should set default hosts if hosts is not set output that does not exists', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + await ensurePreconfiguredOutputs(soClient, esClient, [ + { + id: 'non-existing-output-1', + name: 'Output 1', + type: 'elasticsearch', + is_default: false, + }, + ]); + + expect(mockedOutputService.create).toBeCalled(); + expect(mockedOutputService.create.mock.calls[0][1].hosts).toEqual(['http://default-es:9200']); + }); + + it('should update output if preconfigured output exists and changed', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await ensurePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-output-1', + is_default: false, + name: 'Output 1', + type: 'elasticsearch', + hosts: ['http://newhostichanged.co:9201'], // field that changed + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + }); + + const SCENARIOS: Array<{ name: string; data: PreconfiguredOutput }> = [ + { + name: 'no changes', + data: { + id: 'existing-output-1', + is_default: false, + name: 'Output 1', + type: 'elasticsearch', + hosts: ['http://es.co:80'], + }, + }, + { + name: 'hosts without port', + data: { + id: 'existing-output-1', + is_default: false, + name: 'Output 1', + type: 'elasticsearch', + hosts: ['http://es.co'], + }, + }, + ]; + SCENARIOS.forEach((scenario) => { + const { data, name } = scenario; + it(`should do nothing if preconfigured output exists and did not changed (${name})`, async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + await ensurePreconfiguredOutputs(soClient, esClient, [data]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + }); + }); + + it('should not delete non deleted preconfigured output', async () => { + const soClient = savedObjectsClientMock.create(); + mockedOutputService.list.mockResolvedValue({ + items: [ + { id: 'output1', is_preconfigured: true } as Output, + { id: 'output2', is_preconfigured: true } as Output, + ], + page: 1, + perPage: 10000, + total: 1, + }); + await cleanPreconfiguredOutputs(soClient, [ + { + id: 'output1', + is_default: false, + name: 'Output 1', + type: 'elasticsearch', + hosts: ['http://es.co:9201'], + }, + { + id: 'output2', + is_default: false, + name: 'Output 2', + type: 'elasticsearch', + hosts: ['http://es.co:9201'], + }, + ]); + + expect(mockedOutputService.delete).not.toBeCalled(); + }); + + it('should delete deleted preconfigured output', async () => { + const soClient = savedObjectsClientMock.create(); + mockedOutputService.list.mockResolvedValue({ + items: [ + { id: 'output1', is_preconfigured: true } as Output, + { id: 'output2', is_preconfigured: true } as Output, + ], + page: 1, + perPage: 10000, + total: 1, + }); + await cleanPreconfiguredOutputs(soClient, [ + { + id: 'output1', + is_default: false, + name: 'Output 1', + type: 'elasticsearch', + hosts: ['http://es.co:9201'], + }, + ]); + + expect(mockedOutputService.delete).toBeCalled(); + expect(mockedOutputService.delete).toBeCalledTimes(1); + expect(mockedOutputService.delete.mock.calls[0][1]).toEqual('output2'); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index 37ed98a6f4aa0..30c5c27c68916 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -8,6 +8,7 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import { i18n } from '@kbn/i18n'; import { groupBy, omit, pick, isEqual } from 'lodash'; +import { safeDump } from 'js-yaml'; import type { NewPackagePolicy, @@ -17,16 +18,15 @@ import type { PreconfiguredAgentPolicy, PreconfiguredPackage, PreconfigurationError, + PreconfiguredOutput, } from '../../common'; -import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../common'; - +import { AGENT_POLICY_SAVED_OBJECT_TYPE, normalizeHostsForAgents } from '../../common'; import { PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, PRECONFIGURATION_LATEST_KEYWORD, } from '../constants'; import { escapeSearchQueryPhrase } from './saved_object'; - import { pkgToPkgKey } from './epm/registry'; import { getInstallation, getPackageInfo } from './epm/packages'; import { ensurePackagesCompletedInstall } from './epm/packages/install'; @@ -35,6 +35,7 @@ import { agentPolicyService, addPackageToAgentPolicy } from './agent_policy'; import type { InputsOverride } from './package_policy'; import { overridePackageInputs } from './package_policy'; import { appContextService } from './app_context'; +import { outputService } from './output'; interface PreconfigurationResult { policies: Array<{ id: string; updated_at: string }>; @@ -42,6 +43,89 @@ interface PreconfigurationResult { nonFatalErrors: PreconfigurationError[]; } +function isPreconfiguredOutputDifferentFromCurrent( + existingOutput: Output, + preconfiguredOutput: Partial +): boolean { + return ( + existingOutput.is_default !== preconfiguredOutput.is_default || + existingOutput.name !== preconfiguredOutput.name || + existingOutput.type !== preconfiguredOutput.type || + (preconfiguredOutput.hosts && + !isEqual( + existingOutput.hosts?.map(normalizeHostsForAgents), + preconfiguredOutput.hosts.map(normalizeHostsForAgents) + )) || + existingOutput.ca_sha256 !== preconfiguredOutput.ca_sha256 || + existingOutput.config_yaml !== preconfiguredOutput.config_yaml + ); +} + +export async function ensurePreconfiguredOutputs( + soClient: SavedObjectsClientContract, + esClient: ElasticsearchClient, + outputs: PreconfiguredOutput[] +) { + if (outputs.length === 0) { + return; + } + + const existingOutputs = await outputService.bulkGet( + soClient, + outputs.map(({ id }) => id), + { ignoreNotFound: true } + ); + + await Promise.all( + outputs.map(async (output) => { + const existingOutput = existingOutputs.find((o) => o.id === output.id); + + const { id, config, ...outputData } = output; + + const configYaml = config ? safeDump(config) : undefined; + + const data = { + ...outputData, + config_yaml: configYaml, + is_preconfigured: true, + }; + + if (!data.hosts || data.hosts.length === 0) { + data.hosts = outputService.getDefaultESHosts(); + } + + if (!existingOutput) { + await outputService.create(soClient, data, { id, overwrite: true }); + } else if (isPreconfiguredOutputDifferentFromCurrent(existingOutput, data)) { + await outputService.update(soClient, id, data); + // Bump revision of all policies using that output + if (outputData.is_default) { + await agentPolicyService.bumpAllAgentPolicies(soClient, esClient); + } else { + await agentPolicyService.bumpAllAgentPoliciesForOutput(soClient, esClient, id); + } + } + }) + ); +} + +export async function cleanPreconfiguredOutputs( + soClient: SavedObjectsClientContract, + outputs: PreconfiguredOutput[] +) { + const existingPreconfiguredOutput = (await outputService.list(soClient)).items.filter( + (o) => o.is_preconfigured === true + ); + const logger = appContextService.getLogger(); + + for (const output of existingPreconfiguredOutput) { + if (!outputs.find(({ id }) => output.id === id)) { + logger.info(`Deleting preconfigured output ${output.id}`); + await outputService.delete(soClient, output.id); + } + } +} + export async function ensurePreconfiguredPackagesAndPolicies( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, @@ -224,7 +308,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( } // Add the is_managed flag after configuring package policies to avoid errors if (shouldAddIsManagedFlag) { - agentPolicyService.update(soClient, esClient, policy!.id, { is_managed: true }); + await agentPolicyService.update(soClient, esClient, policy!.id, { is_managed: true }); } } } diff --git a/x-pack/plugins/fleet/server/services/setup.test.ts b/x-pack/plugins/fleet/server/services/setup.test.ts index 212b0fabd26fb..e6b76694a9fca 100644 --- a/x-pack/plugins/fleet/server/services/setup.test.ts +++ b/x-pack/plugins/fleet/server/services/setup.test.ts @@ -8,7 +8,7 @@ import { createAppContextStartContractMock, xpackMocks } from '../mocks'; import { appContextService } from './app_context'; -import { setupIngestManager } from './setup'; +import { setupFleet } from './setup'; const mockedMethodThrowsError = () => jest.fn().mockImplementation(() => { @@ -21,7 +21,7 @@ const mockedMethodThrowsCustom = () => throw new CustomTestError('method mocked to throw'); }); -describe('setupIngestManager', () => { +describe('setupFleet', () => { let context: ReturnType; beforeEach(async () => { @@ -44,7 +44,7 @@ describe('setupIngestManager', () => { soClient.update = mockedMethodThrowsError(); const esClient = context.core.elasticsearch.client.asCurrentUser; - const setupPromise = setupIngestManager(soClient, esClient); + const setupPromise = setupFleet(soClient, esClient); await expect(setupPromise).rejects.toThrow('SO method mocked to throw'); await expect(setupPromise).rejects.toThrow(Error); }); @@ -57,7 +57,7 @@ describe('setupIngestManager', () => { soClient.update = mockedMethodThrowsCustom(); const esClient = context.core.elasticsearch.client.asCurrentUser; - const setupPromise = setupIngestManager(soClient, esClient); + const setupPromise = setupFleet(soClient, esClient); await expect(setupPromise).rejects.toThrow('method mocked to throw'); await expect(setupPromise).rejects.toThrow(CustomTestError); }); diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index 1f3c3c5082b34..08c580d80c804 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -15,13 +15,17 @@ import { SO_SEARCH_LIMIT, DEFAULT_PACKAGES } from '../constants'; import { appContextService } from './app_context'; import { agentPolicyService } from './agent_policy'; -import { ensurePreconfiguredPackagesAndPolicies } from './preconfiguration'; +import { + cleanPreconfiguredOutputs, + ensurePreconfiguredOutputs, + ensurePreconfiguredPackagesAndPolicies, +} from './preconfiguration'; import { outputService } from './output'; import { generateEnrollmentAPIKey, hasEnrollementAPIKeysForPolicy } from './api_keys'; import { settingsService } from '.'; import { awaitIfPending } from './setup_utils'; -import { ensureAgentActionPolicyChangeExists } from './agents'; +import { ensureFleetServerAgentPoliciesExists } from './agents'; import { awaitIfFleetServerSetupPending } from './fleet_server'; import { ensureFleetFinalPipelineIsInstalled } from './epm/elasticsearch/ingest_pipeline/install'; import { ensureDefaultComponentTemplate } from './epm/elasticsearch/template/install'; @@ -34,7 +38,7 @@ export interface SetupStatus { nonFatalErrors: Array; } -export async function setupIngestManager( +export async function setupFleet( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient ): Promise { @@ -45,23 +49,27 @@ async function createSetupSideEffects( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient ): Promise { - const [defaultOutput] = await Promise.all([ - outputService.ensureDefaultOutput(soClient), + const { + agentPolicies: policiesOrUndefined, + packages: packagesOrUndefined, + outputs: outputsOrUndefined, + } = appContextService.getConfig() ?? {}; + + const policies = policiesOrUndefined ?? []; + let packages = packagesOrUndefined ?? []; + + await Promise.all([ + ensurePreconfiguredOutputs(soClient, esClient, outputsOrUndefined ?? []), settingsService.settingsSetup(soClient), ]); + const defaultOutput = await outputService.ensureDefaultOutput(soClient); + await awaitIfFleetServerSetupPending(); if (appContextService.getConfig()?.agentIdVerificationEnabled) { await ensureFleetGlobalEsAssets(soClient, esClient); } - const { agentPolicies: policiesOrUndefined, packages: packagesOrUndefined } = - appContextService.getConfig() ?? {}; - - const policies = policiesOrUndefined ?? []; - - let packages = packagesOrUndefined ?? []; - // Ensure that required packages are always installed even if they're left out of the config const preconfiguredPackageNames = new Set(packages.map((pkg) => pkg.name)); @@ -90,8 +98,10 @@ async function createSetupSideEffects( defaultOutput ); + await cleanPreconfiguredOutputs(soClient, outputsOrUndefined ?? []); + await ensureDefaultEnrollmentAPIKeysExists(soClient, esClient); - await ensureAgentActionPolicyChangeExists(soClient, esClient); + await ensureFleetServerAgentPoliciesExists(soClient, esClient); return { isInitialized: true, diff --git a/x-pack/plugins/fleet/server/types/index.tsx b/x-pack/plugins/fleet/server/types/index.tsx index f686b969fd038..63e6c277ed710 100644 --- a/x-pack/plugins/fleet/server/types/index.tsx +++ b/x-pack/plugins/fleet/server/types/index.tsx @@ -27,6 +27,7 @@ export { PackagePolicySOAttributes, FullAgentPolicyInput, FullAgentPolicy, + FullAgentPolicyOutput, AgentPolicy, AgentPolicySOAttributes, NewAgentPolicy, diff --git a/x-pack/plugins/fleet/server/types/models/preconfiguration.test.ts b/x-pack/plugins/fleet/server/types/models/preconfiguration.test.ts new file mode 100644 index 0000000000000..eb349e0d0f823 --- /dev/null +++ b/x-pack/plugins/fleet/server/types/models/preconfiguration.test.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PreconfiguredOutputsSchema, PreconfiguredAgentPoliciesSchema } from './preconfiguration'; + +describe('Test preconfiguration schema', () => { + describe('PreconfiguredOutputsSchema', () => { + it('should not allow multiple default output', () => { + expect(() => { + PreconfiguredOutputsSchema.validate([ + { + id: 'output-1', + name: 'Output 1', + type: 'elasticsearch', + is_default: true, + }, + { + id: 'output-2', + name: 'Output 2', + type: 'elasticsearch', + is_default: true, + }, + ]); + }).toThrowError('preconfigured outputs need to have only one default output.'); + }); + it('should not allow multiple output with same ids', () => { + expect(() => { + PreconfiguredOutputsSchema.validate([ + { + id: 'nonuniqueid', + name: 'Output 1', + type: 'elasticsearch', + }, + { + id: 'nonuniqueid', + name: 'Output 2', + type: 'elasticsearch', + }, + ]); + }).toThrowError('preconfigured outputs need to have unique ids.'); + }); + it('should not allow multiple output with same names', () => { + expect(() => { + PreconfiguredOutputsSchema.validate([ + { + id: 'output-1', + name: 'nonuniquename', + type: 'elasticsearch', + }, + { + id: 'output-2', + name: 'nonuniquename', + type: 'elasticsearch', + }, + ]); + }).toThrowError('preconfigured outputs need to have unique names.'); + }); + }); + + describe('PreconfiguredAgentPoliciesSchema', () => { + it('should not allow multiple outputs in one policy', () => { + expect(() => { + PreconfiguredAgentPoliciesSchema.validate([ + { + id: 'policy-1', + name: 'Policy 1', + package_policies: [], + data_output_id: 'test1', + monitoring_output_id: 'test2', + }, + ]); + }).toThrowError( + '[0]: Currently Fleet only support one output per agent policy data_output_id should be the same as monitoring_output_id.' + ); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/types/models/preconfiguration.ts b/x-pack/plugins/fleet/server/types/models/preconfiguration.ts index 4ea9f086bda68..b65fa122911dc 100644 --- a/x-pack/plugins/fleet/server/types/models/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/types/models/preconfiguration.ts @@ -14,6 +14,8 @@ import { DEFAULT_FLEET_SERVER_AGENT_POLICY, DEFAULT_PACKAGES, } from '../../constants'; +import type { PreconfiguredOutput } from '../../../common'; +import { outputType } from '../../../common'; import { AgentPolicyBaseSchema } from './agent_policy'; import { NamespaceSchema } from './package_policy'; @@ -47,47 +49,94 @@ export const PreconfiguredPackagesSchema = schema.arrayOf( } ); -export const PreconfiguredAgentPoliciesSchema = schema.arrayOf( +function validatePreconfiguredOutputs(outputs: PreconfiguredOutput[]) { + const acc = { names: new Set(), ids: new Set(), is_default: false }; + + for (const output of outputs) { + if (acc.names.has(output.name)) { + return 'preconfigured outputs need to have unique names.'; + } + if (acc.ids.has(output.id)) { + return 'preconfigured outputs need to have unique ids.'; + } + if (acc.is_default && output.is_default) { + return 'preconfigured outputs need to have only one default output.'; + } + + acc.ids.add(output.id); + acc.names.add(output.name); + acc.is_default = acc.is_default || output.is_default; + } +} + +export const PreconfiguredOutputsSchema = schema.arrayOf( schema.object({ - ...AgentPolicyBaseSchema, - namespace: schema.maybe(NamespaceSchema), - id: schema.maybe(schema.oneOf([schema.string(), schema.number()])), - is_default: schema.maybe(schema.boolean()), - is_default_fleet_server: schema.maybe(schema.boolean()), - package_policies: schema.arrayOf( - schema.object({ - name: schema.string(), - package: schema.object({ - name: schema.string(), - }), - description: schema.maybe(schema.string()), - namespace: schema.maybe(NamespaceSchema), - inputs: schema.maybe( - schema.arrayOf( - schema.object({ - type: schema.string(), - enabled: schema.maybe(schema.boolean()), - keep_enabled: schema.maybe(schema.boolean()), - vars: varsSchema, - streams: schema.maybe( - schema.arrayOf( - schema.object({ - data_stream: schema.object({ - type: schema.maybe(schema.string()), - dataset: schema.string(), - }), - enabled: schema.maybe(schema.boolean()), - keep_enabled: schema.maybe(schema.boolean()), - vars: varsSchema, - }) - ) - ), - }) - ) - ), - }) - ), + id: schema.string(), + is_default: schema.boolean({ defaultValue: false }), + name: schema.string(), + type: schema.oneOf([schema.literal(outputType.Elasticsearch)]), + hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))), + ca_sha256: schema.maybe(schema.string()), + config: schema.maybe(schema.object({}, { unknowns: 'allow' })), }), + { + defaultValue: [], + validate: validatePreconfiguredOutputs, + } +); + +export const PreconfiguredAgentPoliciesSchema = schema.arrayOf( + schema.object( + { + ...AgentPolicyBaseSchema, + namespace: schema.maybe(NamespaceSchema), + id: schema.maybe(schema.oneOf([schema.string(), schema.number()])), + is_default: schema.maybe(schema.boolean()), + is_default_fleet_server: schema.maybe(schema.boolean()), + data_output_id: schema.maybe(schema.string()), + monitoring_output_id: schema.maybe(schema.string()), + package_policies: schema.arrayOf( + schema.object({ + name: schema.string(), + package: schema.object({ + name: schema.string(), + }), + description: schema.maybe(schema.string()), + namespace: schema.maybe(NamespaceSchema), + inputs: schema.maybe( + schema.arrayOf( + schema.object({ + type: schema.string(), + enabled: schema.maybe(schema.boolean()), + keep_enabled: schema.maybe(schema.boolean()), + vars: varsSchema, + streams: schema.maybe( + schema.arrayOf( + schema.object({ + data_stream: schema.object({ + type: schema.maybe(schema.string()), + dataset: schema.string(), + }), + enabled: schema.maybe(schema.boolean()), + keep_enabled: schema.maybe(schema.boolean()), + vars: varsSchema, + }) + ) + ), + }) + ) + ), + }) + ), + }, + { + validate: (policy) => { + if (policy.data_output_id !== policy.monitoring_output_id) { + return 'Currently Fleet only support one output per agent policy data_output_id should be the same as monitoring_output_id.'; + } + }, + } + ), { defaultValue: [DEFAULT_AGENT_POLICY, DEFAULT_FLEET_SERVER_AGENT_POLICY], } diff --git a/x-pack/plugins/fleet/storybook/decorator.tsx b/x-pack/plugins/fleet/storybook/decorator.tsx new file mode 100644 index 0000000000000..499b01c2bfba0 --- /dev/null +++ b/x-pack/plugins/fleet/storybook/decorator.tsx @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { of } from 'rxjs'; +import type { DecoratorFn } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { createMemoryHistory } from 'history'; + +import { I18nProvider } from '@kbn/i18n/react'; + +import { ScopedHistory } from '../../../../src/core/public'; +import { IntegrationsAppContext } from '../public/applications/integrations/app'; +import type { FleetConfigType, FleetStartServices } from '../public/plugin'; + +// TODO: clintandrewhall - this is not ideal, or complete. The root context of Fleet applications +// requires full start contracts of its dependencies. As a result, we have to mock all of those contracts +// with Storybook equivalents. This is a temporary solution, and should be replaced with a more complete +// mock later, (or, ideally, Fleet starts to use a service abstraction). +// +// Expect this to grow as components that are given Stories need access to mocked services. +export const contextDecorator: DecoratorFn = (story: Function) => { + const basepath = '/'; + const memoryHistory = createMemoryHistory({ initialEntries: [basepath] }); + const history = new ScopedHistory(memoryHistory, basepath); + + const startServices = { + application: { + currentAppId$: of('home'), + navigateToUrl: (url: string) => action(`Navigate to: ${url}`), + getUrlForApp: (url: string) => url, + }, + http: { + basePath: { + prepend: () => basepath, + }, + }, + notifications: {}, + history, + uiSettings: { + get$: (key: string) => { + switch (key) { + case 'theme:darkMode': + return of(false); + default: + return of(); + } + }, + }, + i18n: { + Context: I18nProvider, + }, + } as unknown as FleetStartServices; + + const config = { + enabled: true, + agents: { + enabled: true, + elasticsearch: {}, + }, + } as unknown as FleetConfigType; + + const extensions = {}; + + const kibanaVersion = '1.2.3'; + + return ( + + {story()} + + ); +}; diff --git a/x-pack/plugins/fleet/storybook/main.ts b/x-pack/plugins/fleet/storybook/main.ts new file mode 100644 index 0000000000000..2cf4124c61783 --- /dev/null +++ b/x-pack/plugins/fleet/storybook/main.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Configuration } from 'webpack'; +import { defaultConfig, WebpackConfig } from '@kbn/storybook'; + +module.exports = { + ...defaultConfig, + addons: ['@storybook/addon-essentials'], + babel: () => ({ + presets: [require.resolve('@kbn/babel-preset/webpack_preset')], + }), + webpackFinal: (config: Configuration) => { + return WebpackConfig({ config }); + }, +}; diff --git a/x-pack/plugins/fleet/storybook/manager.ts b/x-pack/plugins/fleet/storybook/manager.ts new file mode 100644 index 0000000000000..471a735ed370f --- /dev/null +++ b/x-pack/plugins/fleet/storybook/manager.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { addons } from '@storybook/addons'; +import { create } from '@storybook/theming'; +import { PANEL_ID } from '@storybook/addon-actions'; + +addons.setConfig({ + theme: create({ + base: 'light', + brandTitle: 'Kibana Fleet Storybook', + brandUrl: 'https://github.com/elastic/kibana/tree/master/x-pack/plugins/fleet', + }), + showPanel: true.valueOf, + selectedPanel: PANEL_ID, +}); diff --git a/x-pack/plugins/fleet/storybook/preview.tsx b/x-pack/plugins/fleet/storybook/preview.tsx new file mode 100644 index 0000000000000..a50ff2faaff56 --- /dev/null +++ b/x-pack/plugins/fleet/storybook/preview.tsx @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { addDecorator } from '@storybook/react'; +import { Title, Subtitle, Description, Primary, Stories } from '@storybook/addon-docs/blocks'; + +import { contextDecorator } from './decorator'; + +addDecorator(contextDecorator); + +export const parameters = { + docs: { + page: () => ( + <> + + <Subtitle /> + <Description /> + <Primary /> + <Stories /> + </> + ), + }, +}; diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index 5002bf2893872..a9dd66ce503a9 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -14,6 +14,7 @@ "server/**/*.json", "scripts/**/*", "package.json", + "storybook/**/*", "../../../typings/**/*" ], "references": [ diff --git a/x-pack/plugins/graph/public/components/settings/settings.test.tsx b/x-pack/plugins/graph/public/components/settings/settings.test.tsx index 060b1e93fbdc0..1c3fbb9f54f67 100644 --- a/x-pack/plugins/graph/public/components/settings/settings.test.tsx +++ b/x-pack/plugins/graph/public/components/settings/settings.test.tsx @@ -24,6 +24,18 @@ import { createMockGraphStore } from '../../state_management/mocks'; import { Provider } from 'react-redux'; import { UrlTemplate } from '../../types'; +jest.mock('@elastic/eui', () => { + const original = jest.requireActual('@elastic/eui'); + + return { + ...original, + htmlIdGenerator: (fn: unknown) => { + let counter = 0; + return () => String(counter++); + }, + }; +}); + describe('settings', () => { let store: GraphStore; let dispatchSpy: jest.Mock; diff --git a/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx b/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx index cd0857f82ab6b..c4c40ada490f1 100644 --- a/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx +++ b/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx @@ -4,15 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; -import { mount } from 'enzyme'; import { useWorkspaceLoader, UseWorkspaceLoaderProps } from './use_workspace_loader'; import { coreMock } from 'src/core/public/mocks'; import { spacesPluginMock } from '../../../spaces/public/mocks'; import { createMockGraphStore } from '../state_management/mocks'; import { Workspace } from '../types'; import { SavedObjectsClientCommon } from 'src/plugins/data/common'; -import { act } from 'react-dom/test-utils'; +import { renderHook, act, RenderHookOptions } from '@testing-library/react-hooks'; jest.mock('react-router-dom', () => { const useLocation = () => ({ @@ -41,20 +39,6 @@ const mockSavedObjectsClient = { find: jest.fn().mockResolvedValue({ title: 'test' }), } as unknown as SavedObjectsClientCommon; -async function setup(props: UseWorkspaceLoaderProps) { - const returnVal = {}; - function TestComponent() { - Object.assign(returnVal, useWorkspaceLoader(props)); - return null; - } - await act(async () => { - const promise = Promise.resolve(); - mount(<TestComponent />); - await act(() => promise); - }); - return returnVal; -} - describe('use_workspace_loader', () => { const defaultProps = { workspaceRef: { current: {} as Workspace }, @@ -62,13 +46,16 @@ describe('use_workspace_loader', () => { savedObjectsClient: mockSavedObjectsClient, coreStart: coreMock.createStart(), spaces: spacesPluginMock.createStartContract(), - }; + } as unknown as UseWorkspaceLoaderProps; it('should not redirect if outcome is exactMatch', async () => { await act(async () => { - await setup(defaultProps as unknown as UseWorkspaceLoaderProps); + renderHook( + () => useWorkspaceLoader(defaultProps), + defaultProps as RenderHookOptions<UseWorkspaceLoaderProps> + ); }); - expect(defaultProps.spaces.ui.redirectLegacyUrl).not.toHaveBeenCalled(); + expect(defaultProps.spaces?.ui.redirectLegacyUrl).not.toHaveBeenCalled(); expect(defaultProps.store.dispatch).toHaveBeenCalled(); }); it('should redirect if outcome is aliasMatch', async () => { @@ -83,11 +70,15 @@ describe('use_workspace_loader', () => { alias_target_id: 'aliasTargetId', }), }, - }; + } as unknown as UseWorkspaceLoaderProps; + await act(async () => { - await setup(props as unknown as UseWorkspaceLoaderProps); + renderHook( + () => useWorkspaceLoader(props), + props as RenderHookOptions<UseWorkspaceLoaderProps> + ); }); - expect(props.spaces.ui.redirectLegacyUrl).toHaveBeenCalledWith( + expect(props.spaces?.ui.redirectLegacyUrl).toHaveBeenCalledWith( '#/workspace/aliasTargetId?query={}', 'Graph' ); diff --git a/x-pack/plugins/graph/public/state_management/mocks.ts b/x-pack/plugins/graph/public/state_management/mocks.ts index 6f7b5dba2e4a1..5003e550f87a1 100644 --- a/x-pack/plugins/graph/public/state_management/mocks.ts +++ b/x-pack/plugins/graph/public/state_management/mocks.ts @@ -42,6 +42,7 @@ export function createMockGraphStore({ }): MockedGraphEnvironment { const workspaceMock = { runLayout: jest.fn(), + simpleSearch: jest.fn(), nodes: [], edges: [], options: {}, @@ -55,7 +56,7 @@ export function createMockGraphStore({ chrome: { setBreadcrumbs: jest.fn(), } as unknown as ChromeStart, - createWorkspace: jest.fn(), + createWorkspace: jest.fn((index, advancedSettings) => workspaceMock), getWorkspace: jest.fn(() => workspaceMock), indexPatternProvider: { get: jest.fn(() => diff --git a/x-pack/plugins/graph/public/state_management/persistence.test.ts b/x-pack/plugins/graph/public/state_management/persistence.test.ts index dc59869fafd4c..2ef68f2198070 100644 --- a/x-pack/plugins/graph/public/state_management/persistence.test.ts +++ b/x-pack/plugins/graph/public/state_management/persistence.test.ts @@ -23,6 +23,18 @@ import { settingsSelector } from './advanced_settings'; import { openSaveModal } from '../services/save_modal'; const waitForPromise = () => new Promise((r) => setTimeout(r)); +// mocking random id generator function +jest.mock('@elastic/eui', () => { + const original = jest.requireActual('@elastic/eui'); + + return { + ...original, + htmlIdGenerator: (fn: unknown) => { + let counter = 0; + return () => counter++; + }, + }; +}); jest.mock('../services/persistence', () => ({ lookupIndexPatternId: jest.fn(() => ({ id: '123', attributes: { title: 'test-pattern' } })), diff --git a/x-pack/plugins/graph/server/index.ts b/x-pack/plugins/graph/server/index.ts index 10ddca631a898..528e122da9a4d 100644 --- a/x-pack/plugins/graph/server/index.ts +++ b/x-pack/plugins/graph/server/index.ts @@ -18,4 +18,5 @@ export const config: PluginConfigDescriptor<ConfigSchema> = { savePolicy: true, }, schema: configSchema, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/hot_phase_validation.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/hot_phase_validation.test.ts index 6cbc28ec161f2..6dca2b7b23fb7 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/hot_phase_validation.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/hot_phase_validation.test.ts @@ -158,13 +158,23 @@ describe('<EditPolicy /> hot phase validation', () => { }); describe('shrink', () => { - test(`doesn't allow 0 for shrink`, async () => { - await actions.hot.setShrink('0'); + test(`doesn't allow 0 for shrink size`, async () => { + await actions.hot.setShrinkSize('0'); actions.errors.waitForValidation(); actions.errors.expectMessages([i18nTexts.editPolicy.errors.numberGreatThan0Required]); }); - test(`doesn't allow -1 for shrink`, async () => { - await actions.hot.setShrink('-1'); + test(`doesn't allow -1 for shrink size`, async () => { + await actions.hot.setShrinkSize('-1'); + actions.errors.waitForValidation(); + actions.errors.expectMessages([i18nTexts.editPolicy.errors.numberGreatThan0Required]); + }); + test(`doesn't allow 0 for shrink count`, async () => { + await actions.hot.setShrinkCount('0'); + actions.errors.waitForValidation(); + actions.errors.expectMessages([i18nTexts.editPolicy.errors.numberGreatThan0Required]); + }); + test(`doesn't allow -1 for shrink count`, async () => { + await actions.hot.setShrinkCount('-1'); actions.errors.waitForValidation(); actions.errors.expectMessages([i18nTexts.editPolicy.errors.numberGreatThan0Required]); }); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/warm_phase_validation.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/warm_phase_validation.test.ts index 0b8bfceebfaf4..741611f2d2c3b 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/warm_phase_validation.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/warm_phase_validation.test.ts @@ -58,17 +58,33 @@ describe('<EditPolicy /> warm phase validation', () => { }); describe('shrink', () => { - test(`doesn't allow 0 for shrink`, async () => { + test(`doesn't allow 0 for shrink size`, async () => { const { actions } = testBed; - await actions.warm.setShrink('0'); + await actions.warm.setShrinkSize('0'); actions.errors.waitForValidation(); actions.errors.expectMessages([i18nTexts.editPolicy.errors.numberGreatThan0Required]); }); - test(`doesn't allow -1 for shrink`, async () => { + test(`doesn't allow -1 for shrink size`, async () => { const { actions } = testBed; - await actions.warm.setShrink('-1'); + await actions.warm.setShrinkSize('-1'); + + actions.errors.waitForValidation(); + + actions.errors.expectMessages([i18nTexts.editPolicy.errors.numberGreatThan0Required]); + }); + test(`doesn't allow 0 for shrink count`, async () => { + const { actions } = testBed; + await actions.warm.setShrinkCount('0'); + + actions.errors.waitForValidation(); + + actions.errors.expectMessages([i18nTexts.editPolicy.errors.numberGreatThan0Required]); + }); + test(`doesn't allow -1 for shrink count`, async () => { + const { actions } = testBed; + await actions.warm.setShrinkCount('-1'); actions.errors.waitForValidation(); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts index c315bde7e37d8..7a4d1f7efca63 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts @@ -171,7 +171,7 @@ describe('<EditPolicy /> serialization', () => { await actions.hot.toggleForceMerge(); await actions.hot.setForcemergeSegmentsCount('123'); await actions.hot.setBestCompression(true); - await actions.hot.setShrink('2'); + await actions.hot.setShrinkCount('2'); await actions.hot.toggleReadonly(); await actions.hot.setIndexPriority('123'); @@ -274,7 +274,7 @@ describe('<EditPolicy /> serialization', () => { await actions.warm.setDataAllocation('node_attrs'); await actions.warm.setSelectedNodeAttribute('test:123'); await actions.warm.setReplicas('123'); - await actions.warm.setShrink('123'); + await actions.warm.setShrinkCount('123'); await actions.warm.toggleForceMerge(); await actions.warm.setForcemergeSegmentsCount('123'); await actions.warm.setBestCompression(true); @@ -546,4 +546,49 @@ describe('<EditPolicy /> serialization', () => { }); }); }); + + describe('shrink', () => { + test('shrink shard size', async () => { + const { actions } = testBed; + await actions.hot.setShrinkSize('50'); + + await actions.togglePhase('warm'); + await actions.warm.setMinAgeValue('11'); + await actions.warm.setShrinkSize('100'); + + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + expect(entirePolicy).toMatchInlineSnapshot(` + Object { + "name": "my_policy", + "phases": Object { + "hot": Object { + "actions": Object { + "rollover": Object { + "max_age": "30d", + "max_primary_shard_size": "50gb", + }, + "shrink": Object { + "max_primary_shard_size": "50gb", + }, + }, + "min_age": "0ms", + }, + "warm": Object { + "actions": Object { + "set_priority": Object { + "priority": 50, + }, + "shrink": Object { + "max_primary_shard_size": "100gb", + }, + }, + "min_age": "11d", + }, + }, + } + `); + }); + }); }); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/shrink_actions.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/shrink_actions.ts index 29c3e4a04a9a1..394a64696d5eb 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/shrink_actions.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/actions/shrink_actions.ts @@ -6,18 +6,41 @@ */ import { TestBed } from '@kbn/test/jest'; +import { act } from 'react-dom/test-utils'; import { Phase } from '../../../../common/types'; -import { createFormToggleAndSetValueAction } from './form_toggle_and_set_value_action'; +import { createFormSetValueAction } from './form_set_value_action'; export const createShrinkActions = (testBed: TestBed, phase: Phase) => { - const { exists } = testBed; - const toggleSelector = `${phase}-shrinkSwitch`; + const { exists, form, component, find } = testBed; + const toggleShrinkSelector = `${phase}-shrinkSwitch`; + const shrinkSizeSelector = `${phase}-primaryShardSize`; + const shrinkCountSelector = `${phase}-primaryShardCount`; + + const changeShrinkRadioButton = async (selector: string) => { + await act(async () => { + await find(selector).find('input').simulate('change'); + }); + component.update(); + }; return { - shrinkExists: () => exists(toggleSelector), - setShrink: createFormToggleAndSetValueAction( - testBed, - toggleSelector, - `${phase}-primaryShardCount` - ), + shrinkExists: () => exists(toggleShrinkSelector), + setShrinkCount: async (value: string) => { + if (!exists(shrinkCountSelector) && !exists(shrinkSizeSelector)) { + await form.toggleEuiSwitch(toggleShrinkSelector); + } + if (!exists(shrinkCountSelector)) { + await changeShrinkRadioButton(`${phase}-configureShardCount`); + } + await createFormSetValueAction(testBed, shrinkCountSelector)(value); + }, + setShrinkSize: async (value: string) => { + if (!exists(shrinkCountSelector) && !exists(shrinkSizeSelector)) { + await form.toggleEuiSwitch(toggleShrinkSelector); + } + if (!exists(shrinkSizeSelector)) { + await changeShrinkRadioButton(`${phase}-configureShardSize`); + } + await createFormSetValueAction(testBed, shrinkSizeSelector)(value); + }, }; }; diff --git a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts index 3a338c80fa56c..b9922a0d59459 100644 --- a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts +++ b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts @@ -168,7 +168,8 @@ export interface AllocateAction { } export interface ShrinkAction { - number_of_shards: number; + number_of_shards?: number; + max_primary_shard_size?: string; } export interface ForcemergeAction { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/described_form_row/described_form_row.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/described_form_row/described_form_row.tsx index cc05ac2c47872..98fe3d52bc6ae 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/described_form_row/described_form_row.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/described_form_row/described_form_row.tsx @@ -29,7 +29,7 @@ export interface SwitchProps } export type Props = EuiDescribedFormGroupProps & { - children: (() => JSX.Element) | JSX.Element | JSX.Element[] | undefined; + children: (() => JSX.Element) | JSX.Element | JSX.Element[] | undefined | null; switchProps?: SwitchProps; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_age_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_age_field.tsx index 7fbdaf344b8fa..7ee861ce8071e 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_age_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_age_field.tsx @@ -11,10 +11,8 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { NumericField } from '../../../../../../../shared_imports'; import { UseField } from '../../../../form'; -import { ROLLOVER_FORM_PATHS } from '../../../../constants'; -import { UnitField } from './unit_field'; - -import { maxAgeUnits } from '../constants'; +import { ROLLOVER_FORM_PATHS, timeUnits } from '../../../../constants'; +import { UnitField } from '../../shared_fields/unit_field'; export const MaxAgeField: FunctionComponent = () => { return ( @@ -30,7 +28,7 @@ export const MaxAgeField: FunctionComponent = () => { append: ( <UnitField path="_meta.hot.customRollover.maxAgeUnit" - options={maxAgeUnits} + options={timeUnits} euiFieldProps={{ 'data-test-subj': 'hot-selectedMaxAgeUnits', 'aria-label': i18n.translate( diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_index_size_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_index_size_field.tsx index e4e700a84118c..52dc9445c261f 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_index_size_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_index_size_field.tsx @@ -11,10 +11,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import { NumericField } from '../../../../../../../shared_imports'; import { UseField } from '../../../../form'; -import { ROLLOVER_FORM_PATHS } from '../../../../constants'; -import { UnitField } from './unit_field'; - -import { maxSizeStoredUnits } from '../constants'; +import { byteSizeUnits, ROLLOVER_FORM_PATHS } from '../../../../constants'; +import { UnitField } from '../../shared_fields/unit_field'; const i18nTexts = { deprecationMessage: i18n.translate( @@ -52,7 +50,7 @@ export const MaxIndexSizeField: FunctionComponent = () => { append: ( <UnitField path="_meta.hot.customRollover.maxStorageSizeUnit" - options={maxSizeStoredUnits} + options={byteSizeUnits} euiFieldProps={{ 'data-test-subj': 'hot-selectedMaxSizeStoredUnits', 'aria-label': i18nTexts.maxSizeUnit.ariaLabel, diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_primary_shard_size_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_primary_shard_size_field.tsx index d9c7ed5a24b99..97d784fbe7327 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_primary_shard_size_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/max_primary_shard_size_field.tsx @@ -6,15 +6,13 @@ */ import React, { FunctionComponent } from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { NumericField } from '../../../../../../../shared_imports'; import { UseField } from '../../../../form'; -import { ROLLOVER_FORM_PATHS } from '../../../../constants'; -import { UnitField } from './unit_field'; - -import { maxSizeStoredUnits } from '../constants'; +import { byteSizeUnits, ROLLOVER_FORM_PATHS } from '../../../../constants'; +import { i18nTexts } from '../../../../i18n_texts'; +import { UnitField } from '../../shared_fields/unit_field'; export const MaxPrimaryShardSizeField: FunctionComponent = () => { return ( @@ -30,15 +28,10 @@ export const MaxPrimaryShardSizeField: FunctionComponent = () => { append: ( <UnitField path="_meta.hot.customRollover.maxPrimaryShardSizeUnit" - options={maxSizeStoredUnits} + options={byteSizeUnits} euiFieldProps={{ 'data-test-subj': 'hot-selectedMaxPrimaryShardSizeUnits', - 'aria-label': i18n.translate( - 'xpack.indexLifecycleMgmt.hotPhase.maximumPrimaryShardSizeAriaLabel', - { - defaultMessage: 'Maximum primary shard size units', - } - ), + 'aria-label': i18nTexts.editPolicy.maxPrimaryShardSizeUnitsLabel, }} /> ), diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/constants.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/constants.ts deleted file mode 100644 index 3b03c7c7ec0c8..0000000000000 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/constants.ts +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const maxSizeStoredUnits = [ - { - value: 'gb', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.gigabytesLabel', { - defaultMessage: 'gigabytes', - }), - }, - { - value: 'mb', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.megabytesLabel', { - defaultMessage: 'megabytes', - }), - }, - { - value: 'b', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.bytesLabel', { - defaultMessage: 'bytes', - }), - }, - { - value: 'kb', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.kilobytesLabel', { - defaultMessage: 'kilobytes', - }), - }, - { - value: 'tb', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.terabytesLabel', { - defaultMessage: 'terabytes', - }), - }, - { - value: 'pb', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.petabytesLabel', { - defaultMessage: 'petabytes', - }), - }, -]; - -export const maxAgeUnits = [ - { - value: 'd', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.daysLabel', { - defaultMessage: 'days', - }), - }, - { - value: 'h', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.hoursLabel', { - defaultMessage: 'hours', - }), - }, - { - value: 'm', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.minutesLabel', { - defaultMessage: 'minutes', - }), - }, - { - value: 's', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.secondsLabel', { - defaultMessage: 'seconds', - }), - }, - { - value: 'ms', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.millisecondsLabel', { - defaultMessage: 'milliseconds', - }), - }, - { - value: 'micros', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.microsecondsLabel', { - defaultMessage: 'microseconds', - }), - }, - { - value: 'nanos', - text: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.nanosecondsLabel', { - defaultMessage: 'nanoseconds', - }), - }, -]; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/min_age_field/min_age_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/min_age_field/min_age_field.tsx index 2c42d76415dbc..b6c6102425d12 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/min_age_field/min_age_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/min_age_field/min_age_field.tsx @@ -25,43 +25,10 @@ import { PhaseWithTiming } from '../../../../../../../../common/types'; import { getFieldValidityAndErrorMessage, useFormData } from '../../../../../../../shared_imports'; import { UseField, useConfiguration, useGlobalFields } from '../../../../form'; import { getPhaseMinAgeInMilliseconds } from '../../../../lib'; +import { timeUnits } from '../../../../constants'; import { getUnitsAriaLabelForPhase, getTimingLabelForPhase } from './util'; const i18nTexts = { - daysOptionLabel: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.daysOptionLabel', { - defaultMessage: 'days', - }), - - hoursOptionLabel: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.hoursOptionLabel', { - defaultMessage: 'hours', - }), - minutesOptionLabel: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.minutesOptionLabel', { - defaultMessage: 'minutes', - }), - - secondsOptionLabel: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.secondsOptionLabel', { - defaultMessage: 'seconds', - }), - millisecondsOptionLabel: i18n.translate( - 'xpack.indexLifecycleMgmt.editPolicy.milliSecondsOptionLabel', - { - defaultMessage: 'milliseconds', - } - ), - - microsecondsOptionLabel: i18n.translate( - 'xpack.indexLifecycleMgmt.editPolicy.microSecondsOptionLabel', - { - defaultMessage: 'microseconds', - } - ), - - nanosecondsOptionLabel: i18n.translate( - 'xpack.indexLifecycleMgmt.editPolicy.nanoSecondsOptionLabel', - { - defaultMessage: 'nanoseconds', - } - ), rolloverToolTipDescription: i18n.translate( 'xpack.indexLifecycleMgmt.editPolicy.minimumAge.rolloverToolTipDescription', { @@ -180,36 +147,7 @@ export const MinAgeField: FunctionComponent<Props> = ({ phase }): React.ReactEle append={selectAppendValue} data-test-subj={`${phase}-selectedMinimumAgeUnits`} aria-label={getUnitsAriaLabelForPhase(phase)} - options={[ - { - value: 'd', - text: i18nTexts.daysOptionLabel, - }, - { - value: 'h', - text: i18nTexts.hoursOptionLabel, - }, - { - value: 'm', - text: i18nTexts.minutesOptionLabel, - }, - { - value: 's', - text: i18nTexts.secondsOptionLabel, - }, - { - value: 'ms', - text: i18nTexts.millisecondsOptionLabel, - }, - { - value: 'micros', - text: i18nTexts.microsecondsOptionLabel, - }, - { - value: 'nanos', - text: i18nTexts.nanosecondsOptionLabel, - }, - ]} + options={timeUnits} /> ); }} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/shrink_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/shrink_field.tsx index 8ac387ba106b7..1becf90de4d46 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/shrink_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/shrink_field.tsx @@ -6,24 +6,35 @@ */ import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTextColor } from '@elastic/eui'; +import { EuiTextColor, EuiRadioGroup, EuiSpacer } from '@elastic/eui'; import React, { FunctionComponent } from 'react'; -import { NumericField } from '../../../../../../shared_imports'; +import { get } from 'lodash'; +import { NumericField, useFormData } from '../../../../../../shared_imports'; import { useEditPolicyContext } from '../../../edit_policy_context'; -import { UseField } from '../../../form'; +import { UseField, useGlobalFields } from '../../../form'; import { i18nTexts } from '../../../i18n_texts'; import { LearnMoreLink, DescribedFormRow } from '../../'; +import { byteSizeUnits } from '../../../constants'; +import { UnitField } from './unit_field'; interface Props { phase: 'hot' | 'warm'; } export const ShrinkField: FunctionComponent<Props> = ({ phase }) => { - const path = `phases.${phase}.actions.shrink.number_of_shards`; + const globalFields = useGlobalFields(); + const { setValue: setIsUsingShardSize } = + globalFields[`${phase}IsUsingShardSize` as 'hotIsUsingShardSize']; const { policy } = useEditPolicyContext(); + const isUsingShardSizePath = `_meta.${phase}.shrink.isUsingShardSize`; + const [formData] = useFormData({ watch: [isUsingShardSizePath] }); + const isUsingShardSize: boolean | undefined = get(formData, isUsingShardSizePath); + const path = `phases.${phase}.actions.shrink.${ + isUsingShardSize ? 'max_primary_shard_size' : 'number_of_shards' + }`; return ( <DescribedFormRow title={ @@ -51,22 +62,51 @@ export const ShrinkField: FunctionComponent<Props> = ({ phase }) => { }} fullWidth > - <EuiFlexGroup> - <EuiFlexItem> + {isUsingShardSize === undefined ? null : ( + <> + <EuiRadioGroup + options={[ + { + id: `${phase}-configureShardCount`, + label: i18nTexts.editPolicy.shrinkCountLabel, + 'data-test-subj': `${phase}-configureShardCount`, + }, + { + id: `${phase}-configureShardSize`, + label: i18nTexts.editPolicy.shrinkSizeLabel, + 'data-test-subj': `${phase}-configureShardSize`, + }, + ]} + idSelected={ + isUsingShardSize ? `${phase}-configureShardSize` : `${phase}-configureShardCount` + } + onChange={(id) => setIsUsingShardSize(id === `${phase}-configureShardSize`)} + /> + <EuiSpacer /> <UseField path={path} + key={path} component={NumericField} componentProps={{ fullWidth: false, euiFieldProps: { - 'data-test-subj': `${phase}-primaryShardCount`, + 'data-test-subj': `${phase}-primaryShard${isUsingShardSize ? 'Size' : 'Count'}`, min: 1, + append: isUsingShardSize ? ( + <UnitField + path={`_meta.${phase}.shrink.maxPrimaryShardSizeUnits`} + options={byteSizeUnits} + euiFieldProps={{ + 'data-test-subj': `${phase}-shrinkMaxPrimaryShardSizeUnits`, + 'aria-label': i18nTexts.editPolicy.maxPrimaryShardSizeUnitsLabel, + }} + /> + ) : null, }, }} /> - </EuiFlexItem> - </EuiFlexGroup> - <EuiSpacer /> + </> + )} </DescribedFormRow> ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/unit_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/unit_field.tsx similarity index 97% rename from x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/unit_field.tsx rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/unit_field.tsx index 2ef8917d53989..6b76b0357b8ba 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/components/unit_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/unit_field.tsx @@ -7,8 +7,7 @@ import React, { FunctionComponent, useState } from 'react'; import { EuiFilterSelectItem, EuiPopover, EuiButtonEmpty } from '@elastic/eui'; - -import { UseField } from '../../../../form'; +import { UseField } from '../../../form'; interface Props { path: string; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/constants.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/constants.ts index 88d5f6e138882..bd8c06de7e402 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/constants.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/constants.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { i18n } from '@kbn/i18n'; + export const isUsingCustomRolloverPath = '_meta.hot.customRollover.enabled'; export const isUsingDefaultRolloverPath = '_meta.hot.isUsingDefaultRollover'; @@ -25,3 +27,93 @@ export const ROLLOVER_FORM_PATHS = { * exist as a "managed" repository. */ export const CLOUD_DEFAULT_REPO = 'found-snapshots'; + +/* + * Labels for byte size units + */ +export const byteSizeUnits = [ + { + value: 'gb', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.byteSizeUnits.gigabytesLabel', { + defaultMessage: 'gigabytes', + }), + }, + { + value: 'mb', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.byteSizeUnits.megabytesLabel', { + defaultMessage: 'megabytes', + }), + }, + { + value: 'b', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.byteSizeUnits.bytesLabel', { + defaultMessage: 'bytes', + }), + }, + { + value: 'kb', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.byteSizeUnits.kilobytesLabel', { + defaultMessage: 'kilobytes', + }), + }, + { + value: 'tb', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.byteSizeUnits.terabytesLabel', { + defaultMessage: 'terabytes', + }), + }, + { + value: 'pb', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.byteSizeUnits.petabytesLabel', { + defaultMessage: 'petabytes', + }), + }, +]; + +/* + * Labels for time units + */ +export const timeUnits = [ + { + value: 'd', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.timeUnits.daysLabel', { + defaultMessage: 'days', + }), + }, + { + value: 'h', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.timeUnits.hoursLabel', { + defaultMessage: 'hours', + }), + }, + { + value: 'm', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.timeUnits.minutesLabel', { + defaultMessage: 'minutes', + }), + }, + { + value: 's', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.timeUnits.secondsLabel', { + defaultMessage: 'seconds', + }), + }, + { + value: 'ms', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.timeUnits.millisecondsLabel', { + defaultMessage: 'milliseconds', + }), + }, + { + value: 'micros', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.timeUnits.microsecondsLabel', { + defaultMessage: 'microseconds', + }), + }, + { + value: 'nanos', + text: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.timeUnits.nanosecondsLabel', { + defaultMessage: 'nanoseconds', + }), + }, +]; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts index dc3714bdaf8da..1ce5b8aa7a717 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts @@ -39,6 +39,7 @@ export const createDeserializer = }, bestCompression: hot?.actions?.forcemerge?.index_codec === 'best_compression', readonlyEnabled: Boolean(hot?.actions?.readonly), + shrink: { isUsingShardSize: Boolean(hot?.actions.shrink?.max_primary_shard_size) }, }, warm: { enabled: Boolean(warm), @@ -47,6 +48,7 @@ export const createDeserializer = dataTierAllocationType: determineDataTierAllocationType(warm?.actions), readonlyEnabled: Boolean(warm?.actions?.readonly), minAgeToMilliSeconds: -1, + shrink: { isUsingShardSize: Boolean(warm?.actions.shrink?.max_primary_shard_size) }, }, cold: { enabled: Boolean(cold), @@ -97,6 +99,13 @@ export const createDeserializer = draft._meta.hot.customRollover.maxAgeUnit = maxAge.units; } } + if (draft.phases.hot?.actions.shrink?.max_primary_shard_size) { + const primaryShardSize = splitSizeAndUnits( + draft.phases.hot.actions.shrink.max_primary_shard_size! + ); + draft.phases.hot.actions.shrink.max_primary_shard_size = primaryShardSize.size; + draft._meta.hot.shrink.maxPrimaryShardSizeUnits = primaryShardSize.units; + } if (draft.phases.warm) { if (draft.phases.warm.actions?.allocate?.require) { @@ -110,6 +119,14 @@ export const createDeserializer = draft.phases.warm.min_age = minAge.size; draft._meta.warm.minAgeUnit = minAge.units; } + + if (draft.phases.warm.actions.shrink?.max_primary_shard_size) { + const primaryShardSize = splitSizeAndUnits( + draft.phases.warm.actions.shrink.max_primary_shard_size! + ); + draft.phases.warm.actions.shrink.max_primary_shard_size = primaryShardSize.size; + draft._meta.warm.shrink.maxPrimaryShardSizeUnits = primaryShardSize.units; + } } if (draft.phases.cold) { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/global_fields_context.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/global_fields_context.tsx index 5834fe5b9ea77..bb02e5a50a48a 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/global_fields_context.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/global_fields_context.tsx @@ -11,13 +11,15 @@ import { UseMultiFields, FieldHook, FieldConfig } from '../../../../shared_impor /** * Those are the fields that we always want present in our form. */ -interface GlobalFieldsTypes { +export interface GlobalFieldsTypes { deleteEnabled: boolean; searchableSnapshotRepo: string; warmMinAgeMilliSeconds: number; coldMinAgeMilliSeconds: number; frozenMinAgeMilliSeconds: number; deleteMinAgeMilliSeconds: number; + hotIsUsingShardSize: boolean; + warmIsUsingShardSize: boolean; } type GlobalFields = { @@ -46,6 +48,12 @@ export const globalFields: Record<keyof GlobalFields, { path: string; config?: F deleteMinAgeMilliSeconds: { path: '_meta.delete.minAgeToMilliSeconds', }, + hotIsUsingShardSize: { + path: '_meta.hot.shrink.isUsingShardSize', + }, + warmIsUsingShardSize: { + path: '_meta.warm.shrink.isUsingShardSize', + }, }; export const GlobalFieldsProvider: FunctionComponent = ({ children }) => { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts index c26f54cbb6f5a..24112cf4725d2 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts @@ -93,6 +93,22 @@ const numberOfShardsField = { label: i18n.translate('xpack.indexLifecycleMgmt.shrink.numberOfPrimaryShardsLabel', { defaultMessage: 'Number of primary shards', }), + defaultValue: 1, + validations: [ + { + validator: emptyField(i18nTexts.editPolicy.errors.numberRequired), + }, + { + validator: numberGreaterThanField({ + message: i18nTexts.editPolicy.errors.numberGreatThan0Required, + than: 0, + }), + }, + ], + serializer: serializers.stringToNumber, +}; +const shardSizeField = { + label: i18nTexts.editPolicy.maxPrimaryShardSizeLabel, validations: [ { validator: emptyField(i18nTexts.editPolicy.errors.numberRequired), @@ -173,6 +189,14 @@ export const getSchema = (isCloudEnabled: boolean): FormSchema => ({ defaultValue: false, label: i18nTexts.editPolicy.readonlyEnabledFieldLabel, }, + shrink: { + isUsingShardSize: { + defaultValue: false, + }, + maxPrimaryShardSizeUnits: { + defaultValue: 'gb', + }, + }, }, warm: { enabled: { @@ -207,6 +231,14 @@ export const getSchema = (isCloudEnabled: boolean): FormSchema => ({ defaultValue: false, label: i18nTexts.editPolicy.readonlyEnabledFieldLabel, }, + shrink: { + isUsingShardSize: { + defaultValue: false, + }, + maxPrimaryShardSizeUnits: { + defaultValue: 'gb', + }, + }, }, cold: { enabled: { @@ -334,12 +366,7 @@ export const getSchema = (isCloudEnabled: boolean): FormSchema => ({ fieldsToValidateOnChange: rolloverFormPaths, }, max_primary_shard_size: { - label: i18n.translate( - 'xpack.indexLifecycleMgmt.hotPhase.maximumPrimaryShardSizeLabel', - { - defaultMessage: 'Maximum primary shard size', - } - ), + label: i18nTexts.editPolicy.maxPrimaryShardSizeLabel, validations: [ { validator: rolloverThresholdsValidator, @@ -370,6 +397,7 @@ export const getSchema = (isCloudEnabled: boolean): FormSchema => ({ }, shrink: { number_of_shards: numberOfShardsField, + max_primary_shard_size: shardSizeField, }, set_priority: { priority: getPriorityField('hot'), @@ -385,6 +413,7 @@ export const getSchema = (isCloudEnabled: boolean): FormSchema => ({ }, shrink: { number_of_shards: numberOfShardsField, + max_primary_shard_size: shardSizeField, }, forcemerge: { max_num_segments: maxNumSegmentsField, diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts index cf81468dd2b48..652f045922d4d 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts @@ -43,100 +43,104 @@ export const createSerializer = */ if (draft.phases.hot) { draft.phases.hot.min_age = draft.phases.hot.min_age ?? '0ms'; - } - if (draft.phases.hot?.actions) { - const hotPhaseActions = draft.phases.hot.actions; + if (draft.phases.hot?.actions) { + const hotPhaseActions = draft.phases.hot.actions; - /** - * HOT PHASE ROLLOVER - */ - if (isUsingRollover) { - if (_meta.hot?.isUsingDefaultRollover) { - hotPhaseActions.rollover = cloneDeep(defaultRolloverAction); - } else { - // Rollover may not exist if editing an existing policy with initially no rollover configured - if (!hotPhaseActions.rollover) { - hotPhaseActions.rollover = {}; + /** + * HOT PHASE ROLLOVER + */ + if (isUsingRollover) { + if (_meta.hot?.isUsingDefaultRollover) { + hotPhaseActions.rollover = cloneDeep(defaultRolloverAction); + } else { + // Rollover may not exist if editing an existing policy with initially no rollover configured + if (!hotPhaseActions.rollover) { + hotPhaseActions.rollover = {}; + } + + // We are using user-defined, custom rollover settings. + if (updatedPolicy.phases.hot!.actions.rollover?.max_age) { + hotPhaseActions.rollover.max_age = `${hotPhaseActions.rollover.max_age}${_meta.hot?.customRollover.maxAgeUnit}`; + } else { + delete hotPhaseActions.rollover.max_age; + } + + if (typeof updatedPolicy.phases.hot!.actions.rollover?.max_docs !== 'number') { + delete hotPhaseActions.rollover.max_docs; + } + + if (updatedPolicy.phases.hot!.actions.rollover?.max_primary_shard_size) { + hotPhaseActions.rollover.max_primary_shard_size = `${hotPhaseActions.rollover.max_primary_shard_size}${_meta.hot?.customRollover.maxPrimaryShardSizeUnit}`; + } else { + delete hotPhaseActions.rollover.max_primary_shard_size; + } + + if (updatedPolicy.phases.hot!.actions.rollover?.max_size) { + hotPhaseActions.rollover.max_size = `${hotPhaseActions.rollover.max_size}${_meta.hot?.customRollover.maxStorageSizeUnit}`; + } else { + delete hotPhaseActions.rollover.max_size; + } } - // We are using user-defined, custom rollover settings. - if (updatedPolicy.phases.hot!.actions.rollover?.max_age) { - hotPhaseActions.rollover.max_age = `${hotPhaseActions.rollover.max_age}${_meta.hot?.customRollover.maxAgeUnit}`; + /** + * HOT PHASE FORCEMERGE + */ + if (!updatedPolicy.phases.hot!.actions?.forcemerge) { + delete hotPhaseActions.forcemerge; + } else if (_meta.hot?.bestCompression) { + hotPhaseActions.forcemerge!.index_codec = 'best_compression'; } else { - delete hotPhaseActions.rollover.max_age; + delete hotPhaseActions.forcemerge!.index_codec; } - if (typeof updatedPolicy.phases.hot!.actions.rollover?.max_docs !== 'number') { - delete hotPhaseActions.rollover.max_docs; + if (_meta.hot?.bestCompression && hotPhaseActions.forcemerge) { + hotPhaseActions.forcemerge.index_codec = 'best_compression'; } - if (updatedPolicy.phases.hot!.actions.rollover?.max_primary_shard_size) { - hotPhaseActions.rollover.max_primary_shard_size = `${hotPhaseActions.rollover.max_primary_shard_size}${_meta.hot?.customRollover.maxPrimaryShardSizeUnit}`; + /** + * HOT PHASE READ-ONLY + */ + if (_meta.hot?.readonlyEnabled) { + hotPhaseActions.readonly = hotPhaseActions.readonly ?? {}; } else { - delete hotPhaseActions.rollover.max_primary_shard_size; + delete hotPhaseActions.readonly; } - - if (updatedPolicy.phases.hot!.actions.rollover?.max_size) { - hotPhaseActions.rollover.max_size = `${hotPhaseActions.rollover.max_size}${_meta.hot?.customRollover.maxStorageSizeUnit}`; + /** + * HOT PHASE SHRINK + */ + if (!updatedPolicy.phases.hot?.actions?.shrink) { + delete hotPhaseActions.shrink; + } else if (_meta.hot.shrink.isUsingShardSize) { + delete hotPhaseActions.shrink!.number_of_shards; + hotPhaseActions.shrink!.max_primary_shard_size = `${hotPhaseActions.shrink?.max_primary_shard_size}${_meta.hot?.shrink.maxPrimaryShardSizeUnits}`; } else { - delete hotPhaseActions.rollover.max_size; + delete hotPhaseActions.shrink!.max_primary_shard_size; } + } else { + delete hotPhaseActions.rollover; + delete hotPhaseActions.forcemerge; + delete hotPhaseActions.readonly; + delete hotPhaseActions.shrink; } - /** - * HOT PHASE FORCEMERGE + * HOT PHASE SET PRIORITY */ - if (!updatedPolicy.phases.hot!.actions?.forcemerge) { - delete hotPhaseActions.forcemerge; - } else if (_meta.hot?.bestCompression) { - hotPhaseActions.forcemerge!.index_codec = 'best_compression'; - } else { - delete hotPhaseActions.forcemerge!.index_codec; - } - - if (_meta.hot?.bestCompression && hotPhaseActions.forcemerge) { - hotPhaseActions.forcemerge.index_codec = 'best_compression'; + if (!updatedPolicy.phases.hot!.actions?.set_priority) { + delete hotPhaseActions.set_priority; } /** - * HOT PHASE READ-ONLY + * HOT PHASE SEARCHABLE SNAPSHOT */ - if (_meta.hot?.readonlyEnabled) { - hotPhaseActions.readonly = hotPhaseActions.readonly ?? {}; + if (updatedPolicy.phases.hot!.actions?.searchable_snapshot) { + hotPhaseActions.searchable_snapshot = { + ...hotPhaseActions.searchable_snapshot, + snapshot_repository: _meta.searchableSnapshot.repository, + }; } else { - delete hotPhaseActions.readonly; + delete hotPhaseActions.searchable_snapshot; } - } else { - delete hotPhaseActions.rollover; - delete hotPhaseActions.forcemerge; - delete hotPhaseActions.readonly; - } - - /** - * HOT PHASE SET PRIORITY - */ - if (!updatedPolicy.phases.hot!.actions?.set_priority) { - delete hotPhaseActions.set_priority; - } - - /** - * HOT PHASE SHRINK - */ - if (!updatedPolicy.phases.hot?.actions?.shrink) { - delete hotPhaseActions.shrink; - } - - /** - * HOT PHASE SEARCHABLE SNAPSHOT - */ - if (updatedPolicy.phases.hot!.actions?.searchable_snapshot) { - hotPhaseActions.searchable_snapshot = { - ...hotPhaseActions.searchable_snapshot, - snapshot_repository: _meta.searchableSnapshot.repository, - }; - } else { - delete hotPhaseActions.searchable_snapshot; } } @@ -197,6 +201,11 @@ export const createSerializer = */ if (!updatedPolicy.phases.warm?.actions?.shrink) { delete warmPhase.actions.shrink; + } else if (_meta.warm.shrink.isUsingShardSize) { + delete warmPhase.actions.shrink!.number_of_shards; + warmPhase.actions.shrink!.max_primary_shard_size = `${warmPhase.actions.shrink?.max_primary_shard_size}${_meta.warm?.shrink.maxPrimaryShardSizeUnits}`; + } else { + delete warmPhase.actions.shrink!.max_primary_shard_size; } } else { delete draft.phases.warm; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts index bfc31c220825a..dca07fa6b1ead 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts @@ -9,9 +9,21 @@ import { i18n } from '@kbn/i18n'; export const i18nTexts = { editPolicy: { - shrinkLabel: i18n.translate('xpack.indexLifecycleMgmt.shrink.indexFieldLabel', { + shrinkLabel: i18n.translate('xpack.indexLifecycleMgmt.shrink.enableShrinkLabel', { defaultMessage: 'Shrink index', }), + shrinkCountLabel: i18n.translate( + 'xpack.indexLifecycleMgmt.editPolicy.shrink.configureShardCountLabel', + { + defaultMessage: 'Configure shard count', + } + ), + shrinkSizeLabel: i18n.translate( + 'xpack.indexLifecycleMgmt.editPolicy.shrink.configureShardSizeLabel', + { + defaultMessage: 'Configure shard size', + } + ), rolloverOffsetsHotPhaseTiming: i18n.translate( 'xpack.indexLifecycleMgmt.rollover.rolloverOffsetsPhaseTimingDescription', { @@ -89,6 +101,18 @@ export const i18nTexts = { defaultMessage: 'Searchable snapshot storage', } ), + maxPrimaryShardSizeLabel: i18n.translate( + 'xpack.indexLifecycleMgmt.hotPhase.maximumPrimaryShardSizeLabel', + { + defaultMessage: 'Maximum primary shard size', + } + ), + maxPrimaryShardSizeUnitsLabel: i18n.translate( + 'xpack.indexLifecycleMgmt.editPolicy.maximumPrimaryShardSizeAriaLabel', + { + defaultMessage: 'Maximum shard size units', + } + ), errors: { numberRequired: i18n.translate( 'xpack.indexLifecycleMgmt.editPolicy.errors.numberRequiredErrorMessage', diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts index ba7d31cf6da49..6c4d311d6177c 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts @@ -22,7 +22,14 @@ export interface ForcemergeFields { bestCompression: boolean; } -interface HotPhaseMetaFields extends ForcemergeFields { +interface ShrinkFields { + shrink: { + isUsingShardSize: boolean; + maxPrimaryShardSizeUnits?: string; + }; +} + +interface HotPhaseMetaFields extends ForcemergeFields, ShrinkFields { /** * By default rollover is enabled with set values for max age, max size and max docs. In this policy form * opting in to default rollover overrides custom rollover values. @@ -47,7 +54,11 @@ interface HotPhaseMetaFields extends ForcemergeFields { }; } -interface WarmPhaseMetaFields extends DataAllocationMetaFields, MinAgeField, ForcemergeFields { +interface WarmPhaseMetaFields + extends DataAllocationMetaFields, + MinAgeField, + ForcemergeFields, + ShrinkFields { enabled: boolean; warmPhaseOnRollover: boolean; readonlyEnabled: boolean; diff --git a/x-pack/plugins/index_lifecycle_management/server/index.ts b/x-pack/plugins/index_lifecycle_management/server/index.ts index e90518dbfa357..1f8b01913fd3e 100644 --- a/x-pack/plugins/index_lifecycle_management/server/index.ts +++ b/x-pack/plugins/index_lifecycle_management/server/index.ts @@ -17,4 +17,5 @@ export const config: PluginConfigDescriptor<IndexLifecycleManagementConfig> = { exposeToBrowser: { ui: true, }, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx index aeb4debddcd65..7307dd0e41eda 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx @@ -86,7 +86,7 @@ export const PathParameter = ({ field, allFields }: Props) => { 'xpack.idxMgmt.mappingsEditor.aliasType.aliasTargetFieldDescription', { defaultMessage: - 'Select the field you want your alias to point to. You will then be able to use the alias instead of the target field in search requests, and selected other APIs like field capabilities.', + 'Select the field you want your alias to point to. You will then be able to use the alias instead of the target field in search requests and select other APIs like field capabilities.', } )} withToggle={false} diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts index 321500730c82f..162bb59a0528a 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts @@ -10,7 +10,7 @@ jest.mock('../constants', () => { return { MAIN_DATA_TYPE_DEFINITION: {}, TYPE_DEFINITION }; }); -import { stripUndefinedValues, getTypeLabelFromField } from './utils'; +import { stripUndefinedValues, getTypeLabelFromField, getFieldMeta } from './utils'; describe('utils', () => { describe('stripUndefinedValues()', () => { @@ -77,4 +77,17 @@ describe('utils', () => { ).toBe('Other: hyperdrive'); }); }); + + describe('getFieldMeta', () => { + test('returns "canHaveMultiFields:true" for IP data type', () => { + expect(getFieldMeta({ name: 'ip_field', type: 'ip' })).toEqual({ + canHaveChildFields: false, + canHaveMultiFields: true, + childFieldsName: 'fields', + hasChildFields: false, + hasMultiFields: false, + isExpanded: false, + }); + }); + }); }); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts index bc02640ba7b78..44461f1b98aef 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts @@ -40,7 +40,7 @@ import { TreeItem } from '../components/tree'; export const getUniqueId = () => uuid.v4(); export const getChildFieldsName = (dataType: DataType): ChildFieldName | undefined => { - if (dataType === 'text' || dataType === 'keyword') { + if (dataType === 'text' || dataType === 'keyword' || dataType === 'ip') { return 'fields'; } else if (dataType === 'object' || dataType === 'nested') { return 'properties'; diff --git a/x-pack/plugins/index_management/server/index.ts b/x-pack/plugins/index_management/server/index.ts index 507401398a407..14b67e2ffd581 100644 --- a/x-pack/plugins/index_management/server/index.ts +++ b/x-pack/plugins/index_management/server/index.ts @@ -5,15 +5,16 @@ * 2.0. */ -import { PluginInitializerContext } from 'src/core/server'; +import { PluginInitializerContext, PluginConfigDescriptor } from 'src/core/server'; import { IndexMgmtServerPlugin } from './plugin'; import { configSchema } from './config'; export const plugin = (context: PluginInitializerContext) => new IndexMgmtServerPlugin(context); -export const config = { +export const config: PluginConfigDescriptor = { schema: configSchema, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; /** @public */ diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts index 3cd435ab0f6e8..4d4a0ff6320bd 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts @@ -15,7 +15,7 @@ import { PluginStart as DataPluginStart, } from '../../../../../../../src/plugins/data/server'; import { HomeServerPluginSetup } from '../../../../../../../src/plugins/home/server'; -import { VisTypeTimeseriesSetup } from '../../../../../../../src/plugins/vis_type_timeseries/server'; +import { VisTypeTimeseriesSetup } from '../../../../../../../src/plugins/vis_types/timeseries/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../plugins/features/server'; import { SpacesPluginSetup } from '../../../../../../plugins/spaces/server'; import { PluginSetupContract as AlertingPluginContract } from '../../../../../alerting/server'; diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index 2aede2f6aad16..4576a2e8452ac 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -34,7 +34,7 @@ import { RequestHandler } from '../../../../../../../src/core/server'; import { InfraConfig } from '../../../plugin'; import type { InfraPluginRequestHandlerContext } from '../../../types'; import { UI_SETTINGS } from '../../../../../../../src/plugins/data/server'; -import { TimeseriesVisData } from '../../../../../../../src/plugins/vis_type_timeseries/server'; +import { TimeseriesVisData } from '../../../../../../../src/plugins/vis_types/timeseries/server'; import { InfraServerPluginStartDeps } from './adapter_types'; export class KibanaFramework { diff --git a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts index a9ddcc8d3d4c1..730da9511dc38 100644 --- a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts @@ -21,7 +21,7 @@ import { import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; import { CallWithRequestParams, InfraDatabaseSearchResponse } from '../framework'; import type { InfraPluginRequestHandlerContext } from '../../../types'; -import { isVisSeriesData } from '../../../../../../../src/plugins/vis_type_timeseries/server'; +import { isVisSeriesData } from '../../../../../../../src/plugins/vis_types/timeseries/server'; export class KibanaMetricsAdapter implements InfraMetricsAdapter { private framework: KibanaFramework; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts index c7c1eb5454d1d..45eef3cc85a57 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts @@ -64,6 +64,7 @@ export const evaluateAlert = <Params extends EvaluatedAlertParams = EvaluatedAle esClient: ElasticsearchClient, params: Params, config: InfraSource['configuration'], + prevGroups: string[], timeframe?: { start?: number; end: number } ) => { const { criteria, groupBy, filterQuery, shouldDropPartialBuckets } = params; @@ -91,21 +92,53 @@ export const evaluateAlert = <Params extends EvaluatedAlertParams = EvaluatedAle : [false]; }; - return mapValues(currentValues, (points: any[] | typeof NaN | null) => { - if (isTooManyBucketsPreviewException(points)) throw points; - return { - ...criterion, - metric: criterion.metric ?? DOCUMENT_COUNT_I18N, - currentValue: Array.isArray(points) ? last(points)?.value : NaN, - timestamp: Array.isArray(points) ? last(points)?.key : NaN, - shouldFire: pointsEvaluator(points, threshold, comparator), - shouldWarn: pointsEvaluator(points, warningThreshold, warningComparator), - isNoData: Array.isArray(points) - ? points.map((point) => point?.value === null || point === null) - : [points === null], - isError: isNaN(Array.isArray(points) ? last(points)?.value : points), - }; - }); + // If any previous groups are no longer being reported, backfill them with null values + const currentGroups = Object.keys(currentValues); + + const missingGroups = prevGroups.filter((g) => !currentGroups.includes(g)); + if (currentGroups.length === 0 && missingGroups.length === 0) { + missingGroups.push(UNGROUPED_FACTORY_KEY); + } + const backfillTimestamp = + last(last(Object.values(currentValues)))?.key ?? new Date().toISOString(); + const backfilledPrevGroups: Record< + string, + Array<{ key: string; value: number }> + > = missingGroups.reduce( + (result, group) => ({ + ...result, + [group]: [ + { + key: backfillTimestamp, + value: criterion.aggType === Aggregators.COUNT ? 0 : null, + }, + ], + }), + {} + ); + const currentValuesWithBackfilledPrevGroups = { + ...currentValues, + ...backfilledPrevGroups, + }; + + return mapValues( + currentValuesWithBackfilledPrevGroups, + (points: any[] | typeof NaN | null) => { + if (isTooManyBucketsPreviewException(points)) throw points; + return { + ...criterion, + metric: criterion.metric ?? DOCUMENT_COUNT_I18N, + currentValue: Array.isArray(points) ? last(points)?.value : NaN, + timestamp: Array.isArray(points) ? last(points)?.key : NaN, + shouldFire: pointsEvaluator(points, threshold, comparator), + shouldWarn: pointsEvaluator(points, warningThreshold, warningComparator), + isNoData: Array.isArray(points) + ? points.map((point) => point?.value === null || point === null) + : [points === null], + isError: isNaN(Array.isArray(points) ? last(points)?.value : points), + }; + } + ); }) ); }; @@ -119,7 +152,7 @@ const getMetric: ( filterQuery: string | undefined, timeframe?: { start?: number; end: number }, shouldDropPartialBuckets?: boolean -) => Promise<Record<string, number[]>> = async function ( +) => Promise<Record<string, Array<{ key: string; value: number }>>> = async function ( esClient, params, index, diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 8eb19ad582057..869d0afd52367 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -37,10 +37,13 @@ let persistAlertInstances = false; // eslint-disable-line prefer-const type TestRuleState = Record<string, unknown> & { aRuleStateKey: string; + groups: string[]; + groupBy?: string | string[]; }; const initialRuleState: TestRuleState = { aRuleStateKey: 'INITIAL_RULE_STATE_VALUE', + groups: [], }; const mockOptions = { @@ -90,6 +93,7 @@ const mockOptions = { describe('The metric threshold alert type', () => { describe('querying the entire infrastructure', () => { + afterAll(() => clearInstances()); const instanceID = '*'; const execute = (comparator: Comparator, threshold: number[], sourceId: string = 'default') => executor({ @@ -157,20 +161,29 @@ describe('The metric threshold alert type', () => { }); describe('querying with a groupBy parameter', () => { - const execute = (comparator: Comparator, threshold: number[], sourceId: string = 'default') => + afterAll(() => clearInstances()); + const execute = ( + comparator: Comparator, + threshold: number[], + groupBy: string[] = ['something'], + metric?: string, + state?: any + ) => executor({ ...mockOptions, services, params: { - groupBy: 'something', + groupBy, criteria: [ { ...baseNonCountCriterion, comparator, threshold, + metric: metric ?? baseNonCountCriterion.metric, }, ], }, + state: state ?? mockOptions.state.wrapped, }); const instanceIdA = 'a'; const instanceIdB = 'b'; @@ -194,9 +207,35 @@ describe('The metric threshold alert type', () => { expect(mostRecentAction(instanceIdA).action.group).toBe('a'); expect(mostRecentAction(instanceIdB).action.group).toBe('b'); }); + test('reports previous groups and the groupBy parameter in its state', async () => { + const stateResult = await execute(Comparator.GT, [0.75]); + expect(stateResult.groups).toEqual(expect.arrayContaining(['a', 'b'])); + expect(stateResult.groupBy).toEqual(['something']); + }); + test('persists previous groups that go missing, until the groupBy param changes', async () => { + const stateResult1 = await execute(Comparator.GT, [0.75], ['something'], 'test.metric.2'); + expect(stateResult1.groups).toEqual(expect.arrayContaining(['a', 'b', 'c'])); + const stateResult2 = await execute( + Comparator.GT, + [0.75], + ['something'], + 'test.metric.1', + stateResult1 + ); + expect(stateResult2.groups).toEqual(expect.arrayContaining(['a', 'b', 'c'])); + const stateResult3 = await execute( + Comparator.GT, + [0.75], + ['something', 'something-else'], + 'test.metric.1', + stateResult2 + ); + expect(stateResult3.groups).toEqual(expect.arrayContaining(['a', 'b'])); + }); }); describe('querying with multiple criteria', () => { + afterAll(() => clearInstances()); const execute = ( comparator: Comparator, thresholdA: number[], @@ -257,6 +296,7 @@ describe('The metric threshold alert type', () => { }); }); describe('querying with the count aggregator', () => { + afterAll(() => clearInstances()); const instanceID = '*'; const execute = (comparator: Comparator, threshold: number[], sourceId: string = 'default') => executor({ @@ -279,8 +319,47 @@ describe('The metric threshold alert type', () => { await execute(Comparator.LT, [0.5]); expect(mostRecentAction(instanceID)).toBe(undefined); }); + describe('with a groupBy parameter', () => { + const executeGroupBy = ( + comparator: Comparator, + threshold: number[], + sourceId: string = 'default', + state?: any + ) => + executor({ + ...mockOptions, + services, + params: { + sourceId, + groupBy: 'something', + criteria: [ + { + ...baseCountCriterion, + comparator, + threshold, + }, + ], + }, + state: state ?? mockOptions.state.wrapped, + }); + const instanceIdA = 'a'; + const instanceIdB = 'b'; + + test('successfully detects and alerts on a document count of 0', async () => { + const resultState = await executeGroupBy(Comparator.LT_OR_EQ, [0]); + expect(mostRecentAction(instanceIdA)).toBe(undefined); + expect(mostRecentAction(instanceIdB)).toBe(undefined); + await executeGroupBy(Comparator.LT_OR_EQ, [0], 'empty-response', resultState); + expect(mostRecentAction(instanceIdA).id).toBe(FIRED_ACTIONS.id); + expect(mostRecentAction(instanceIdB).id).toBe(FIRED_ACTIONS.id); + await executeGroupBy(Comparator.LT_OR_EQ, [0]); + expect(mostRecentAction(instanceIdA)).toBe(undefined); + expect(mostRecentAction(instanceIdB)).toBe(undefined); + }); + }); }); describe('querying with the p99 aggregator', () => { + afterAll(() => clearInstances()); const instanceID = '*'; const execute = (comparator: Comparator, threshold: number[], sourceId: string = 'default') => executor({ @@ -306,6 +385,7 @@ describe('The metric threshold alert type', () => { }); }); describe('querying with the p95 aggregator', () => { + afterAll(() => clearInstances()); const instanceID = '*'; const execute = (comparator: Comparator, threshold: number[], sourceId: string = 'default') => executor({ @@ -332,6 +412,7 @@ describe('The metric threshold alert type', () => { }); }); describe("querying a metric that hasn't reported data", () => { + afterAll(() => clearInstances()); const instanceID = '*'; const execute = (alertOnNoData: boolean, sourceId: string = 'default') => executor({ @@ -360,7 +441,51 @@ describe('The metric threshold alert type', () => { }); }); + describe('querying a groupBy alert that starts reporting no data, and then later reports data', () => { + afterAll(() => clearInstances()); + const instanceID = '*'; + const instanceIdA = 'a'; + const instanceIdB = 'b'; + const execute = (metric: string, state?: any) => + executor({ + ...mockOptions, + services, + params: { + groupBy: 'something', + sourceId: 'default', + criteria: [ + { + ...baseNonCountCriterion, + comparator: Comparator.GT, + threshold: [0], + metric, + }, + ], + alertOnNoData: true, + }, + state: state ?? mockOptions.state.wrapped, + }); + const resultState: any[] = []; + test('first sends a No Data alert with the * group, but then reports groups when data is available', async () => { + resultState.push(await execute('test.metric.3')); + expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id); + resultState.push(await execute('test.metric.3', resultState.pop())); + expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id); + resultState.push(await execute('test.metric.1', resultState.pop())); + expect(mostRecentAction(instanceID)).toBe(undefined); + expect(mostRecentAction(instanceIdA).id).toBe(FIRED_ACTIONS.id); + expect(mostRecentAction(instanceIdB).id).toBe(FIRED_ACTIONS.id); + }); + test('sends No Data alerts for the previously detected groups when they stop reporting data, but not the * group', async () => { + await execute('test.metric.3', resultState.pop()); + expect(mostRecentAction(instanceID)).toBe(undefined); + expect(mostRecentAction(instanceIdA).id).toBe(FIRED_ACTIONS.id); + expect(mostRecentAction(instanceIdB).id).toBe(FIRED_ACTIONS.id); + }); + }); + describe("querying a rate-aggregated metric that hasn't reported data", () => { + afterAll(() => clearInstances()); const instanceID = '*'; const execute = (sourceId: string = 'default') => executor({ @@ -439,6 +564,7 @@ describe('The metric threshold alert type', () => { */ describe('querying a metric with a percentage metric', () => { + afterAll(() => clearInstances()); const instanceID = '*'; const execute = () => executor({ @@ -497,7 +623,15 @@ const services: AlertServicesMock & services.scopedClusterClient.asCurrentUser.search.mockImplementation((params?: any): any => { const from = params?.body.query.bool.filter[0]?.range['@timestamp'].gte; if (params.index === 'alternatebeat-*') return mocks.changedSourceIdResponse(from); + if (params.index === 'empty-response') return mocks.emptyMetricResponse; const metric = params?.body.query.bool.filter[1]?.exists.field; + if (metric === 'test.metric.3') { + return elasticsearchClientMock.createSuccessTransportRequestPromise( + params?.body.aggs.aggregatedIntervals?.aggregations.aggregatedValueMax + ? mocks.emptyRateResponse + : mocks.emptyMetricResponse + ); + } if (params?.body.aggs.groupings) { if (params?.body.aggs.groupings.composite.after) { return elasticsearchClientMock.createSuccessTransportRequestPromise( @@ -517,12 +651,6 @@ services.scopedClusterClient.asCurrentUser.search.mockImplementation((params?: a return elasticsearchClientMock.createSuccessTransportRequestPromise( mocks.alternateMetricResponse() ); - } else if (metric === 'test.metric.3') { - return elasticsearchClientMock.createSuccessTransportRequestPromise( - params?.body.aggs.aggregatedIntervals.aggregations.aggregatedValueMax - ? mocks.emptyRateResponse - : mocks.emptyMetricResponse - ); } return elasticsearchClientMock.createSuccessTransportRequestPromise(mocks.basicMetricResponse()); }); @@ -534,6 +662,13 @@ services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId type, references: [], }; + if (sourceId === 'empty-response') + return { + id: 'empty', + attributes: { metricAlias: 'empty-response' }, + type, + references: [], + }; return { id: 'default', attributes: { metricAlias: 'metricbeat-*' }, type, references: [] }; }); @@ -561,7 +696,13 @@ services.alertInstanceFactory.mockImplementation((instanceID: string) => { }); function mostRecentAction(id: string) { - return alertInstances.get(id)!.actionQueue.pop(); + const instance = alertInstances.get(id); + if (!instance) return undefined; + return instance.actionQueue.pop(); +} + +function clearInstances() { + alertInstances.clear(); } const baseNonCountCriterion: Pick< diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts index 9c99ad6bf49e2..f49b281909f4b 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { first, last } from 'lodash'; +import { first, last, isEqual } from 'lodash'; import { i18n } from '@kbn/i18n'; import moment from 'moment'; import { ALERT_REASON } from '@kbn/rule-data-utils'; @@ -24,12 +24,16 @@ import { // buildRecoveredAlertReason, stateToAlertMessage, } from '../common/messages'; +import { UNGROUPED_FACTORY_KEY } from '../common/utils'; import { createFormatter } from '../../../../common/formatters'; import { AlertStates, Comparator } from './types'; import { evaluateAlert, EvaluatedAlertParams } from './lib/evaluate_alert'; export type MetricThresholdAlertTypeParams = Record<string, any>; -export type MetricThresholdAlertTypeState = AlertTypeState; // no specific state used +export type MetricThresholdAlertTypeState = AlertTypeState & { + groups: string[]; + groupBy?: string | string[]; +}; export type MetricThresholdAlertInstanceState = AlertInstanceState; // no specific instace state used export type MetricThresholdAlertInstanceContext = AlertInstanceContext; // no specific instace state used @@ -58,7 +62,7 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) => MetricThresholdAlertInstanceContext, MetricThresholdAllowedActionGroups >(async function (options) { - const { services, params } = options; + const { services, params, state } = options; const { criteria } = params; if (criteria.length === 0) throw new Error('Cannot execute an alert with 0 conditions'); const { alertWithLifecycle, savedObjectsClient } = services; @@ -80,14 +84,28 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) => sourceId || 'default' ); const config = source.configuration; + + const previousGroupBy = state.groupBy; + const prevGroups = isEqual(previousGroupBy, params.groupBy) + ? // Filter out the * key from the previous groups, only include it if it's one of + // the current groups. In case of a groupBy alert that starts out with no data and no + // groups, we don't want to persist the existence of the * alert instance + state.groups?.filter((g) => g !== UNGROUPED_FACTORY_KEY) ?? [] + : []; + const alertResults = await evaluateAlert( services.scopedClusterClient.asCurrentUser, params as EvaluatedAlertParams, - config + config, + prevGroups ); // Because each alert result has the same group definitions, just grab the groups from the first one. - const groups = Object.keys(first(alertResults)!); + const resultGroups = Object.keys(first(alertResults)!); + // Merge the list of currently fetched groups and previous groups, and uniquify them. This is necessary for reporting + // no data results on groups that get removed + const groups = [...new Set([...prevGroups, ...resultGroups])]; + for (const group of groups) { // AND logic; all criteria must be across the threshold const shouldAlertFire = alertResults.every((result) => @@ -169,6 +187,8 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) => }); } } + + return { groups, groupBy: params.groupBy }; }); export const FIRED_ACTIONS = { diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/test_mocks.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/test_mocks.ts index b1173f2d611c8..db6b771e91784 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/test_mocks.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/test_mocks.ts @@ -199,12 +199,20 @@ export const alternateCompositeResponse = (from: number) => ({ buckets: bucketsA(from), }, }, + { + key: { + groupBy0: 'c', + }, + aggregatedIntervals: { + buckets: bucketsC(from), + }, + }, ], }, }, hits: { total: { - value: 2, + value: 3, }, }, }); diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index de445affc178e..b77b81cf41ee1 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -9,7 +9,12 @@ import { Server } from '@hapi/hapi'; import { schema, TypeOf } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { Logger } from '@kbn/logging'; -import { CoreSetup, PluginInitializerContext, Plugin } from 'src/core/server'; +import { + CoreSetup, + PluginInitializerContext, + Plugin, + PluginConfigDescriptor, +} from 'src/core/server'; import { LOGS_FEATURE_ID, METRICS_FEATURE_ID } from '../common/constants'; import { InfraStaticSourceConfiguration } from '../common/source_configuration/source_configuration'; import { inventoryViewSavedObjectType } from '../common/saved_objects/inventory_view'; @@ -36,7 +41,7 @@ import { createGetLogQueryFields } from './services/log_queries/get_log_query_fi import { handleEsError } from '../../../../src/plugins/es_ui_shared/server'; import { RulesService } from './services/rules'; -export const config = { +export const config: PluginConfigDescriptor = { schema: schema.object({ enabled: schema.boolean({ defaultValue: true }), inventory: schema.object({ @@ -63,6 +68,7 @@ export const config = { }) ), }), + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; export type InfraConfig = TypeOf<typeof config.schema>; diff --git a/x-pack/plugins/infra/server/utils/get_all_composite_data.ts b/x-pack/plugins/infra/server/utils/get_all_composite_data.ts index df97c91aacd04..1ab290796e36d 100644 --- a/x-pack/plugins/infra/server/utils/get_all_composite_data.ts +++ b/x-pack/plugins/infra/server/utils/get_all_composite_data.ts @@ -24,7 +24,7 @@ export const getAllCompositeData = async < const { body: response } = await esClientSearch(options); // Nothing available, return the previous buckets. - if (response.hits.total.value === 0) { + if (response.hits?.total.value === 0) { return previousBuckets; } diff --git a/x-pack/plugins/infra/tsconfig.json b/x-pack/plugins/infra/tsconfig.json index a9739bdfdedc7..a2d1d2b63655a 100644 --- a/x-pack/plugins/infra/tsconfig.json +++ b/x-pack/plugins/infra/tsconfig.json @@ -22,7 +22,7 @@ { "path": "../../../src/plugins/kibana_utils/tsconfig.json" }, { "path": "../../../src/plugins/kibana_react/tsconfig.json" }, { "path": "../../../src/plugins/usage_collection/tsconfig.json" }, - { "path": "../../../src/plugins/vis_type_timeseries/tsconfig.json" }, + { "path": "../../../src/plugins/vis_types/timeseries/tsconfig.json" }, { "path": "../data_enhanced/tsconfig.json" }, { "path": "../alerting/tsconfig.json" }, { "path": "../features/tsconfig.json" }, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/dissect.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/dissect.tsx index 3864581317e38..be55000bf374a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/dissect.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/dissect.tsx @@ -42,11 +42,7 @@ const getFieldsConfig = (esDocUrl: string): Record<string, FieldConfig> => { defaultMessage="Pattern used to dissect the specified field. The pattern is defined by the parts of the string to discard. Use a {keyModifier} to alter the dissection behavior." values={{ keyModifier: ( - <EuiLink - target="_blank" - external - href={esDocUrl + '/dissect-processor.html#dissect-key-modifiers'} - > + <EuiLink target="_blank" external href={esDocUrl}> {i18n.translate( 'xpack.ingestPipelines.pipelineEditor.dissectForm.patternFieldHelpText.dissectProcessorLink', { @@ -97,7 +93,7 @@ const getFieldsConfig = (esDocUrl: string): Record<string, FieldConfig> => { export const Dissect: FunctionComponent = () => { const { services } = useKibana(); - const fieldsConfig = getFieldsConfig(services.documentation.getEsDocsBasePath()); + const fieldsConfig = getFieldsConfig(services.documentation.getDissectKeyModifiersUrl()); return ( <> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/enrich.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/enrich.tsx index dfbcfc9566507..1c6292795d587 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/enrich.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/enrich.tsx @@ -139,7 +139,6 @@ const fieldsConfig: FieldsConfig = { export const Enrich: FunctionComponent = () => { const { services } = useKibana(); - const esDocUrl = services.documentation.getEsDocsBasePath(); return ( <> <FieldNameField @@ -161,7 +160,11 @@ export const Enrich: FunctionComponent = () => { defaultMessage="Name of the {enrichPolicyLink}." values={{ enrichPolicyLink: ( - <EuiLink external target="_blank" href={esDocUrl + '/ingest-enriching-data.html'}> + <EuiLink + external + target="_blank" + href={services.documentation.getEnrichDataUrl()} + > {i18n.translate( 'xpack.ingestPipelines.pipelineEditor.enrichForm.policyNameHelpText.enrichPolicyLink', { defaultMessage: 'enrich policy' } @@ -206,11 +209,7 @@ export const Enrich: FunctionComponent = () => { defaultMessage="Operator used to match the geo-shape of incoming documents to enrich documents. Only used for {geoMatchPolicyLink}." values={{ geoMatchPolicyLink: ( - <EuiLink - external - target="_blank" - href={esDocUrl + '/enrich-policy-definition.html'} - > + <EuiLink external target="_blank" href={services.documentation.getGeoMatchUrl()}> {i18n.translate( 'xpack.ingestPipelines.pipelineEditor.enrichForm.shapeRelationFieldHelpText.geoMatchPoliciesLink', { defaultMessage: 'geo-match enrich policies' } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx index 9575e6d690e00..9c3601c368342 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx @@ -28,14 +28,12 @@ const { emptyField, isJsonField } = fieldValidators; const INFERENCE_CONFIG_DOCS = { regression: { - path: 'inference-processor.html#inference-processor-regression-opt', linkLabel: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.inferenceForm.inferenceConfigField.regressionLinkLabel', { defaultMessage: 'regression' } ), }, classification: { - path: 'inference-processor.html#inference-processor-classification-opt', linkLabel: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.inferenceForm.inferenceConfigField.classificationLinkLabel', { defaultMessage: 'classification' } @@ -43,27 +41,22 @@ const INFERENCE_CONFIG_DOCS = { }, }; -const getInferenceConfigHelpText = (esDocsBasePath: string): React.ReactNode => { +const getInferenceConfigHelpText = ( + regressionDocsLink: string, + classificationDocsLink: string +): React.ReactNode => { return ( <FormattedMessage id="xpack.ingestPipelines.pipelineEditor.inferenceForm.inferenceConfigurationHelpText" defaultMessage="Contains the inference type and its options. There are two types: {regression} and {classification}." values={{ regression: ( - <EuiLink - external - target="_blank" - href={`${esDocsBasePath}/${INFERENCE_CONFIG_DOCS.regression.path}`} - > + <EuiLink external target="_blank" href={regressionDocsLink}> {INFERENCE_CONFIG_DOCS.regression.linkLabel} </EuiLink> ), classification: ( - <EuiLink - external - target="_blank" - href={`${esDocsBasePath}/${INFERENCE_CONFIG_DOCS.classification.path}`} - > + <EuiLink external target="_blank" href={classificationDocsLink}> {INFERENCE_CONFIG_DOCS.classification.linkLabel} </EuiLink> ), @@ -158,7 +151,8 @@ const fieldsConfig: FieldsConfig = { export const Inference: FunctionComponent = () => { const { services } = useKibana(); - const esDocUrl = services.documentation.getEsDocsBasePath(); + const regressionDocsLink = services.documentation.getRegressionUrl(); + const classificationDocsLink = services.documentation.getClassificationUrl(); return ( <> <UseField config={fieldsConfig.model_id} component={Field} path="fields.model_id" /> @@ -188,7 +182,7 @@ export const Inference: FunctionComponent = () => { <UseField config={{ ...fieldsConfig.inference_config, - helpText: getInferenceConfigHelpText(esDocUrl), + helpText: getInferenceConfigHelpText(regressionDocsLink, classificationDocsLink), }} component={XJsonEditor} componentProps={{ diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/test_pipeline/test_pipeline_tabs/tab_documents/tab_documents.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/test_pipeline/test_pipeline_tabs/tab_documents/tab_documents.tsx index 3d9e60ff9f05e..e6e9968ab4511 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/test_pipeline/test_pipeline_tabs/tab_documents/tab_documents.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/test_pipeline/test_pipeline_tabs/tab_documents/tab_documents.tsx @@ -179,7 +179,7 @@ export const DocumentsTab: FunctionComponent<Props> = ({ values={{ learnMoreLink: ( <EuiLink - href={`${services.documentation.getEsDocsBasePath()}/simulate-pipeline-api.html`} + href={services.documentation.getSimulatePipelineApiUrl()} target="_blank" external > diff --git a/x-pack/plugins/ingest_pipelines/public/application/services/documentation.ts b/x-pack/plugins/ingest_pipelines/public/application/services/documentation.ts index 8aa165cc502a8..801088b868370 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/services/documentation.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/services/documentation.ts @@ -13,16 +13,28 @@ export class DocumentationService { private processorsUrl: string = ''; private handlingFailureUrl: string = ''; private putPipelineApiUrl: string = ''; + private simulatePipelineApiUrl: string = ''; + private enrichDataUrl: string = ''; + private geoMatchUrl: string = ''; + private dissectKeyModifiersUrl: string = ''; + private classificationUrl: string = ''; + private regressionUrl: string = ''; public setup(docLinks: DocLinksStart): void { const { DOC_LINK_VERSION, ELASTIC_WEBSITE_URL, links } = docLinks; const docsBase = `${ELASTIC_WEBSITE_URL}guide/en`; this.esDocBasePath = `${docsBase}/elasticsearch/reference/${DOC_LINK_VERSION}`; - this.ingestNodeUrl = `${links.ingest.pipelines}`; - this.processorsUrl = `${links.ingest.processors}`; - this.handlingFailureUrl = `${links.ingest.pipelineFailure}`; - this.putPipelineApiUrl = `${links.apis.createPipeline}`; + this.ingestNodeUrl = links.ingest.pipelines; + this.processorsUrl = links.ingest.processors; + this.handlingFailureUrl = links.ingest.pipelineFailure; + this.putPipelineApiUrl = links.apis.createPipeline; + this.simulatePipelineApiUrl = links.apis.simulatePipeline; + this.enrichDataUrl = links.ingest.enrich; + this.geoMatchUrl = links.ingest.geoMatch; + this.dissectKeyModifiersUrl = links.ingest.dissectKeyModifiers; + this.classificationUrl = links.ingest.inferenceClassification; + this.regressionUrl = links.ingest.inferenceRegression; } public getEsDocsBasePath() { @@ -44,6 +56,30 @@ export class DocumentationService { public getPutPipelineApiUrl() { return this.putPipelineApiUrl; } + + public getSimulatePipelineApiUrl() { + return this.simulatePipelineApiUrl; + } + + public getEnrichDataUrl() { + return this.enrichDataUrl; + } + + public getGeoMatchUrl() { + return this.geoMatchUrl; + } + + public getDissectKeyModifiersUrl() { + return this.dissectKeyModifiersUrl; + } + + public getClassificationUrl() { + return this.classificationUrl; + } + + public getRegressionUrl() { + return this.regressionUrl; + } } export const documentationService = new DocumentationService(); diff --git a/x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts b/x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts index 9a9273e43f6f1..29b0fb1352e5b 100644 --- a/x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts +++ b/x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts @@ -27,12 +27,18 @@ interface AxisConfig { hide?: boolean; } -export type YAxisMode = 'auto' | 'left' | 'right'; +export type YAxisMode = 'auto' | 'left' | 'right' | 'bottom'; +export type LineStyle = 'solid' | 'dashed' | 'dotted'; +export type FillStyle = 'none' | 'above' | 'below'; export interface YConfig { forAccessor: string; axisMode?: YAxisMode; color?: string; + icon?: string; + lineWidth?: number; + lineStyle?: LineStyle; + fill?: FillStyle; } export type AxisTitlesVisibilityConfigResult = AxesSettingsConfig & { @@ -161,6 +167,24 @@ export const yAxisConfig: ExpressionFunctionDefinition< types: ['string'], help: 'The color of the series', }, + lineStyle: { + types: ['string'], + options: ['solid', 'dotted', 'dashed'], + help: 'The style of the threshold line', + }, + lineWidth: { + types: ['number'], + help: 'The width of the threshold line', + }, + icon: { + types: ['string'], + help: 'An optional icon used for threshold lines', + }, + fill: { + types: ['string'], + options: ['none', 'above', 'below'], + help: '', + }, }, fn: function fn(input: unknown, args: YConfig) { return { diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 25a809cb3c05d..275e6519367c7 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -604,6 +604,9 @@ describe('Lens App', () => { }); it('handles save failure by showing a warning, but still allows another save', async () => { + const mockedConsoleDir = jest.spyOn(console, 'dir'); // mocked console.dir to avoid messages in the console when running tests + mockedConsoleDir.mockImplementation(() => {}); + const services = makeDefaultServices(sessionIdSubject); services.attributeService.wrapAttributes = jest .fn() @@ -620,6 +623,9 @@ describe('Lens App', () => { }); expect(props.redirectTo).not.toHaveBeenCalled(); expect(getButton(instance).disableButton).toEqual(false); + // eslint-disable-next-line no-console + expect(console.dir).toHaveBeenCalledTimes(1); + mockedConsoleDir.mockRestore(); }); it('saves new doc and redirects to originating app', async () => { diff --git a/x-pack/plugins/lens/public/assets/chart_bar_threshold.tsx b/x-pack/plugins/lens/public/assets/chart_bar_threshold.tsx new file mode 100644 index 0000000000000..88e0a46b5538c --- /dev/null +++ b/x-pack/plugins/lens/public/assets/chart_bar_threshold.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiIconProps } from '@elastic/eui'; + +export const LensIconChartBarThreshold = ({ + title, + titleId, + ...props +}: Omit<EuiIconProps, 'type'>) => ( + <svg + viewBox="0 0 16 12" + width={30} + height={22} + fill="none" + xmlns="http://www.w3.org/2000/svg" + aria-labelledby={titleId} + {...props} + > + {title ? <title id={titleId}>{title} : null} + + + + + +); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/add_layer.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/add_layer.tsx index 0259acc4dcca1..69e4aa629cec6 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/add_layer.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/add_layer.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; import { EuiToolTip, EuiButton, @@ -38,12 +38,17 @@ export function AddLayerButton({ }: AddLayerButtonProps) { const [showLayersChoice, toggleLayersChoice] = useState(false); - const hasMultipleLayers = Boolean(visualization.appendLayer && visualizationState); - if (!hasMultipleLayers) { + const supportedLayers = useMemo(() => { + if (!visualization.appendLayer || !visualizationState) { + return null; + } + return visualization.getSupportedLayers?.(visualizationState, layersMeta); + }, [visualization, visualizationState, layersMeta]); + + if (supportedLayers == null) { return null; } - const supportedLayers = visualization.getSupportedLayers?.(visualizationState, layersMeta); - if (supportedLayers?.length === 1) { + if (supportedLayers.length === 1) { return ( new Promise((r) => setTimeout(r, time)); + let container: HTMLDivElement | undefined; beforeEach(() => { @@ -137,7 +141,7 @@ describe('ConfigPanel', () => { const updater = () => 'updated'; updateDatasource('mockindexpattern', updater); - await new Promise((r) => setTimeout(r, 0)); + await waitMs(0); expect(lensStore.dispatch).toHaveBeenCalledTimes(1); expect( (lensStore.dispatch as jest.Mock).mock.calls[0][0].payload.updater( @@ -147,7 +151,7 @@ describe('ConfigPanel', () => { updateAll('mockindexpattern', updater, props.visualizationState); // wait for one tick so async updater has a chance to trigger - await new Promise((r) => setTimeout(r, 0)); + await waitMs(0); expect(lensStore.dispatch).toHaveBeenCalledTimes(2); expect( (lensStore.dispatch as jest.Mock).mock.calls[0][0].payload.updater( @@ -293,4 +297,164 @@ describe('ConfigPanel', () => { expect(focusedEl?.children[0].getAttribute('data-test-subj')).toEqual('lns-layerPanel-1'); }); }); + + describe('initial default value', () => { + function prepareAndMountComponent(props: ReturnType) { + (generateId as jest.Mock).mockReturnValue(`newId`); + return mountWithProvider( + , + + { + preloadedState: { + datasourceStates: { + mockindexpattern: { + isLoading: false, + state: 'state', + }, + }, + activeDatasourceId: 'mockindexpattern', + }, + }, + { + attachTo: container, + } + ); + } + function clickToAddLayer(instance: ReactWrapper) { + act(() => { + instance.find('[data-test-subj="lnsLayerAddButton"]').first().simulate('click'); + }); + instance.update(); + act(() => { + instance + .find(`[data-test-subj="lnsLayerAddButton-${layerTypes.THRESHOLD}"]`) + .first() + .simulate('click'); + }); + instance.update(); + + return waitMs(0); + } + + function clickToAddDimension(instance: ReactWrapper) { + act(() => { + instance.find('[data-test-subj="lns-empty-dimension"]').last().simulate('click'); + }); + return waitMs(0); + } + + it('should not add an initial dimension when not specified', async () => { + const props = getDefaultProps(); + props.activeVisualization.getSupportedLayers = jest.fn(() => [ + { type: layerTypes.DATA, label: 'Data Layer' }, + { + type: layerTypes.THRESHOLD, + label: 'Threshold layer', + }, + ]); + mockDatasource.initializeDimension = jest.fn(); + + const { instance, lensStore } = await prepareAndMountComponent(props); + await clickToAddLayer(instance); + + expect(lensStore.dispatch).toHaveBeenCalledTimes(1); + expect(mockDatasource.initializeDimension).not.toHaveBeenCalled(); + }); + + it('should not add an initial dimension when initialDimensions are not available for the given layer type', async () => { + const props = getDefaultProps(); + props.activeVisualization.getSupportedLayers = jest.fn(() => [ + { + type: layerTypes.DATA, + label: 'Data Layer', + initialDimensions: [ + { + groupId: 'testGroup', + columnId: 'myColumn', + dataType: 'number', + label: 'Initial value', + staticValue: 100, + }, + ], + }, + { + type: layerTypes.THRESHOLD, + label: 'Threshold layer', + }, + ]); + mockDatasource.initializeDimension = jest.fn(); + + const { instance, lensStore } = await prepareAndMountComponent(props); + await clickToAddLayer(instance); + + expect(lensStore.dispatch).toHaveBeenCalledTimes(1); + expect(mockDatasource.initializeDimension).not.toHaveBeenCalled(); + }); + + it('should use group initial dimension value when adding a new layer if available', async () => { + const props = getDefaultProps(); + props.activeVisualization.getSupportedLayers = jest.fn(() => [ + { type: layerTypes.DATA, label: 'Data Layer' }, + { + type: layerTypes.THRESHOLD, + label: 'Threshold layer', + initialDimensions: [ + { + groupId: 'testGroup', + columnId: 'myColumn', + dataType: 'number', + label: 'Initial value', + staticValue: 100, + }, + ], + }, + ]); + mockDatasource.initializeDimension = jest.fn(); + + const { instance, lensStore } = await prepareAndMountComponent(props); + await clickToAddLayer(instance); + + expect(lensStore.dispatch).toHaveBeenCalledTimes(1); + expect(mockDatasource.initializeDimension).toHaveBeenCalledWith(undefined, 'newId', { + columnId: 'myColumn', + dataType: 'number', + groupId: 'testGroup', + label: 'Initial value', + staticValue: 100, + }); + }); + + it('should add an initial dimension value when clicking on the empty dimension button', async () => { + const props = getDefaultProps(); + props.activeVisualization.getSupportedLayers = jest.fn(() => [ + { + type: layerTypes.DATA, + label: 'Data Layer', + initialDimensions: [ + { + groupId: 'a', + columnId: 'newId', + dataType: 'number', + label: 'Initial value', + staticValue: 100, + }, + ], + }, + ]); + mockDatasource.initializeDimension = jest.fn(); + + const { instance, lensStore } = await prepareAndMountComponent(props); + + await clickToAddDimension(instance); + expect(lensStore.dispatch).toHaveBeenCalledTimes(1); + + expect(mockDatasource.initializeDimension).toHaveBeenCalledWith('state', 'first', { + groupId: 'a', + columnId: 'newId', + dataType: 'number', + label: 'Initial value', + staticValue: 100, + }); + }); + }); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx index f7fe2beefa963..57e4cf5b8dffd 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx @@ -26,8 +26,9 @@ import { useLensSelector, selectVisualization, VisualizationState, + LensAppState, } from '../../../state_management'; -import { AddLayerButton } from './add_layer'; +import { AddLayerButton, getLayerType } from './add_layer'; export const ConfigPanelWrapper = memo(function ConfigPanelWrapper(props: ConfigPanelWrapperProps) { const visualization = useLensSelector(selectVisualization); @@ -177,6 +178,33 @@ export function LayerPanels( layerIds.length ) === 'clear' } + onEmptyDimensionAdd={(columnId, { groupId }) => { + // avoid state update if the datasource does not support initializeDimension + if ( + activeDatasourceId != null && + datasourceMap[activeDatasourceId]?.initializeDimension + ) { + dispatchLens( + updateState({ + subType: 'LAYER_DEFAULT_DIMENSION', + updater: (state) => + addInitialValueIfAvailable({ + ...props, + state, + activeDatasourceId, + layerId, + layerType: getLayerType( + activeVisualization, + state.visualization.state, + layerId + ), + columnId, + groupId, + }), + }) + ); + } + }} onRemoveLayer={() => { dispatchLens( updateState({ @@ -232,21 +260,92 @@ export function LayerPanels( dispatchLens( updateState({ subType: 'ADD_LAYER', - updater: (state) => - appendLayer({ + updater: (state) => { + const newState = appendLayer({ activeVisualization, generateId: () => id, trackUiEvent, activeDatasource: datasourceMap[activeDatasourceId!], state, layerType, - }), + }); + return addInitialValueIfAvailable({ + ...props, + activeDatasourceId: activeDatasourceId!, + state: newState, + layerId: id, + layerType, + }); + }, }) ); - setNextFocusedLayerId(id); }} /> ); } + +function addInitialValueIfAvailable({ + state, + activeVisualization, + framePublicAPI, + layerType, + activeDatasourceId, + datasourceMap, + layerId, + columnId, + groupId, +}: ConfigPanelWrapperProps & { + state: LensAppState; + activeDatasourceId: string; + activeVisualization: Visualization; + layerId: string; + layerType: string; + columnId?: string; + groupId?: string; +}) { + const layerInfo = activeVisualization + .getSupportedLayers(state.visualization.state, framePublicAPI) + .find(({ type }) => type === layerType); + + const activeDatasource = datasourceMap[activeDatasourceId]; + + if (layerInfo?.initialDimensions && activeDatasource?.initializeDimension) { + const info = groupId + ? layerInfo.initialDimensions.find(({ groupId: id }) => id === groupId) + : // pick the first available one if not passed + layerInfo.initialDimensions[0]; + + if (info) { + return { + ...state, + datasourceStates: { + ...state.datasourceStates, + [activeDatasourceId]: { + ...state.datasourceStates[activeDatasourceId], + state: activeDatasource.initializeDimension( + state.datasourceStates[activeDatasourceId].state, + layerId, + { + ...info, + columnId: columnId || info.columnId, + } + ), + }, + }, + visualization: { + ...state.visualization, + state: activeVisualization.setDimension({ + groupId: info.groupId, + layerId, + columnId: columnId || info.columnId, + prevState: state.visualization.state, + frame: framePublicAPI, + }), + }, + }; + } + } + return state; +} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx index 13b7b8cfecf56..f777fd0976dfd 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx @@ -83,6 +83,7 @@ describe('LayerPanel', () => { registerNewLayerRef: jest.fn(), isFullscreen: false, toggleFullscreen: jest.fn(), + onEmptyDimensionAdd: jest.fn(), }; } @@ -920,4 +921,33 @@ describe('LayerPanel', () => { expect(updateVisualization).toHaveBeenCalledTimes(1); }); }); + + describe('add a new dimension', () => { + it('should call onEmptyDimensionAdd callback on new dimension creation', async () => { + mockVisualization.getConfiguration.mockReturnValue({ + groups: [ + { + groupLabel: 'A', + groupId: 'a', + accessors: [], + filterOperations: () => true, + supportsMoreColumns: true, + dataTestSubj: 'lnsGroup', + }, + ], + }); + const props = getDefaultProps(); + const { instance } = await mountWithProvider(); + + act(() => { + instance.find('[data-test-subj="lns-empty-dimension"]').first().simulate('click'); + }); + instance.update(); + + expect(props.onEmptyDimensionAdd).toHaveBeenCalledWith( + 'newid', + expect.objectContaining({ groupId: 'a' }) + ); + }); + }); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx index 520c2bc837c60..8c947d3502f93 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx @@ -57,6 +57,7 @@ export function LayerPanel( onRemoveLayer: () => void; registerNewLayerRef: (layerId: string, instance: HTMLDivElement | null) => void; toggleFullscreen: () => void; + onEmptyDimensionAdd: (columnId: string, group: { groupId: string }) => void; } ) { const [activeDimension, setActiveDimension] = useState( @@ -124,7 +125,11 @@ export function LayerPanel( dateRange, }; - const { groups, supportStaticValue } = useMemo( + const { + groups, + supportStaticValue, + supportFieldFormat = true, + } = useMemo( () => activeVisualization.getConfiguration(layerVisualizationConfigProps), // eslint-disable-next-line react-hooks/exhaustive-deps [ @@ -227,13 +232,25 @@ export function LayerPanel( const isDimensionPanelOpen = Boolean(activeId); const updateDataLayerState = useCallback( - (newState: unknown, { isDimensionComplete = true }: { isDimensionComplete?: boolean } = {}) => { + ( + newState: unknown, + { + isDimensionComplete = true, + // this flag is a hack to force a sync render where it was planned an async/setTimeout state update + // TODO: revisit this once we get rid of updateDatasourceAsync upstream + forceRender = false, + }: { isDimensionComplete?: boolean; forceRender?: boolean } = {} + ) => { if (!activeGroup || !activeId) { return; } if (allAccessors.includes(activeId)) { if (isDimensionComplete) { - updateDatasourceAsync(datasourceId, newState); + if (forceRender) { + updateDatasource(datasourceId, newState); + } else { + updateDatasourceAsync(datasourceId, newState); + } } else { // The datasource can indicate that the previously-valid column is no longer // complete, which clears the visualization. This keeps the flyout open and reuses @@ -263,7 +280,11 @@ export function LayerPanel( ); setActiveDimension({ ...activeDimension, isNew: false }); } else { - updateDatasourceAsync(datasourceId, newState); + if (forceRender) { + updateDatasource(datasourceId, newState); + } else { + updateDatasourceAsync(datasourceId, newState); + } } }, // eslint-disable-next-line react-hooks/exhaustive-deps @@ -295,11 +316,10 @@ export function LayerPanel( hasBorder hasShadow > -

    +
    )} -
    +
    {groups.map((group, groupIndex) => { const isMissing = !isEmptyLayer && group.required && group.accessors.length === 0; @@ -460,6 +480,8 @@ export function LayerPanel( columnId: accessorConfig.columnId, groupId: group.groupId, filterOperations: group.filterOperations, + invalid: group.invalid, + invalidMessage: group.invalidMessage, }} /> @@ -478,6 +500,7 @@ export function LayerPanel( layerDatasource={layerDatasource} layerDatasourceDropProps={layerDatasourceDropProps} onClick={(id) => { + props.onEmptyDimensionAdd(id, group); setActiveDimension({ activeGroup: group, activeId: id, @@ -538,6 +561,8 @@ export function LayerPanel( toggleFullscreen, isFullscreen, setState: updateDataLayerState, + supportStaticValue: Boolean(supportStaticValue), + supportFieldFormat: Boolean(supportFieldFormat), layerType: activeVisualization.getLayerType(layerId, visualizationState), }} /> diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.test.tsx new file mode 100644 index 0000000000000..04c430143a3c8 --- /dev/null +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.test.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + createMockFramePublicAPI, + createMockVisualization, + mountWithProvider, +} from '../../../mocks'; +import { Visualization } from '../../../types'; +import { LayerSettings } from './layer_settings'; + +describe('LayerSettings', () => { + let mockVisualization: jest.Mocked; + const frame = createMockFramePublicAPI(); + + function getDefaultProps() { + return { + activeVisualization: mockVisualization, + layerConfigProps: { + layerId: 'myLayer', + state: {}, + frame, + dateRange: { fromDate: 'now-7d', toDate: 'now' }, + activeData: frame.activeData, + setState: jest.fn(), + }, + }; + } + + beforeEach(() => { + mockVisualization = { + ...createMockVisualization(), + id: 'testVis', + visualizationTypes: [ + { + icon: 'empty', + id: 'testVis', + label: 'TEST1', + groupLabel: 'testVisGroup', + }, + ], + }; + }); + + it('should render nothing with no custom renderer nor description', async () => { + // @ts-expect-error + mockVisualization.getDescription.mockReturnValue(undefined); + const { instance } = await mountWithProvider(); + expect(instance.html()).toBe(null); + }); + + it('should render a static header if visualization has only a description value', async () => { + mockVisualization.getDescription.mockReturnValue({ + icon: 'myIcon', + label: 'myVisualizationType', + }); + const { instance } = await mountWithProvider(); + expect(instance.find('StaticHeader').first().prop('label')).toBe('myVisualizationType'); + }); + + it('should call the custom renderer if available', async () => { + mockVisualization.renderLayerHeader = jest.fn(); + await mountWithProvider(); + expect(mockVisualization.renderLayerHeader).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.tsx index 467b1ecfe1b5b..fc88ff2af8bbe 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.tsx @@ -6,44 +6,23 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiTitle } from '@elastic/eui'; import { NativeRenderer } from '../../../native_renderer'; import { Visualization, VisualizationLayerWidgetProps } from '../../../types'; +import { StaticHeader } from '../../../shared_components'; export function LayerSettings({ - layerId, activeVisualization, layerConfigProps, }: { - layerId: string; activeVisualization: Visualization; layerConfigProps: VisualizationLayerWidgetProps; }) { - const description = activeVisualization.getDescription(layerConfigProps.state); - if (!activeVisualization.renderLayerHeader) { + const description = activeVisualization.getDescription(layerConfigProps.state); if (!description) { return null; } - return ( - - {description.icon && ( - - {' '} - - )} - - -
    {description.label}
    -
    -
    -
    - ); + return ; } return ( diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts index 632989057b488..90fa2ab080dd2 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts @@ -45,21 +45,22 @@ describe('suggestion helpers', () => { generateSuggestion(), ]); const suggestedState = {}; - const suggestions = getSuggestions({ - visualizationMap: { - vis1: { - ...mockVisualization, - getSuggestions: () => [ - { - score: 0.5, - title: 'Test', - state: suggestedState, - previewIcon: 'empty', - }, - ], - }, + const visualizationMap = { + vis1: { + ...mockVisualization, + getSuggestions: () => [ + { + score: 0.5, + title: 'Test', + state: suggestedState, + previewIcon: 'empty', + }, + ], }, - activeVisualizationId: 'vis1', + }; + const suggestions = getSuggestions({ + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -74,38 +75,39 @@ describe('suggestion helpers', () => { datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([ generateSuggestion(), ]); - const suggestions = getSuggestions({ - visualizationMap: { - vis1: { - ...mockVisualization1, - getSuggestions: () => [ - { - score: 0.5, - title: 'Test', - state: {}, - previewIcon: 'empty', - }, - { - score: 0.5, - title: 'Test2', - state: {}, - previewIcon: 'empty', - }, - ], - }, - vis2: { - ...mockVisualization2, - getSuggestions: () => [ - { - score: 0.5, - title: 'Test3', - state: {}, - previewIcon: 'empty', - }, - ], - }, + const visualizationMap = { + vis1: { + ...mockVisualization1, + getSuggestions: () => [ + { + score: 0.5, + title: 'Test', + state: {}, + previewIcon: 'empty', + }, + { + score: 0.5, + title: 'Test2', + state: {}, + previewIcon: 'empty', + }, + ], + }, + vis2: { + ...mockVisualization2, + getSuggestions: () => [ + { + score: 0.5, + title: 'Test3', + state: {}, + previewIcon: 'empty', + }, + ], }, - activeVisualizationId: 'vis1', + }; + const suggestions = getSuggestions({ + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -116,11 +118,12 @@ describe('suggestion helpers', () => { it('should call getDatasourceSuggestionsForField when a field is passed', () => { datasourceMap.mock.getDatasourceSuggestionsForField.mockReturnValue([generateSuggestion()]); const droppedField = {}; + const visualizationMap = { + vis1: createMockVisualization(), + }; getSuggestions({ - visualizationMap: { - vis1: createMockVisualization(), - }, - activeVisualizationId: 'vis1', + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -128,7 +131,8 @@ describe('suggestion helpers', () => { }); expect(datasourceMap.mock.getDatasourceSuggestionsForField).toHaveBeenCalledWith( datasourceStates.mock.state, - droppedField + droppedField, + expect.any(Function) ); }); @@ -148,12 +152,13 @@ describe('suggestion helpers', () => { mock2: createMockDatasource('a'), mock3: createMockDatasource('a'), }; + const visualizationMap = { + vis1: createMockVisualization(), + }; const droppedField = {}; getSuggestions({ - visualizationMap: { - vis1: createMockVisualization(), - }, - activeVisualizationId: 'vis1', + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap: multiDatasourceMap, datasourceStates: multiDatasourceStates, @@ -161,11 +166,13 @@ describe('suggestion helpers', () => { }); expect(multiDatasourceMap.mock.getDatasourceSuggestionsForField).toHaveBeenCalledWith( multiDatasourceStates.mock.state, - droppedField + droppedField, + expect.any(Function) ); expect(multiDatasourceMap.mock2.getDatasourceSuggestionsForField).toHaveBeenCalledWith( multiDatasourceStates.mock2.state, - droppedField + droppedField, + expect.any(Function) ); expect(multiDatasourceMap.mock3.getDatasourceSuggestionsForField).not.toHaveBeenCalled(); }); @@ -174,11 +181,14 @@ describe('suggestion helpers', () => { datasourceMap.mock.getDatasourceSuggestionsForVisualizeField.mockReturnValue([ generateSuggestion(), ]); + + const visualizationMap = { + vis1: createMockVisualization(), + }; + getSuggestions({ - visualizationMap: { - vis1: createMockVisualization(), - }, - activeVisualizationId: 'vis1', + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -214,11 +224,13 @@ describe('suggestion helpers', () => { indexPatternId: '1', fieldName: 'test', }; + + const visualizationMap = { + vis1: createMockVisualization(), + }; getSuggestions({ - visualizationMap: { - vis1: createMockVisualization(), - }, - activeVisualizationId: 'vis1', + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap: multiDatasourceMap, datasourceStates: multiDatasourceStates, @@ -245,38 +257,39 @@ describe('suggestion helpers', () => { datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([ generateSuggestion(), ]); - const suggestions = getSuggestions({ - visualizationMap: { - vis1: { - ...mockVisualization1, - getSuggestions: () => [ - { - score: 0.2, - title: 'Test', - state: {}, - previewIcon: 'empty', - }, - { - score: 0.8, - title: 'Test2', - state: {}, - previewIcon: 'empty', - }, - ], - }, - vis2: { - ...mockVisualization2, - getSuggestions: () => [ - { - score: 0.6, - title: 'Test3', - state: {}, - previewIcon: 'empty', - }, - ], - }, + const visualizationMap = { + vis1: { + ...mockVisualization1, + getSuggestions: () => [ + { + score: 0.2, + title: 'Test', + state: {}, + previewIcon: 'empty', + }, + { + score: 0.8, + title: 'Test2', + state: {}, + previewIcon: 'empty', + }, + ], }, - activeVisualizationId: 'vis1', + vis2: { + ...mockVisualization2, + getSuggestions: () => [ + { + score: 0.6, + title: 'Test3', + state: {}, + previewIcon: 'empty', + }, + ], + }, + }; + const suggestions = getSuggestions({ + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -305,12 +318,13 @@ describe('suggestion helpers', () => { { state: {}, table: table1, keptLayerIds: ['first'] }, { state: {}, table: table2, keptLayerIds: ['first'] }, ]); + const visualizationMap = { + vis1: mockVisualization1, + vis2: mockVisualization2, + }; getSuggestions({ - visualizationMap: { - vis1: mockVisualization1, - vis2: mockVisualization2, - }, - activeVisualizationId: 'vis1', + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -357,18 +371,20 @@ describe('suggestion helpers', () => { previewIcon: 'empty', }, ]); - const suggestions = getSuggestions({ - visualizationMap: { - vis1: { - ...mockVisualization1, - getSuggestions: vis1Suggestions, - }, - vis2: { - ...mockVisualization2, - getSuggestions: vis2Suggestions, - }, + const visualizationMap = { + vis1: { + ...mockVisualization1, + getSuggestions: vis1Suggestions, }, - activeVisualizationId: 'vis1', + vis2: { + ...mockVisualization2, + getSuggestions: vis2Suggestions, + }, + }; + + const suggestions = getSuggestions({ + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -389,12 +405,15 @@ describe('suggestion helpers', () => { generateSuggestion(0), generateSuggestion(1), ]); + + const visualizationMap = { + vis1: mockVisualization1, + vis2: mockVisualization2, + }; + getSuggestions({ - visualizationMap: { - vis1: mockVisualization1, - vis2: mockVisualization2, - }, - activeVisualizationId: 'vis1', + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -419,12 +438,13 @@ describe('suggestion helpers', () => { generateSuggestion(0), generateSuggestion(1), ]); + const visualizationMap = { + vis1: mockVisualization1, + vis2: mockVisualization2, + }; getSuggestions({ - visualizationMap: { - vis1: mockVisualization1, - vis2: mockVisualization2, - }, - activeVisualizationId: 'vis1', + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -451,12 +471,14 @@ describe('suggestion helpers', () => { generateSuggestion(0), generateSuggestion(1), ]); + const visualizationMap = { + vis1: mockVisualization1, + vis2: mockVisualization2, + }; + getSuggestions({ - visualizationMap: { - vis1: mockVisualization1, - vis2: mockVisualization2, - }, - activeVisualizationId: 'vis1', + visualizationMap, + activeVisualization: visualizationMap.vis1, visualizationState: {}, datasourceMap, datasourceStates, @@ -538,7 +560,8 @@ describe('suggestion helpers', () => { humanData: { label: 'myfieldLabel', }, - } + }, + expect.any(Function) ); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts index 2f3fe3795a881..a5c7871f33dfc 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts @@ -58,7 +58,7 @@ export function getSuggestions({ datasourceMap, datasourceStates, visualizationMap, - activeVisualizationId, + activeVisualization, subVisualizationId, visualizationState, field, @@ -69,7 +69,7 @@ export function getSuggestions({ datasourceMap: DatasourceMap; datasourceStates: DatasourceStates; visualizationMap: VisualizationMap; - activeVisualizationId: string | null; + activeVisualization?: Visualization; subVisualizationId?: string; visualizationState: unknown; field?: unknown; @@ -83,16 +83,12 @@ export function getSuggestions({ const layerTypesMap = datasources.reduce((memo, [datasourceId, datasource]) => { const datasourceState = datasourceStates[datasourceId].state; - if (!activeVisualizationId || !datasourceState || !visualizationMap[activeVisualizationId]) { + if (!activeVisualization || !datasourceState) { return memo; } const layers = datasource.getLayers(datasourceState); for (const layerId of layers) { - const type = getLayerType( - visualizationMap[activeVisualizationId], - visualizationState, - layerId - ); + const type = getLayerType(activeVisualization, visualizationState, layerId); memo[layerId] = type; } return memo; @@ -112,7 +108,11 @@ export function getSuggestions({ visualizeTriggerFieldContext.fieldName ); } else if (field) { - dataSourceSuggestions = datasource.getDatasourceSuggestionsForField(datasourceState, field); + dataSourceSuggestions = datasource.getDatasourceSuggestionsForField( + datasourceState, + field, + (layerId) => isLayerSupportedByVisualization(layerId, [layerTypes.DATA]) // a field dragged to workspace should added to data layer + ); } else { dataSourceSuggestions = datasource.getDatasourceSuggestionsFromCurrentState( datasourceState, @@ -121,7 +121,6 @@ export function getSuggestions({ } return dataSourceSuggestions.map((suggestion) => ({ ...suggestion, datasourceId })); }); - // Pass all table suggestions to all visualization extensions to get visualization suggestions // and rank them by score return Object.entries(visualizationMap) @@ -139,12 +138,8 @@ export function getSuggestions({ .flatMap((datasourceSuggestion) => { const table = datasourceSuggestion.table; const currentVisualizationState = - visualizationId === activeVisualizationId ? visualizationState : undefined; - const palette = - mainPalette || - (activeVisualizationId && visualizationMap[activeVisualizationId]?.getMainPalette - ? visualizationMap[activeVisualizationId].getMainPalette?.(visualizationState) - : undefined); + visualizationId === activeVisualization?.id ? visualizationState : undefined; + const palette = mainPalette || activeVisualization?.getMainPalette?.(visualizationState); return getVisualizationSuggestions( visualization, @@ -169,14 +164,14 @@ export function getVisualizeFieldSuggestions({ datasourceMap, datasourceStates, visualizationMap, - activeVisualizationId, + activeVisualization, visualizationState, visualizeTriggerFieldContext, }: { datasourceMap: DatasourceMap; datasourceStates: DatasourceStates; visualizationMap: VisualizationMap; - activeVisualizationId: string | null; + activeVisualization: Visualization; subVisualizationId?: string; visualizationState: unknown; visualizeTriggerFieldContext?: VisualizeFieldContext; @@ -185,12 +180,12 @@ export function getVisualizeFieldSuggestions({ datasourceMap, datasourceStates, visualizationMap, - activeVisualizationId, + activeVisualization, visualizationState, visualizeTriggerFieldContext, }); if (suggestions.length) { - return suggestions.find((s) => s.visualizationId === activeVisualizationId) || suggestions[0]; + return suggestions.find((s) => s.visualizationId === activeVisualization?.id) || suggestions[0]; } } @@ -263,18 +258,19 @@ export function getTopSuggestionForField( (datasourceLayer) => datasourceLayer.getTableSpec().length > 0 ); - const mainPalette = - visualization.activeId && visualizationMap[visualization.activeId]?.getMainPalette - ? visualizationMap[visualization.activeId].getMainPalette?.(visualization.state) - : undefined; + const activeVisualization = visualization.activeId + ? visualizationMap[visualization.activeId] + : undefined; + + const mainPalette = activeVisualization?.getMainPalette?.(visualization.state); const suggestions = getSuggestions({ datasourceMap: { [datasource.id]: datasource }, datasourceStates, visualizationMap: hasData && visualization.activeId - ? { [visualization.activeId]: visualizationMap[visualization.activeId] } + ? { [visualization.activeId]: activeVisualization! } : visualizationMap, - activeVisualizationId: visualization.activeId, + activeVisualization, visualizationState: visualization.state, field, mainPalette, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index 858fcedf215ef..5e5e19ea29e84 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -201,7 +201,9 @@ export function SuggestionPanel({ datasourceMap, datasourceStates: currentDatasourceStates, visualizationMap, - activeVisualizationId: currentVisualization.activeId, + activeVisualization: currentVisualization.activeId + ? visualizationMap[currentVisualization.activeId] + : undefined, visualizationState: currentVisualization.state, activeData, }) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx index 28c0567d784ea..51d4f2955a52b 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx @@ -515,11 +515,14 @@ function getTopSuggestion( props.visualizationMap[visualization.activeId].getMainPalette ? props.visualizationMap[visualization.activeId].getMainPalette!(visualization.state) : undefined; + const unfilteredSuggestions = getSuggestions({ datasourceMap: props.datasourceMap, datasourceStates, visualizationMap: { [visualizationId]: newVisualization }, - activeVisualizationId: visualization.activeId, + activeVisualization: visualization.activeId + ? props.visualizationMap[visualization.activeId] + : undefined, visualizationState: visualization.state, subVisualizationId, activeData: props.framePublicAPI.activeData, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index e386bac026fdc..d25e6754fe03f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -11,15 +11,11 @@ import { i18n } from '@kbn/i18n'; import { EuiListGroup, EuiFormRow, - EuiFieldText, EuiSpacer, EuiListGroupItemProps, EuiFormLabel, EuiToolTip, EuiText, - EuiTabs, - EuiTab, - EuiCallOut, } from '@elastic/eui'; import { IndexPatternDimensionEditorProps } from './dimension_panel'; import { OperationSupportMatrix } from './operation_support'; @@ -47,41 +43,29 @@ import { setTimeScaling, TimeScaling } from './time_scaling'; import { defaultFilter, Filtering, setFilter } from './filtering'; import { AdvancedOptions } from './advanced_options'; import { setTimeShift, TimeShift } from './time_shift'; -import { useDebouncedValue } from '../../shared_components'; +import { LayerType } from '../../../common'; +import { + quickFunctionsName, + staticValueOperationName, + isQuickFunction, + getParamEditor, + formulaOperationName, + DimensionEditorTabs, + CalloutWarning, + LabelInput, + getErrorMessage, +} from './dimensions_editor_helpers'; +import type { TemporaryState } from './dimensions_editor_helpers'; const operationPanels = getOperationDisplay(); export interface DimensionEditorProps extends IndexPatternDimensionEditorProps { selectedColumn?: IndexPatternColumn; + layerType: LayerType; operationSupportMatrix: OperationSupportMatrix; currentIndexPattern: IndexPattern; } -const LabelInput = ({ value, onChange }: { value: string; onChange: (value: string) => void }) => { - const { inputValue, handleInputChange, initialValue } = useDebouncedValue({ onChange, value }); - - return ( - - { - handleInputChange(e.target.value); - }} - placeholder={initialValue} - /> - - ); -}; - export function DimensionEditor(props: DimensionEditorProps) { const { selectedColumn, @@ -96,6 +80,8 @@ export function DimensionEditor(props: DimensionEditorProps) { dimensionGroups, toggleFullscreen, isFullscreen, + supportStaticValue, + supportFieldFormat = true, layerType, } = props; const services = { @@ -110,6 +96,11 @@ export function DimensionEditor(props: DimensionEditorProps) { const selectedOperationDefinition = selectedColumn && operationDefinitionMap[selectedColumn.operationType]; + const [temporaryState, setTemporaryState] = useState('none'); + + const temporaryQuickFunction = Boolean(temporaryState === quickFunctionsName); + const temporaryStaticValue = Boolean(temporaryState === staticValueOperationName); + const updateLayer = useCallback( (newLayer) => setState((prevState) => mergeLayer({ state: prevState, layerId, newLayer })), [layerId, setState] @@ -141,9 +132,64 @@ export function DimensionEditor(props: DimensionEditorProps) { ...incompleteParams } = incompleteInfo || {}; - const ParamEditor = selectedOperationDefinition?.paramEditor; + const isQuickFunctionSelected = Boolean( + supportStaticValue + ? selectedOperationDefinition && isQuickFunction(selectedOperationDefinition.type) + : !selectedOperationDefinition || isQuickFunction(selectedOperationDefinition.type) + ); + const showQuickFunctions = temporaryQuickFunction || isQuickFunctionSelected; + + const showStaticValueFunction = + temporaryStaticValue || + (temporaryState === 'none' && + supportStaticValue && + (!selectedColumn || selectedColumn?.operationType === staticValueOperationName)); + + const addStaticValueColumn = (prevLayer = props.state.layers[props.layerId]) => { + if (selectedColumn?.operationType !== staticValueOperationName) { + trackUiEvent(`indexpattern_dimension_operation_static_value`); + return insertOrReplaceColumn({ + layer: prevLayer, + indexPattern: currentIndexPattern, + columnId, + op: staticValueOperationName, + visualizationGroups: dimensionGroups, + }); + } + return prevLayer; + }; + + // this function intercepts the state update for static value function + // and. if in temporary state, it merges the "add new static value column" state with the incoming + // changes from the static value operation (which has to be a function) + // Note: it forced a rerender at this point to avoid UI glitches in async updates (another hack upstream) + // TODO: revisit this once we get rid of updateDatasourceAsync upstream + const moveDefinetelyToStaticValueAndUpdate = ( + setter: IndexPatternLayer | ((prevLayer: IndexPatternLayer) => IndexPatternLayer) + ) => { + if (temporaryStaticValue) { + setTemporaryState('none'); + if (typeof setter === 'function') { + return setState( + (prevState) => { + const layer = setter(addStaticValueColumn(prevState.layers[layerId])); + return mergeLayer({ state: prevState, layerId, newLayer: layer }); + }, + { + isDimensionComplete: true, + forceRender: true, + } + ); + } + } + return setStateWrapper(setter); + }; - const [temporaryQuickFunction, setQuickFunction] = useState(false); + const ParamEditor = getParamEditor( + temporaryStaticValue, + selectedOperationDefinition, + supportStaticValue && !showQuickFunctions + ); const possibleOperations = useMemo(() => { return Object.values(operationDefinitionMap) @@ -245,9 +291,9 @@ export function DimensionEditor(props: DimensionEditorProps) { [`aria-pressed`]: isActive, onClick() { if ( - operationDefinitionMap[operationType].input === 'none' || - operationDefinitionMap[operationType].input === 'managedReference' || - operationDefinitionMap[operationType].input === 'fullReference' + ['none', 'fullReference', 'managedReference'].includes( + operationDefinitionMap[operationType].input + ) ) { // Clear invalid state because we are reseting to a valid column if (selectedColumn?.operationType === operationType) { @@ -264,9 +310,12 @@ export function DimensionEditor(props: DimensionEditorProps) { visualizationGroups: dimensionGroups, targetGroup: props.groupId, }); - if (temporaryQuickFunction && newLayer.columns[columnId].operationType !== 'formula') { + if ( + temporaryQuickFunction && + isQuickFunction(newLayer.columns[columnId].operationType) + ) { // Only switch the tab once the formula is fully removed - setQuickFunction(false); + setTemporaryState('none'); } setStateWrapper(newLayer); trackUiEvent(`indexpattern_dimension_operation_${operationType}`); @@ -297,9 +346,12 @@ export function DimensionEditor(props: DimensionEditorProps) { }); // ); } - if (temporaryQuickFunction && newLayer.columns[columnId].operationType !== 'formula') { + if ( + temporaryQuickFunction && + isQuickFunction(newLayer.columns[columnId].operationType) + ) { // Only switch the tab once the formula is fully removed - setQuickFunction(false); + setTemporaryState('none'); } setStateWrapper(newLayer); trackUiEvent(`indexpattern_dimension_operation_${operationType}`); @@ -314,7 +366,7 @@ export function DimensionEditor(props: DimensionEditorProps) { } if (temporaryQuickFunction) { - setQuickFunction(false); + setTemporaryState('none'); } const newLayer = replaceColumn({ layer: props.state.layers[props.layerId], @@ -348,29 +400,10 @@ export function DimensionEditor(props: DimensionEditorProps) { !currentFieldIsInvalid && !incompleteInfo && selectedColumn && - selectedColumn.operationType !== 'formula'; + isQuickFunction(selectedColumn.operationType); const quickFunctions = ( <> - {temporaryQuickFunction && selectedColumn?.operationType === 'formula' && ( - <> - -

    - {i18n.translate('xpack.lens.indexPattern.formulaWarningText', { - defaultMessage: 'To overwrite your formula, select a quick function', - })} -

    -
    - - )}
    {i18n.translate('xpack.lens.indexPattern.functionsLabel', { @@ -608,24 +641,28 @@ export function DimensionEditor(props: DimensionEditorProps) { ); - const formulaTab = ParamEditor ? ( - + const customParamEditor = ParamEditor ? ( + <> + + ) : null; + const TabContent = showQuickFunctions ? quickFunctions : customParamEditor; + const onFormatChange = useCallback( (newFormat) => { updateLayer( @@ -640,58 +677,69 @@ export function DimensionEditor(props: DimensionEditorProps) { [columnId, layerId, state.layers, updateLayer] ); + const hasFormula = + !isFullscreen && operationSupportMatrix.operationWithoutField.has(formulaOperationName); + + const hasTabs = hasFormula || supportStaticValue; + return (
    - {!isFullscreen && operationSupportMatrix.operationWithoutField.has('formula') ? ( - - { - if (selectedColumn?.operationType === 'formula') { - setQuickFunction(true); + {hasTabs ? ( + { + if (tabClicked === 'quickFunctions') { + if (selectedColumn && !isQuickFunction(selectedColumn.operationType)) { + setTemporaryState(quickFunctionsName); + return; } - }} - > - {i18n.translate('xpack.lens.indexPattern.quickFunctionsLabel', { - defaultMessage: 'Quick functions', - })} - - { - if (selectedColumn?.operationType !== 'formula') { - setQuickFunction(false); + } + + if (tabClicked === 'static_value') { + // when coming from a formula, set a temporary state + if (selectedColumn?.operationType === formulaOperationName) { + return setTemporaryState(staticValueOperationName); + } + setTemporaryState('none'); + setStateWrapper(addStaticValueColumn()); + return; + } + + if (tabClicked === 'formula') { + setTemporaryState('none'); + if (selectedColumn?.operationType !== formulaOperationName) { const newLayer = insertOrReplaceColumn({ layer: props.state.layers[props.layerId], indexPattern: currentIndexPattern, columnId, - op: 'formula', + op: formulaOperationName, visualizationGroups: dimensionGroups, }); setStateWrapper(newLayer); trackUiEvent(`indexpattern_dimension_operation_formula`); - return; - } else { - setQuickFunction(false); } - }} - > - {i18n.translate('xpack.lens.indexPattern.formulaLabel', { - defaultMessage: 'Formula', - })} - - + } + }} + /> ) : null} - {isFullscreen - ? formulaTab - : selectedOperationDefinition?.type === 'formula' && !temporaryQuickFunction - ? formulaTab - : quickFunctions} + + {TabContent} - {!isFullscreen && !currentFieldIsInvalid && !temporaryQuickFunction && ( + {!isFullscreen && !currentFieldIsInvalid && temporaryState === 'none' && (
    {!incompleteInfo && selectedColumn && ( )} - {!isFullscreen && + {supportFieldFormat && + !isFullscreen && selectedColumn && (selectedColumn.dataType === 'number' || selectedColumn.operationType === 'range') ? ( @@ -735,26 +784,3 @@ export function DimensionEditor(props: DimensionEditorProps) {
    ); } - -function getErrorMessage( - selectedColumn: IndexPatternColumn | undefined, - incompleteOperation: boolean, - input: 'none' | 'field' | 'fullReference' | 'managedReference' | undefined, - fieldInvalid: boolean -) { - if (selectedColumn && incompleteOperation) { - if (input === 'field') { - return i18n.translate('xpack.lens.indexPattern.invalidOperationLabel', { - defaultMessage: 'This field does not work with the selected function.', - }); - } - return i18n.translate('xpack.lens.indexPattern.chooseFieldLabel', { - defaultMessage: 'To use this function, select a field.', - }); - } - if (fieldInvalid) { - return i18n.translate('xpack.lens.indexPattern.invalidFieldLabel', { - defaultMessage: 'Invalid field. Check your index pattern or pick another field.', - }); - } -} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx index 5d56661f15915..d823def1da114 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx @@ -52,6 +52,13 @@ jest.mock('lodash', () => { }; }); jest.mock('../../id_generator'); +// Mock the Monaco Editor component +jest.mock('../operations/definitions/formula/editor/formula_editor', () => { + return { + WrappedFormulaEditor: () =>
    , + FormulaEditor: () =>
    , + }; +}); const fields = [ { @@ -211,6 +218,7 @@ describe('IndexPatternDimensionEditorPanel', () => { dimensionGroups: [], groupId: 'a', isFullscreen: false, + supportStaticValue: false, toggleFullscreen: jest.fn(), }; @@ -402,8 +410,9 @@ describe('IndexPatternDimensionEditorPanel', () => { const items: EuiListGroupItemProps[] = wrapper.find(EuiListGroup).prop('listItems') || []; - expect(items.find(({ id }) => id === 'math')).toBeUndefined(); - expect(items.find(({ id }) => id === 'formula')).toBeUndefined(); + ['math', 'formula', 'static_value'].forEach((hiddenOp) => { + expect(items.some(({ id }) => id === hiddenOp)).toBe(false); + }); }); it('should indicate that reference-based operations are not compatible when they are incomplete', () => { @@ -2217,4 +2226,130 @@ describe('IndexPatternDimensionEditorPanel', () => { 0 ); }); + + it('should not show tabs when formula and static_value operations are not available', () => { + const stateWithInvalidCol: IndexPatternPrivateState = getStateWithColumns({ + col1: { + label: 'Average of memory', + dataType: 'number', + isBucketed: false, + // Private + operationType: 'average', + sourceField: 'memory', + params: { + format: { id: 'bytes', params: { decimals: 2 } }, + }, + }, + }); + + const props = { + ...defaultProps, + filterOperations: jest.fn((op) => { + // the formula operation will fall into this metadata category + return !(op.dataType === 'number' && op.scale === 'ratio'); + }), + }; + + wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="lens-dimensionTabs"]').exists()).toBeFalsy(); + }); + + it('should show the formula tab when supported', () => { + const stateWithFormulaColumn: IndexPatternPrivateState = getStateWithColumns({ + col1: { + label: 'Formula', + dataType: 'number', + isBucketed: false, + operationType: 'formula', + references: ['ref1'], + params: {}, + }, + }); + + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="lens-dimensionTabs-formula"]').first().prop('isSelected') + ).toBeTruthy(); + }); + + it('should now show the static_value tab when not supported', () => { + const stateWithFormulaColumn: IndexPatternPrivateState = getStateWithColumns({ + col1: { + label: 'Formula', + dataType: 'number', + isBucketed: false, + operationType: 'formula', + references: ['ref1'], + params: {}, + }, + }); + + wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="lens-dimensionTabs-static_value"]').exists()).toBeFalsy(); + }); + + it('should show the static value tab when supported', () => { + const staticWithFormulaColumn: IndexPatternPrivateState = getStateWithColumns({ + col1: { + label: 'Formula', + dataType: 'number', + isBucketed: false, + operationType: 'formula', + references: ['ref1'], + params: {}, + }, + }); + + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="lens-dimensionTabs-static_value"]').exists() + ).toBeTruthy(); + }); + + it('should select the quick function tab by default', () => { + const stateWithNoColumn: IndexPatternPrivateState = getStateWithColumns({}); + + wrapper = mount( + + ); + + expect( + wrapper + .find('[data-test-subj="lens-dimensionTabs-quickFunctions"]') + .first() + .prop('isSelected') + ).toBeTruthy(); + }); + + it('should select the static value tab when supported by default', () => { + const stateWithNoColumn: IndexPatternPrivateState = getStateWithColumns({}); + + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="lens-dimensionTabs-static_value"]').first().prop('isSelected') + ).toBeTruthy(); + }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx index f3e51516d161c..ac8296cca968e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx @@ -16,7 +16,7 @@ import { IndexPatternColumn } from '../indexpattern'; import { isColumnInvalid } from '../utils'; import { IndexPatternPrivateState } from '../types'; import { DimensionEditor } from './dimension_editor'; -import type { DateRange } from '../../../common'; +import { DateRange, layerTypes } from '../../../common'; import { getOperationSupportMatrix } from './operation_support'; export type IndexPatternDimensionTriggerProps = @@ -49,11 +49,11 @@ export const IndexPatternDimensionTriggerComponent = function IndexPatternDimens const layerId = props.layerId; const layer = props.state.layers[layerId]; const currentIndexPattern = props.state.indexPatterns[layer.indexPatternId]; - const { columnId, uniqueLabel } = props; + const { columnId, uniqueLabel, invalid, invalidMessage } = props; const currentColumnHasErrors = useMemo( - () => isColumnInvalid(layer, columnId, currentIndexPattern), - [layer, columnId, currentIndexPattern] + () => invalid || isColumnInvalid(layer, columnId, currentIndexPattern), + [layer, columnId, currentIndexPattern, invalid] ); const selectedColumn: IndexPatternColumn | null = layer.columns[props.columnId] ?? null; @@ -67,15 +67,17 @@ export const IndexPatternDimensionTriggerComponent = function IndexPatternDimens return ( - {i18n.translate('xpack.lens.configure.invalidConfigTooltip', { - defaultMessage: 'Invalid configuration.', - })} -
    - {i18n.translate('xpack.lens.configure.invalidConfigTooltipClick', { - defaultMessage: 'Click for more details.', - })} -

    + invalidMessage ?? ( +

    + {i18n.translate('xpack.lens.configure.invalidConfigTooltip', { + defaultMessage: 'Invalid configuration.', + })} +
    + {i18n.translate('xpack.lens.configure.invalidConfigTooltipClick', { + defaultMessage: 'Click for more details.', + })} +

    + ) } anchorClassName="eui-displayBlock" > @@ -127,6 +129,7 @@ export const IndexPatternDimensionEditorComponent = function IndexPatternDimensi return ( void; +}) => { + const { inputValue, handleInputChange, initialValue } = useDebouncedValue({ onChange, value }); + + return ( + + { + handleInputChange(e.target.value); + }} + placeholder={initialValue} + /> + + ); +}; + +export function getParamEditor( + temporaryStaticValue: boolean, + selectedOperationDefinition: typeof operationDefinitionMap[string] | undefined, + showDefaultStaticValue: boolean +) { + if (temporaryStaticValue) { + return operationDefinitionMap[staticValueOperationName].paramEditor; + } + if (selectedOperationDefinition?.paramEditor) { + return selectedOperationDefinition.paramEditor; + } + if (showDefaultStaticValue) { + return operationDefinitionMap[staticValueOperationName].paramEditor; + } + return null; +} + +export const CalloutWarning = ({ + currentOperationType, + temporaryStateType, +}: { + currentOperationType: keyof typeof operationDefinitionMap | undefined; + temporaryStateType: TemporaryState; +}) => { + if ( + temporaryStateType === 'none' || + (currentOperationType != null && isQuickFunction(currentOperationType)) + ) { + return null; + } + if ( + currentOperationType === staticValueOperationName && + temporaryStateType === 'quickFunctions' + ) { + return ( + <> + +

    + {i18n.translate('xpack.lens.indexPattern.staticValueWarningText', { + defaultMessage: 'To overwrite your static value, select a quick function', + })} +

    +
    + + ); + } + return ( + <> + + {temporaryStateType !== 'quickFunctions' ? ( +

    + {i18n.translate('xpack.lens.indexPattern.formulaWarningStaticValueText', { + defaultMessage: 'To overwrite your formula, change the value in the input field', + })} +

    + ) : ( +

    + {i18n.translate('xpack.lens.indexPattern.formulaWarningText', { + defaultMessage: 'To overwrite your formula, select a quick function', + })} +

    + )} +
    + + ); +}; + +type DimensionEditorTabsType = + | typeof quickFunctionsName + | typeof staticValueOperationName + | typeof formulaOperationName; + +export const DimensionEditorTabs = ({ + tabsEnabled, + tabsState, + onClick, +}: { + tabsEnabled: Record; + tabsState: Record; + onClick: (tabClicked: DimensionEditorTabsType) => void; +}) => { + return ( + + {tabsEnabled.static_value ? ( + onClick(staticValueOperationName)} + > + {i18n.translate('xpack.lens.indexPattern.staticValueLabel', { + defaultMessage: 'Static value', + })} + + ) : null} + onClick(quickFunctionsName)} + > + {i18n.translate('xpack.lens.indexPattern.quickFunctionsLabel', { + defaultMessage: 'Quick functions', + })} + + {tabsEnabled.formula ? ( + onClick(formulaOperationName)} + > + {i18n.translate('xpack.lens.indexPattern.formulaLabel', { + defaultMessage: 'Formula', + })} + + ) : null} + + ); +}; + +export function getErrorMessage( + selectedColumn: IndexPatternColumn | undefined, + incompleteOperation: boolean, + input: 'none' | 'field' | 'fullReference' | 'managedReference' | undefined, + fieldInvalid: boolean +) { + if (selectedColumn && incompleteOperation) { + if (input === 'field') { + return i18n.translate('xpack.lens.indexPattern.invalidOperationLabel', { + defaultMessage: 'This field does not work with the selected function.', + }); + } + return i18n.translate('xpack.lens.indexPattern.chooseFieldLabel', { + defaultMessage: 'To use this function, select a field.', + }); + } + if (fieldInvalid) { + return i18n.translate('xpack.lens.indexPattern.invalidFieldLabel', { + defaultMessage: 'Invalid field. Check your index pattern or pick another field.', + }); + } +} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts index 26aac5dab31e3..85807721f80f6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts @@ -17,6 +17,7 @@ import { OperationMetadata, DropType } from '../../../types'; import { IndexPatternColumn, MedianIndexPatternColumn } from '../../operations'; import { getFieldByNameFactory } from '../../pure_helpers'; import { generateId } from '../../../id_generator'; +import { layerTypes } from '../../../../common'; jest.mock('../../../id_generator'); @@ -263,7 +264,6 @@ describe('IndexPatternDimensionEditorPanel', () => { dateRange: { fromDate: 'now-1d', toDate: 'now' }, columnId: 'col1', layerId: 'first', - layerType: 'data', uniqueLabel: 'stuff', groupId: 'group1', filterOperations: () => true, @@ -287,6 +287,8 @@ describe('IndexPatternDimensionEditorPanel', () => { dimensionGroups: [], isFullscreen: false, toggleFullscreen: () => {}, + supportStaticValue: false, + layerType: layerTypes.DATA, }; jest.clearAllMocks(); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts index e09c3e904f535..b518f667a0bfb 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts @@ -121,8 +121,12 @@ function onMoveCompatible( indexPattern, }); - let updatedColumnOrder = getColumnOrder(modifiedLayer); - updatedColumnOrder = reorderByGroups(dimensionGroups, groupId, updatedColumnOrder, columnId); + const updatedColumnOrder = reorderByGroups( + dimensionGroups, + groupId, + getColumnOrder(modifiedLayer), + columnId + ); // Time to replace setState( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index 06c8a50cd2dfa..1dfc7d40f6f3e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -1623,4 +1623,87 @@ describe('IndexPattern Data Source', () => { expect(indexPatternDatasource.isTimeBased(state)).toEqual(false); }); }); + + describe('#initializeDimension', () => { + it('should return the same state if no static value is passed', () => { + const state = enrichBaseState({ + currentIndexPatternId: '1', + layers: { + first: { + indexPatternId: '1', + columnOrder: ['metric'], + columns: { + metric: { + label: 'Count of records', + dataType: 'number', + isBucketed: false, + sourceField: 'Records', + operationType: 'count', + }, + }, + }, + }, + }); + expect( + indexPatternDatasource.initializeDimension!(state, 'first', { + columnId: 'newStatic', + label: 'MyNewColumn', + groupId: 'a', + dataType: 'number', + }) + ).toBe(state); + }); + + it('should add a new static value column if a static value is passed', () => { + const state = enrichBaseState({ + currentIndexPatternId: '1', + layers: { + first: { + indexPatternId: '1', + columnOrder: ['metric'], + columns: { + metric: { + label: 'Count of records', + dataType: 'number', + isBucketed: false, + sourceField: 'Records', + operationType: 'count', + }, + }, + }, + }, + }); + expect( + indexPatternDatasource.initializeDimension!(state, 'first', { + columnId: 'newStatic', + label: 'MyNewColumn', + groupId: 'a', + dataType: 'number', + staticValue: 0, // use a falsy value to check also this corner case + }) + ).toEqual({ + ...state, + layers: { + ...state.layers, + first: { + ...state.layers.first, + incompleteColumns: {}, + columnOrder: ['metric', 'newStatic'], + columns: { + ...state.layers.first.columns, + newStatic: { + dataType: 'number', + isBucketed: false, + label: 'Static value: 0', + operationType: 'static_value', + params: { value: 0 }, + references: [], + scale: 'ratio', + }, + }, + }, + }, + }); + }); + }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index 6a45e3c987f3d..2138b06a4c344 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -44,7 +44,7 @@ import { import { isDraggedField, normalizeOperationDataType } from './utils'; import { LayerPanel } from './layerpanel'; -import { IndexPatternColumn, getErrorMessages } from './operations'; +import { IndexPatternColumn, getErrorMessages, insertNewColumn } from './operations'; import { IndexPatternField, IndexPatternPrivateState, IndexPatternPersistedState } from './types'; import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; @@ -192,6 +192,27 @@ export function getIndexPatternDatasource({ }); }, + initializeDimension(state, layerId, { columnId, groupId, label, dataType, staticValue }) { + const indexPattern = state.indexPatterns[state.layers[layerId]?.indexPatternId]; + if (staticValue == null) { + return state; + } + return mergeLayer({ + state, + layerId, + newLayer: insertNewColumn({ + layer: state.layers[layerId], + op: 'static_value', + columnId, + field: undefined, + indexPattern, + visualizationGroups: [], + initialParams: { params: { value: staticValue } }, + targetGroup: groupId, + }), + }); + }, + toExpression: (state, layerId) => toExpression(state, layerId, uiSettings), renderDataPanel( @@ -404,9 +425,14 @@ export function getIndexPatternDatasource({ }, }; }, - getDatasourceSuggestionsForField(state, draggedField) { + getDatasourceSuggestionsForField(state, draggedField, filterLayers) { return isDraggedField(draggedField) - ? getDatasourceSuggestionsForField(state, draggedField.indexPatternId, draggedField.field) + ? getDatasourceSuggestionsForField( + state, + draggedField.indexPatternId, + draggedField.field, + filterLayers + ) : []; }, getDatasourceSuggestionsFromCurrentState, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx index 4b8bbc09c6799..a5d6db4be3319 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx @@ -1198,6 +1198,91 @@ describe('IndexPattern Data Source suggestions', () => { }) ); }); + + it('should apply layers filter if passed and model the suggestion based on that', () => { + (generateId as jest.Mock).mockReturnValue('newid'); + const initialState = stateWithNonEmptyTables(); + + const modifiedState: IndexPatternPrivateState = { + ...initialState, + layers: { + thresholdLayer: { + indexPatternId: '1', + columnOrder: ['threshold'], + columns: { + threshold: { + dataType: 'number', + isBucketed: false, + label: 'Static Value: 0', + operationType: 'static_value', + params: { value: '0' }, + references: [], + scale: 'ratio', + }, + }, + }, + currentLayer: { + indexPatternId: '1', + columnOrder: ['metric', 'ref'], + columns: { + metric: { + label: '', + customLabel: true, + dataType: 'number', + isBucketed: false, + operationType: 'average', + sourceField: 'bytes', + }, + ref: { + label: '', + customLabel: true, + dataType: 'number', + isBucketed: false, + operationType: 'cumulative_sum', + references: ['metric'], + }, + }, + }, + }, + }; + + const suggestions = getSuggestionSubset( + getDatasourceSuggestionsForField( + modifiedState, + '1', + documentField, + (layerId) => layerId !== 'thresholdLayer' + ) + ); + // should ignore the threshold layer + expect(suggestions).toContainEqual( + expect.objectContaining({ + table: expect.objectContaining({ + changeType: 'extended', + columns: [ + { + columnId: 'ref', + operation: { + dataType: 'number', + isBucketed: false, + label: '', + scale: undefined, + }, + }, + { + columnId: 'newid', + operation: { + dataType: 'number', + isBucketed: false, + label: 'Count of records', + scale: 'ratio', + }, + }, + ], + }), + }) + ); + }); }); describe('finding the layer that is using the current index pattern', () => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts index b0793bf912bb2..0fe0ef617dc27 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts @@ -95,10 +95,14 @@ function buildSuggestion({ export function getDatasourceSuggestionsForField( state: IndexPatternPrivateState, indexPatternId: string, - field: IndexPatternField + field: IndexPatternField, + filterLayers?: (layerId: string) => boolean ): IndexPatternSuggestion[] { const layers = Object.keys(state.layers); - const layerIds = layers.filter((id) => state.layers[id].indexPatternId === indexPatternId); + let layerIds = layers.filter((id) => state.layers[id].indexPatternId === indexPatternId); + if (filterLayers) { + layerIds = layerIds.filter(filterLayers); + } if (layerIds.length === 0) { // The field we're suggesting on does not match any existing layer. diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.test.tsx index c2ba893a9b90e..499170349c3d5 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.test.tsx @@ -355,6 +355,33 @@ describe('formula', () => { references: [], }); }); + + it('should move into Formula previous static_value operation', () => { + expect( + formulaOperation.buildColumn({ + previousColumn: { + label: 'Static value: 0', + dataType: 'number', + isBucketed: false, + operationType: 'static_value', + references: [], + params: { + value: '0', + }, + }, + layer, + indexPattern, + }) + ).toEqual({ + label: '0', + dataType: 'number', + operationType: 'formula', + isBucketed: false, + scale: 'ratio', + params: { isFormulaBroken: false, formula: '0' }, + references: [], + }); + }); }); describe('regenerateLayerFromAst()', () => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/generate.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/generate.ts index 589f547434b91..3db9ebc6f969d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/generate.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/generate.ts @@ -38,6 +38,11 @@ export function generateFormula( previousFormula: string, operationDefinitionMap: Record | undefined ) { + if (previousColumn.operationType === 'static_value') { + if (previousColumn.params && 'value' in previousColumn.params) { + return String(previousColumn.params.value); // make sure it's a string + } + } if ('references' in previousColumn) { const metric = layer.columns[previousColumn.references[0]]; if (metric && 'sourceField' in metric && metric.dataType === 'number') { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx index 45abbcd3d9cf9..a399183694863 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { IndexPatternColumn, operationDefinitionMap } from '.'; -import { FieldBasedIndexPatternColumn } from './column_types'; +import { FieldBasedIndexPatternColumn, ReferenceBasedIndexPatternColumn } from './column_types'; import { IndexPattern } from '../../types'; export function getInvalidFieldMessage( @@ -81,8 +81,7 @@ export function isValidNumber( const inputValueAsNumber = Number(inputValue); return ( inputValue !== '' && - inputValue !== null && - inputValue !== undefined && + inputValue != null && !Number.isNaN(inputValueAsNumber) && Number.isFinite(inputValueAsNumber) && (!integer || Number.isInteger(inputValueAsNumber)) && @@ -91,7 +90,9 @@ export function isValidNumber( ); } -export function getFormatFromPreviousColumn(previousColumn: IndexPatternColumn | undefined) { +export function getFormatFromPreviousColumn( + previousColumn: IndexPatternColumn | ReferenceBasedIndexPatternColumn | undefined +) { return previousColumn?.dataType === 'number' && previousColumn.params && 'format' in previousColumn.params && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts index 326b71f72c060..0212c73f46879 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts @@ -49,6 +49,7 @@ import { formulaOperation, FormulaIndexPatternColumn, } from './formula'; +import { staticValueOperation, StaticValueIndexPatternColumn } from './static_value'; import { lastValueOperation, LastValueIndexPatternColumn } from './last_value'; import { FrameDatasourceAPI, OperationMetadata } from '../../../types'; import type { BaseIndexPatternColumn, ReferenceBasedIndexPatternColumn } from './column_types'; @@ -87,7 +88,8 @@ export type IndexPatternColumn = | DerivativeIndexPatternColumn | MovingAverageIndexPatternColumn | MathIndexPatternColumn - | FormulaIndexPatternColumn; + | FormulaIndexPatternColumn + | StaticValueIndexPatternColumn; export type FieldBasedIndexPatternColumn = Extract; @@ -119,6 +121,7 @@ export { CountIndexPatternColumn } from './count'; export { LastValueIndexPatternColumn } from './last_value'; export { RangeIndexPatternColumn } from './ranges'; export { FormulaIndexPatternColumn, MathIndexPatternColumn } from './formula'; +export { StaticValueIndexPatternColumn } from './static_value'; // List of all operation definitions registered to this data source. // If you want to implement a new operation, add the definition to this array and @@ -147,6 +150,7 @@ const internalOperationDefinitions = [ overallMinOperation, overallMaxOperation, overallAverageOperation, + staticValueOperation, ]; export { termsOperation } from './terms'; @@ -168,6 +172,7 @@ export { overallMinOperation, } from './calculations'; export { formulaOperation } from './formula/formula'; +export { staticValueOperation } from './static_value'; /** * Properties passed to the operation-specific part of the popover editor diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx new file mode 100644 index 0000000000000..0a6620eecf308 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx @@ -0,0 +1,404 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { shallow, mount } from 'enzyme'; +import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'kibana/public'; +import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; +import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; +import { createMockedIndexPattern } from '../../mocks'; +import { staticValueOperation } from './index'; +import { IndexPattern, IndexPatternLayer } from '../../types'; +import { StaticValueIndexPatternColumn } from './static_value'; +import { EuiFieldNumber } from '@elastic/eui'; +import { act } from 'react-dom/test-utils'; + +jest.mock('lodash', () => { + const original = jest.requireActual('lodash'); + + return { + ...original, + debounce: (fn: unknown) => fn, + }; +}); + +const uiSettingsMock = {} as IUiSettingsClient; + +const defaultProps = { + storage: {} as IStorageWrapper, + uiSettings: uiSettingsMock, + savedObjectsClient: {} as SavedObjectsClientContract, + dateRange: { fromDate: 'now-1d', toDate: 'now' }, + data: dataPluginMock.createStartContract(), + http: {} as HttpSetup, + indexPattern: { + ...createMockedIndexPattern(), + hasRestrictions: false, + } as IndexPattern, + operationDefinitionMap: {}, + isFullscreen: false, + toggleFullscreen: jest.fn(), + setIsCloseable: jest.fn(), + layerId: '1', +}; + +describe('static_value', () => { + let layer: IndexPatternLayer; + + beforeEach(() => { + layer = { + indexPatternId: '1', + columnOrder: ['col1', 'col2'], + columns: { + col1: { + label: 'Top value of category', + dataType: 'string', + isBucketed: true, + operationType: 'terms', + params: { + orderBy: { type: 'alphabetical' }, + size: 3, + orderDirection: 'asc', + }, + sourceField: 'category', + }, + col2: { + label: 'Static value: 23', + dataType: 'number', + isBucketed: false, + operationType: 'static_value', + references: [], + params: { + value: '23', + }, + }, + }, + }; + }); + + function getLayerWithStaticValue(newValue: string): IndexPatternLayer { + return { + ...layer, + columns: { + ...layer.columns, + col2: { + ...layer.columns.col2, + label: `Static value: ${newValue}`, + params: { + value: newValue, + }, + } as StaticValueIndexPatternColumn, + }, + }; + } + + describe('getDefaultLabel', () => { + it('should return the label for the given value', () => { + expect( + staticValueOperation.getDefaultLabel( + { + label: 'Static value: 23', + dataType: 'number', + isBucketed: false, + operationType: 'static_value', + references: [], + params: { + value: '23', + }, + }, + createMockedIndexPattern(), + layer.columns + ) + ).toBe('Static value: 23'); + }); + + it('should return the default label for non valid value', () => { + expect( + staticValueOperation.getDefaultLabel( + { + label: 'Static value', + dataType: 'number', + isBucketed: false, + operationType: 'static_value', + references: [], + params: { + value: '', + }, + }, + createMockedIndexPattern(), + layer.columns + ) + ).toBe('Static value'); + }); + }); + + describe('getErrorMessage', () => { + it('should return no error for valid values', () => { + expect( + staticValueOperation.getErrorMessage!( + getLayerWithStaticValue('23'), + 'col2', + createMockedIndexPattern() + ) + ).toBeUndefined(); + // test for potential falsy value + expect( + staticValueOperation.getErrorMessage!( + getLayerWithStaticValue('0'), + 'col2', + createMockedIndexPattern() + ) + ).toBeUndefined(); + }); + + it('should return error for invalid values', () => { + for (const value of ['NaN', 'Infinity', 'string']) { + expect( + staticValueOperation.getErrorMessage!( + getLayerWithStaticValue(value), + 'col2', + createMockedIndexPattern() + ) + ).toEqual(expect.arrayContaining([expect.stringMatching('is not a valid number')])); + } + }); + }); + + describe('toExpression', () => { + it('should return a mathColumn operation with valid value', () => { + for (const value of ['23', '0', '-1']) { + expect( + staticValueOperation.toExpression( + getLayerWithStaticValue(value), + 'col2', + createMockedIndexPattern() + ) + ).toEqual([ + { + type: 'function', + function: 'mathColumn', + arguments: { + id: ['col2'], + name: [`Static value: ${value}`], + expression: [value], + }, + }, + ]); + } + }); + + it('should fallback to mapColumn for invalid value', () => { + for (const value of ['NaN', '', 'Infinity']) { + expect( + staticValueOperation.toExpression( + getLayerWithStaticValue(value), + 'col2', + createMockedIndexPattern() + ) + ).toEqual([ + { + type: 'function', + function: 'mapColumn', + arguments: { + id: ['col2'], + name: [`Static value`], + expression: ['100'], + }, + }, + ]); + } + }); + }); + + describe('buildColumn', () => { + it('should set default static value', () => { + expect( + staticValueOperation.buildColumn({ + indexPattern: createMockedIndexPattern(), + layer: { columns: {}, columnOrder: [], indexPatternId: '' }, + }) + ).toEqual({ + label: 'Static value', + dataType: 'number', + operationType: 'static_value', + isBucketed: false, + scale: 'ratio', + params: { value: '100' }, + references: [], + }); + }); + + it('should merge a previousColumn', () => { + expect( + staticValueOperation.buildColumn({ + indexPattern: createMockedIndexPattern(), + layer: { columns: {}, columnOrder: [], indexPatternId: '' }, + previousColumn: { + label: 'Static value', + dataType: 'number', + operationType: 'static_value', + isBucketed: false, + scale: 'ratio', + params: { value: '23' }, + references: [], + }, + }) + ).toEqual({ + label: 'Static value: 23', + dataType: 'number', + operationType: 'static_value', + isBucketed: false, + scale: 'ratio', + params: { value: '23' }, + references: [], + }); + }); + + it('should create a static_value from passed arguments', () => { + expect( + staticValueOperation.buildColumn( + { + indexPattern: createMockedIndexPattern(), + layer: { columns: {}, columnOrder: [], indexPatternId: '' }, + }, + { value: '23' } + ) + ).toEqual({ + label: 'Static value: 23', + dataType: 'number', + operationType: 'static_value', + isBucketed: false, + scale: 'ratio', + params: { value: '23' }, + references: [], + }); + }); + + it('should prioritize passed arguments over previousColumn', () => { + expect( + staticValueOperation.buildColumn( + { + indexPattern: createMockedIndexPattern(), + layer: { columns: {}, columnOrder: [], indexPatternId: '' }, + previousColumn: { + label: 'Static value', + dataType: 'number', + operationType: 'static_value', + isBucketed: false, + scale: 'ratio', + params: { value: '23' }, + references: [], + }, + }, + { value: '53' } + ) + ).toEqual({ + label: 'Static value: 53', + dataType: 'number', + operationType: 'static_value', + isBucketed: false, + scale: 'ratio', + params: { value: '53' }, + references: [], + }); + }); + }); + + describe('paramEditor', () => { + const ParamEditor = staticValueOperation.paramEditor!; + it('should render current static_value', () => { + const updateLayerSpy = jest.fn(); + const instance = shallow( + + ); + + const input = instance.find('[data-test-subj="lns-indexPattern-static_value-input"]'); + + expect(input.prop('value')).toEqual('23'); + }); + + it('should update state on change', async () => { + const updateLayerSpy = jest.fn(); + const instance = mount( + + ); + + const input = instance + .find('[data-test-subj="lns-indexPattern-static_value-input"]') + .find(EuiFieldNumber); + + await act(async () => { + input.prop('onChange')!({ + currentTarget: { value: '27' }, + } as React.ChangeEvent); + }); + + instance.update(); + + expect(updateLayerSpy.mock.calls[0]).toEqual([expect.any(Function)]); + // check that the result of the setter call is correct + expect(updateLayerSpy.mock.calls[0][0](layer)).toEqual({ + ...layer, + columns: { + ...layer.columns, + col2: { + ...layer.columns.col2, + params: { + value: '27', + }, + label: 'Static value: 27', + }, + }, + }); + }); + + it('should not update on invalid input, but show invalid value locally', async () => { + const updateLayerSpy = jest.fn(); + const instance = mount( + + ); + + const input = instance + .find('[data-test-subj="lns-indexPattern-static_value-input"]') + .find(EuiFieldNumber); + + await act(async () => { + input.prop('onChange')!({ + currentTarget: { value: '' }, + } as React.ChangeEvent); + }); + + instance.update(); + + expect(updateLayerSpy).not.toHaveBeenCalled(); + expect( + instance + .find('[data-test-subj="lns-indexPattern-static_value-input"]') + .find(EuiFieldNumber) + .prop('value') + ).toEqual(''); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx new file mode 100644 index 0000000000000..a76c5f64d1750 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx @@ -0,0 +1,222 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiFieldNumber, EuiFormLabel, EuiSpacer } from '@elastic/eui'; +import { OperationDefinition } from './index'; +import { ReferenceBasedIndexPatternColumn } from './column_types'; +import type { IndexPattern } from '../../types'; +import { useDebouncedValue } from '../../../shared_components'; +import { getFormatFromPreviousColumn, isValidNumber } from './helpers'; + +const defaultLabel = i18n.translate('xpack.lens.indexPattern.staticValueLabelDefault', { + defaultMessage: 'Static value', +}); + +const defaultValue = 100; + +function isEmptyValue(value: number | string | undefined) { + return value == null || value === ''; +} + +function ofName(value: number | string | undefined) { + if (isEmptyValue(value)) { + return defaultLabel; + } + return i18n.translate('xpack.lens.indexPattern.staticValueLabelWithValue', { + defaultMessage: 'Static value: {value}', + values: { value }, + }); +} + +export interface StaticValueIndexPatternColumn extends ReferenceBasedIndexPatternColumn { + operationType: 'static_value'; + params: { + value?: string; + format?: { + id: string; + params?: { + decimals: number; + }; + }; + }; +} + +export const staticValueOperation: OperationDefinition< + StaticValueIndexPatternColumn, + 'managedReference' +> = { + type: 'static_value', + displayName: defaultLabel, + getDefaultLabel: (column) => ofName(column.params.value), + input: 'managedReference', + hidden: true, + getDisabledStatus(indexPattern: IndexPattern) { + return undefined; + }, + getErrorMessage(layer, columnId) { + const column = layer.columns[columnId] as StaticValueIndexPatternColumn; + + return !isValidNumber(column.params.value) + ? [ + i18n.translate('xpack.lens.indexPattern.staticValueError', { + defaultMessage: 'The static value of {value} is not a valid number', + values: { value: column.params.value }, + }), + ] + : undefined; + }, + getPossibleOperation() { + return { + dataType: 'number', + isBucketed: false, + scale: 'ratio', + }; + }, + toExpression: (layer, columnId) => { + const currentColumn = layer.columns[columnId] as StaticValueIndexPatternColumn; + const params = currentColumn.params; + // TODO: improve this logic + const useDisplayLabel = currentColumn.label !== defaultLabel; + const label = isValidNumber(params.value) + ? useDisplayLabel + ? currentColumn.label + : params?.value ?? defaultLabel + : defaultLabel; + + return [ + { + type: 'function', + function: isValidNumber(params.value) ? 'mathColumn' : 'mapColumn', + arguments: { + id: [columnId], + name: [label || defaultLabel], + expression: [isValidNumber(params.value) ? params.value! : String(defaultValue)], + }, + }, + ]; + }, + buildColumn({ previousColumn, layer, indexPattern }, columnParams, operationDefinitionMap) { + const existingStaticValue = + previousColumn?.params && + 'value' in previousColumn.params && + isValidNumber(previousColumn.params.value) + ? previousColumn.params.value + : undefined; + const previousParams: StaticValueIndexPatternColumn['params'] = { + ...{ value: existingStaticValue }, + ...getFormatFromPreviousColumn(previousColumn), + ...columnParams, + }; + return { + label: ofName(previousParams.value), + dataType: 'number', + operationType: 'static_value', + isBucketed: false, + scale: 'ratio', + params: { ...previousParams, value: previousParams.value ?? String(defaultValue) }, + references: [], + }; + }, + isTransferable: (column) => { + return true; + }, + createCopy(layer, sourceId, targetId, indexPattern, operationDefinitionMap) { + const currentColumn = layer.columns[sourceId] as StaticValueIndexPatternColumn; + return { + ...layer, + columns: { + ...layer.columns, + [targetId]: { ...currentColumn }, + }, + }; + }, + + paramEditor: function StaticValueEditor({ + layer, + updateLayer, + currentColumn, + columnId, + activeData, + layerId, + indexPattern, + }) { + const onChange = useCallback( + (newValue) => { + // even if debounced it's triggering for empty string with the previous valid value + if (currentColumn.params.value === newValue) { + return; + } + // Because of upstream specific UX flows, we need fresh layer state here + // so need to use the updater pattern + updateLayer((newLayer) => { + const newColumn = newLayer.columns[columnId] as StaticValueIndexPatternColumn; + return { + ...newLayer, + columns: { + ...newLayer.columns, + [columnId]: { + ...newColumn, + label: newColumn?.customLabel ? newColumn.label : ofName(newValue), + params: { + ...newColumn.params, + value: newValue, + }, + }, + }, + }; + }); + }, + [columnId, updateLayer, currentColumn?.params?.value] + ); + + // Pick the data from the current activeData (to be used when the current operation is not static_value) + const activeDataValue = + activeData && + activeData[layerId] && + activeData[layerId]?.rows?.length === 1 && + activeData[layerId].rows[0][columnId]; + + const fallbackValue = + currentColumn?.operationType !== 'static_value' && activeDataValue != null + ? activeDataValue + : String(defaultValue); + + const { inputValue, handleInputChange } = useDebouncedValue( + { + value: currentColumn?.params?.value || fallbackValue, + onChange, + }, + { allowFalsyValue: true } + ); + + const onChangeHandler = useCallback( + (e: React.ChangeEvent) => { + const value = e.currentTarget.value; + handleInputChange(isValidNumber(value) ? value : undefined); + }, + [handleInputChange] + ); + + return ( +
    + + {i18n.translate('xpack.lens.indexPattern.staticValue.label', { + defaultMessage: 'Threshold value', + })} + + + +
    + ); + }, +}; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts index 11c8206fee021..baacc7bb64d16 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts @@ -184,6 +184,7 @@ export function insertNewColumn({ targetGroup, shouldResetLabel, incompleteParams, + initialParams, }: ColumnChange): IndexPatternLayer { const operationDefinition = operationDefinitionMap[op]; @@ -197,7 +198,7 @@ export function insertNewColumn({ const baseOptions = { indexPattern, - previousColumn: { ...incompleteParams, ...layer.columns[columnId] }, + previousColumn: { ...incompleteParams, ...initialParams, ...layer.columns[columnId] }, }; if (operationDefinition.input === 'none' || operationDefinition.input === 'managedReference') { @@ -396,9 +397,17 @@ export function replaceColumn({ tempLayer = resetIncomplete(tempLayer, columnId); - if (previousDefinition.input === 'managedReference') { + if ( + previousDefinition.input === 'managedReference' && + operationDefinition.input !== previousDefinition.input + ) { // If the transition is incomplete, leave the managed state until it's finished. - tempLayer = deleteColumn({ layer: tempLayer, columnId, indexPattern }); + tempLayer = removeOrphanedColumns( + previousDefinition, + previousColumn, + tempLayer, + indexPattern + ); const hypotheticalLayer = insertNewColumn({ layer: tempLayer, @@ -641,21 +650,31 @@ function removeOrphanedColumns( previousDefinition: | OperationDefinition | OperationDefinition - | OperationDefinition, + | OperationDefinition + | OperationDefinition, previousColumn: IndexPatternColumn, tempLayer: IndexPatternLayer, indexPattern: IndexPattern ) { + let newLayer: IndexPatternLayer = tempLayer; + if (previousDefinition.input === 'managedReference') { + const [columnId] = + Object.entries(tempLayer.columns).find(([_, currColumn]) => currColumn === previousColumn) || + []; + if (columnId != null) { + newLayer = deleteColumn({ layer: tempLayer, columnId, indexPattern }); + } + } if (previousDefinition.input === 'fullReference') { (previousColumn as ReferenceBasedIndexPatternColumn).references.forEach((id: string) => { - tempLayer = deleteColumn({ + newLayer = deleteColumn({ layer: tempLayer, columnId: id, indexPattern, }); }); } - return tempLayer; + return newLayer; } export function canTransition({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts index 2ed6e2b3a7bcb..08136ed501cfc 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts @@ -378,6 +378,10 @@ describe('getOperationTypesForField', () => { "operationType": "formula", "type": "managedReference", }, + Object { + "operationType": "static_value", + "type": "managedReference", + }, ], }, Object { diff --git a/x-pack/plugins/lens/public/mocks.tsx b/x-pack/plugins/lens/public/mocks.tsx index 47a2e00055ce3..402440f3302f6 100644 --- a/x-pack/plugins/lens/public/mocks.tsx +++ b/x-pack/plugins/lens/public/mocks.tsx @@ -59,9 +59,9 @@ export function mockDatasourceStates() { }; } -export function createMockVisualization(): jest.Mocked { +export function createMockVisualization(id = 'vis1'): jest.Mocked { return { - id: 'TEST_VIS', + id, clearLayer: jest.fn((state, _layerId) => state), removeLayer: jest.fn(), getLayerIds: jest.fn((_state) => ['layer1']), @@ -70,9 +70,9 @@ export function createMockVisualization(): jest.Mocked { visualizationTypes: [ { icon: 'empty', - id: 'TEST_VIS', + id, label: 'TEST', - groupLabel: 'TEST_VISGroup', + groupLabel: `${id}Group`, }, ], getVisualizationTypeId: jest.fn((_state) => 'empty'), @@ -122,7 +122,7 @@ export function createMockDatasource(id: string): DatasourceMock { return { id: 'mockindexpattern', clearLayer: jest.fn((state, _layerId) => state), - getDatasourceSuggestionsForField: jest.fn((_state, _item) => []), + getDatasourceSuggestionsForField: jest.fn((_state, _item, filterFn) => []), getDatasourceSuggestionsForVisualizeField: jest.fn((_state, _indexpatternId, _fieldName) => []), getDatasourceSuggestionsFromCurrentState: jest.fn((_state) => []), getPersistableState: jest.fn((x) => ({ diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 5326927d2c6c5..7891b5990989c 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -233,10 +233,10 @@ export class LensPlugin { const getPresentationUtilContext = () => startServices().plugins.presentationUtil.ContextProvider; - const ensureDefaultIndexPattern = async () => { + const ensureDefaultDataView = async () => { // make sure a default index pattern exists // if not, the page will be redirected to management and visualize won't be rendered - await startServices().plugins.data.indexPatterns.ensureDefaultIndexPattern(); + await startServices().plugins.data.indexPatterns.ensureDefaultDataView(); }; core.application.register({ @@ -261,7 +261,7 @@ export class LensPlugin { const frameStart = this.editorFrameService!.start(coreStart, deps); this.stopReportManager = stopReportManager; - await ensureDefaultIndexPattern(); + await ensureDefaultDataView(); return mountApp(core, params, { createEditorFrame: frameStart.createInstance, attributeService: getLensAttributeService(coreStart, deps), diff --git a/x-pack/plugins/lens/public/shared_components/debounced_value.ts b/x-pack/plugins/lens/public/shared_components/debounced_value.ts index fa8fc22dedd57..412199a371f1f 100644 --- a/x-pack/plugins/lens/public/shared_components/debounced_value.ts +++ b/x-pack/plugins/lens/public/shared_components/debounced_value.ts @@ -11,6 +11,10 @@ import { debounce } from 'lodash'; /** * Debounces value changes and updates inputValue on root state changes if no debounced changes * are in flight because the user is currently modifying the value. + * + * * allowFalsyValue: update upstream with all falsy values but null or undefined + * + * When testing this function mock the "debounce" function in lodash (see this module test for an example) */ export const useDebouncedValue = ( diff --git a/x-pack/plugins/lens/public/shared_components/index.ts b/x-pack/plugins/lens/public/shared_components/index.ts index c200a18a25caf..f947ce699dce4 100644 --- a/x-pack/plugins/lens/public/shared_components/index.ts +++ b/x-pack/plugins/lens/public/shared_components/index.ts @@ -14,3 +14,4 @@ export * from './coloring'; export { useDebouncedValue } from './debounced_value'; export * from './helpers'; export { LegendActionPopover } from './legend_action_popover'; +export * from './static_header'; diff --git a/x-pack/plugins/lens/public/shared_components/static_header.tsx b/x-pack/plugins/lens/public/shared_components/static_header.tsx new file mode 100644 index 0000000000000..2250358234a7f --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/static_header.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiTitle, IconType } from '@elastic/eui'; + +export const StaticHeader = ({ label, icon }: { label: string; icon?: IconType }) => { + return ( + + {icon && ( + + {' '} + + )} + + +
    {label}
    +
    +
    +
    + ); +}; diff --git a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts index 0f5f1c15d4fa7..7db03a17a3a8f 100644 --- a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts +++ b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts @@ -149,7 +149,7 @@ export function loadInitial( datasourceMap, datasourceStates, visualizationMap, - activeVisualizationId: Object.keys(visualizationMap)[0] || null, + activeVisualization: visualizationMap?.[Object.keys(visualizationMap)[0]] || null, visualizationState: null, visualizeTriggerFieldContext: initialContext, }); diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index a4a483fa95d37..cf6634c200d55 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -234,7 +234,11 @@ export interface Datasource { toExpression: (state: T, layerId: string) => ExpressionAstExpression | string | null; - getDatasourceSuggestionsForField: (state: T, field: unknown) => Array>; + getDatasourceSuggestionsForField: ( + state: T, + field: unknown, + filterFn: (layerId: string) => boolean + ) => Array>; getDatasourceSuggestionsForVisualizeField: ( state: T, indexPatternId: string, @@ -326,6 +330,8 @@ export type DatasourceDimensionProps = SharedDimensionProps & { onRemove?: (accessor: string) => void; state: T; activeData?: Record; + invalid?: boolean; + invalidMessage?: string; }; // The only way a visualization has to restrict the query building @@ -335,6 +341,7 @@ export type DatasourceDimensionEditorProps = DatasourceDimensionPro newState: Parameters>[0], publishToVisualization?: { isDimensionComplete?: boolean; + forceRender?: boolean; } ) => void; core: Pick; @@ -343,6 +350,8 @@ export type DatasourceDimensionEditorProps = DatasourceDimensionPro toggleFullscreen: () => void; isFullscreen: boolean; layerType: LayerType | undefined; + supportStaticValue: boolean; + supportFieldFormat?: boolean; }; export type DatasourceDimensionTriggerProps = DatasourceDimensionProps; @@ -434,7 +443,7 @@ export interface VisualizationToolbarProps { export type VisualizationDimensionEditorProps = VisualizationConfigProps & { groupId: string; accessor: string; - setState: (newState: T) => void; + setState(newState: T | ((currState: T) => T)): void; panelRef: MutableRefObject; }; @@ -466,13 +475,16 @@ export type VisualizationDimensionGroupConfig = SharedDimensionProps & { // this dimension group in the hierarchy. If not specified, the position of the dimension in the array is used. specified nesting // orders are always higher in the hierarchy than non-specified ones. nestingOrder?: number; + // some type of layers can produce groups even if invalid. Keep this information to visually show the user that. + invalid?: boolean; + invalidMessage?: string; }; interface VisualizationDimensionChangeProps { layerId: string; columnId: string; prevState: T; - frame: Pick; + frame: Pick; } /** @@ -655,6 +667,7 @@ export interface Visualization { getConfiguration: (props: VisualizationConfigProps) => { groups: VisualizationDimensionGroupConfig[]; supportStaticValue?: boolean; + supportFieldFormat?: boolean; }; /** diff --git a/x-pack/plugins/lens/public/xy_visualization/axes_configuration.ts b/x-pack/plugins/lens/public/xy_visualization/axes_configuration.ts index 95c9140624e63..9c83e2c58146e 100644 --- a/x-pack/plugins/lens/public/xy_visualization/axes_configuration.ts +++ b/x-pack/plugins/lens/public/xy_visualization/axes_configuration.ts @@ -30,16 +30,17 @@ export function isFormatterCompatible( return formatter1.id === formatter2.id; } -export function getAxesConfiguration( - layers: XYLayerConfig[], - shouldRotate: boolean, - tables?: Record, - formatFactory?: FormatFactory -): GroupsConfiguration { - const series: { auto: FormattedMetric[]; left: FormattedMetric[]; right: FormattedMetric[] } = { +export function groupAxesByType(layers: XYLayerConfig[], tables?: Record) { + const series: { + auto: FormattedMetric[]; + left: FormattedMetric[]; + right: FormattedMetric[]; + bottom: FormattedMetric[]; + } = { auto: [], left: [], right: [], + bottom: [], }; layers?.forEach((layer) => { @@ -89,6 +90,16 @@ export function getAxesConfiguration( series.right.push(currentSeries); } }); + return series; +} + +export function getAxesConfiguration( + layers: XYLayerConfig[], + shouldRotate: boolean, + tables?: Record, + formatFactory?: FormatFactory +): GroupsConfiguration { + const series = groupAxesByType(layers, tables); const axisGroups: GroupsConfiguration = []; diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 026d9da71beea..863289c31bba4 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -59,6 +59,7 @@ import { getAxesConfiguration, GroupsConfiguration, validateExtent } from './axe import { getColorAssignments } from './color_assignment'; import { getXDomain, XyEndzones } from './x_domain'; import { getLegendAction } from './get_legend_action'; +import { ThresholdAnnotations } from './expression_thresholds'; declare global { interface Window { @@ -251,6 +252,7 @@ export function XYChart({ const icon: IconType = layers.length > 0 ? getIconForSeriesType(layers[0].seriesType) : 'bar'; return ; } + const thresholdLayers = layers.filter((layer) => layer.layerType === layerTypes.THRESHOLD); // use formatting hint of first x axis column to format ticks const xAxisColumn = data.tables[filteredLayers[0].layerId].columns.find( @@ -832,6 +834,20 @@ export function XYChart({ } }) )} + {thresholdLayers.length ? ( + groupId === 'left')?.formatter, + right: yAxesConfiguration.find(({ groupId }) => groupId === 'right')?.formatter, + bottom: xAxisFormatter, + }} + /> + ) : null} ); } diff --git a/x-pack/plugins/lens/public/xy_visualization/expression_thresholds.tsx b/x-pack/plugins/lens/public/xy_visualization/expression_thresholds.tsx new file mode 100644 index 0000000000000..171e2f1cfba9e --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/expression_thresholds.tsx @@ -0,0 +1,193 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { groupBy } from 'lodash'; +import { EuiIcon } from '@elastic/eui'; +import { RectAnnotation, AnnotationDomainType, LineAnnotation } from '@elastic/charts'; +import type { PaletteRegistry, SeriesLayer } from 'src/plugins/charts/public'; +import type { FieldFormat } from 'src/plugins/field_formats/common'; +import type { LayerArgs } from '../../common/expressions'; +import type { LensMultiTable } from '../../common/types'; +import type { ColorAssignments } from './color_assignment'; + +export const ThresholdAnnotations = ({ + thresholdLayers, + data, + colorAssignments, + formatters, + paletteService, + syncColors, +}: { + thresholdLayers: LayerArgs[]; + data: LensMultiTable; + colorAssignments: ColorAssignments; + formatters: Record<'left' | 'right' | 'bottom', FieldFormat | undefined>; + paletteService: PaletteRegistry; + syncColors: boolean; +}) => { + return ( + <> + {thresholdLayers.flatMap((thresholdLayer) => { + if (!thresholdLayer.yConfig) { + return []; + } + const { columnToLabel, palette, yConfig: yConfigs, layerId } = thresholdLayer; + const columnToLabelMap: Record = columnToLabel + ? JSON.parse(columnToLabel) + : {}; + const table = data.tables[layerId]; + const colorAssignment = colorAssignments[palette.name]; + + const row = table.rows[0]; + + const yConfigByValue = yConfigs.sort( + ({ forAccessor: idA }, { forAccessor: idB }) => row[idA] - row[idB] + ); + + const groupedByDirection = groupBy(yConfigByValue, 'fill'); + + return yConfigByValue.flatMap((yConfig, i) => { + // Find the formatter for the given axis + const groupId = + yConfig.axisMode === 'bottom' + ? undefined + : yConfig.axisMode === 'right' + ? 'right' + : 'left'; + + const formatter = formatters[groupId || 'bottom']; + + const seriesLayers: SeriesLayer[] = [ + { + name: columnToLabelMap[yConfig.forAccessor], + totalSeriesAtDepth: colorAssignment.totalSeriesCount, + rankAtDepth: colorAssignment.getRank( + thresholdLayer, + String(yConfig.forAccessor), + String(yConfig.forAccessor) + ), + }, + ]; + const defaultColor = paletteService.get(palette.name).getCategoricalColor( + seriesLayers, + { + maxDepth: 1, + behindText: false, + totalSeries: colorAssignment.totalSeriesCount, + syncColors, + }, + palette.params + ); + + const props = { + groupId, + marker: yConfig.icon ? : undefined, + }; + const annotations = []; + + const dashStyle = + yConfig.lineStyle === 'dashed' + ? [(yConfig.lineWidth || 1) * 3, yConfig.lineWidth || 1] + : yConfig.lineStyle === 'dotted' + ? [yConfig.lineWidth || 1, yConfig.lineWidth || 1] + : undefined; + + const sharedStyle = { + strokeWidth: yConfig.lineWidth || 1, + stroke: (yConfig.color || defaultColor) ?? '#f00', + dash: dashStyle, + }; + + annotations.push( + ({ + dataValue: row[yConfig.forAccessor], + header: columnToLabelMap[yConfig.forAccessor], + details: formatter?.convert(row[yConfig.forAccessor]) || row[yConfig.forAccessor], + }))} + domainType={ + yConfig.axisMode === 'bottom' + ? AnnotationDomainType.XDomain + : AnnotationDomainType.YDomain + } + style={{ + line: { + ...sharedStyle, + opacity: 1, + }, + }} + /> + ); + + if (yConfig.fill && yConfig.fill !== 'none') { + const isFillAbove = yConfig.fill === 'above'; + const indexFromSameType = groupedByDirection[yConfig.fill].findIndex( + ({ forAccessor }) => forAccessor === yConfig.forAccessor + ); + const shouldCheckNextThreshold = + indexFromSameType < groupedByDirection[yConfig.fill].length - 1; + annotations.push( + { + if (yConfig.axisMode === 'bottom') { + return { + coordinates: { + x0: isFillAbove ? row[yConfig.forAccessor] : undefined, + y0: undefined, + x1: isFillAbove + ? shouldCheckNextThreshold + ? row[ + groupedByDirection[yConfig.fill!][indexFromSameType + 1].forAccessor + ] + : undefined + : row[yConfig.forAccessor], + y1: undefined, + }, + header: columnToLabelMap[yConfig.forAccessor], + details: + formatter?.convert(row[yConfig.forAccessor]) || row[yConfig.forAccessor], + }; + } + return { + coordinates: { + x0: undefined, + y0: isFillAbove ? row[yConfig.forAccessor] : undefined, + x1: undefined, + y1: isFillAbove + ? shouldCheckNextThreshold + ? row[ + groupedByDirection[yConfig.fill!][indexFromSameType + 1].forAccessor + ] + : undefined + : row[yConfig.forAccessor], + }, + header: columnToLabelMap[yConfig.forAccessor], + details: + formatter?.convert(row[yConfig.forAccessor]) || row[yConfig.forAccessor], + }; + })} + style={{ + ...sharedStyle, + fill: (yConfig.color || defaultColor) ?? '#f00', + opacity: 0.1, + }} + /> + ); + } + return annotations; + }); + })} + + ); +}; diff --git a/x-pack/plugins/lens/public/xy_visualization/state_helpers.ts b/x-pack/plugins/lens/public/xy_visualization/state_helpers.ts index e3b16f5981f88..4edf7fdf5e512 100644 --- a/x-pack/plugins/lens/public/xy_visualization/state_helpers.ts +++ b/x-pack/plugins/lens/public/xy_visualization/state_helpers.ts @@ -18,6 +18,14 @@ export function isHorizontalSeries(seriesType: SeriesType) { ); } +export function isPercentageSeries(seriesType: SeriesType) { + return ( + seriesType === 'bar_percentage_stacked' || + seriesType === 'bar_horizontal_percentage_stacked' || + seriesType === 'area_percentage_stacked' + ); +} + export function isHorizontalChart(layers: Array<{ seriesType: SeriesType }>) { return layers.every((l) => isHorizontalSeries(l.seriesType)); } diff --git a/x-pack/plugins/lens/public/xy_visualization/threshold_helpers.tsx b/x-pack/plugins/lens/public/xy_visualization/threshold_helpers.tsx new file mode 100644 index 0000000000000..ec47350709473 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/threshold_helpers.tsx @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { layerTypes } from '../../common'; +import type { XYLayerConfig, YConfig } from '../../common/expressions'; +import { Datatable } from '../../../../../src/plugins/expressions/public'; +import type { DatasourcePublicAPI, FramePublicAPI } from '../types'; +import { groupAxesByType } from './axes_configuration'; +import { isPercentageSeries } from './state_helpers'; +import type { XYState } from './types'; +import { checkScaleOperation } from './visualization_helpers'; + +export interface ThresholdBase { + label: 'x' | 'yRight' | 'yLeft'; +} + +/** + * Return the threshold layers groups to show based on multiple criteria: + * * what groups are current defined in data layers + * * what existing threshold are currently defined in data thresholds + */ +export function getGroupsToShow( + thresholdLayers: T[], + state: XYState | undefined, + datasourceLayers: Record, + tables: Record | undefined +): Array { + if (!state) { + return []; + } + const dataLayers = state.layers.filter( + ({ layerType = layerTypes.DATA }) => layerType === layerTypes.DATA + ); + const groupsAvailable = getGroupsAvailableInData(dataLayers, datasourceLayers, tables); + return thresholdLayers + .filter(({ label, config }: T) => groupsAvailable[label] || config?.length) + .map((layer) => ({ ...layer, valid: groupsAvailable[layer.label] })); +} + +/** + * Returns the threshold layers groups to show based on what groups are current defined in data layers. + */ +export function getGroupsRelatedToData( + thresholdLayers: T[], + state: XYState | undefined, + datasourceLayers: Record, + tables: Record | undefined +): T[] { + if (!state) { + return []; + } + const dataLayers = state.layers.filter( + ({ layerType = layerTypes.DATA }) => layerType === layerTypes.DATA + ); + const groupsAvailable = getGroupsAvailableInData(dataLayers, datasourceLayers, tables); + return thresholdLayers.filter(({ label }: T) => groupsAvailable[label]); +} +/** + * Returns a dictionary with the groups filled in all the data layers + */ +export function getGroupsAvailableInData( + dataLayers: XYState['layers'], + datasourceLayers: Record, + tables: Record | undefined +) { + const hasNumberHistogram = dataLayers.some( + checkScaleOperation('interval', 'number', datasourceLayers) + ); + const { right, left } = groupAxesByType(dataLayers, tables); + return { + x: dataLayers.some(({ xAccessor }) => xAccessor != null) && hasNumberHistogram, + yLeft: left.length > 0, + yRight: right.length > 0, + }; +} + +export function getStaticValue( + dataLayers: XYState['layers'], + groupId: 'x' | 'yLeft' | 'yRight', + { activeData }: Pick, + layerHasNumberHistogram: (layer: XYLayerConfig) => boolean +) { + const fallbackValue = 100; + if (!activeData) { + return fallbackValue; + } + + // filter and organize data dimensions into threshold groups + // now pick the columnId in the active data + const { dataLayer, accessor } = getAccessorCriteriaForGroup(groupId, dataLayers, activeData); + if (groupId === 'x' && dataLayer && !layerHasNumberHistogram(dataLayer)) { + return fallbackValue; + } + return ( + computeStaticValueForGroup( + dataLayer, + accessor, + activeData, + groupId !== 'x' // histogram axis should compute the min based on the current data + ) || fallbackValue + ); +} + +function getAccessorCriteriaForGroup( + groupId: 'x' | 'yLeft' | 'yRight', + dataLayers: XYState['layers'], + activeData: FramePublicAPI['activeData'] +) { + switch (groupId) { + case 'x': + const dataLayer = dataLayers.find(({ xAccessor }) => xAccessor); + return { + dataLayer, + accessor: dataLayer?.xAccessor, + }; + case 'yLeft': + const { left } = groupAxesByType(dataLayers, activeData); + return { + dataLayer: dataLayers.find(({ layerId }) => layerId === left[0]?.layer), + accessor: left[0]?.accessor, + }; + case 'yRight': + const { right } = groupAxesByType(dataLayers, activeData); + return { + dataLayer: dataLayers.find(({ layerId }) => layerId === right[0]?.layer), + accessor: right[0]?.accessor, + }; + } +} + +function computeStaticValueForGroup( + dataLayer: XYLayerConfig | undefined, + accessorId: string | undefined, + activeData: NonNullable, + minZeroBased: boolean +) { + const defaultThresholdFactor = 3 / 4; + + if (dataLayer && accessorId) { + if (isPercentageSeries(dataLayer?.seriesType)) { + return defaultThresholdFactor; + } + const tableId = Object.keys(activeData).find((key) => + activeData[key].columns.some(({ id }) => id === accessorId) + ); + if (tableId) { + const columnMax = activeData[tableId].rows.reduce( + (max, row) => Math.max(row[accessorId], max), + -Infinity + ); + const columnMin = activeData[tableId].rows.reduce( + (max, row) => Math.min(row[accessorId], max), + Infinity + ); + // Custom axis bounds can go below 0, so consider also lower values than 0 + const finalMinValue = minZeroBased ? Math.min(0, columnMin) : columnMin; + const interval = columnMax - finalMinValue; + return Number((finalMinValue + interval * defaultThresholdFactor).toFixed(2)); + } + } +} diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts index 5290e0298ae5e..aa99aa9b7b316 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts @@ -322,6 +322,10 @@ export const buildExpression = ( forAccessor: [yConfig.forAccessor], axisMode: yConfig.axisMode ? [yConfig.axisMode] : [], color: yConfig.color ? [yConfig.color] : [], + lineStyle: yConfig.lineStyle ? [yConfig.lineStyle] : [], + lineWidth: yConfig.lineWidth ? [yConfig.lineWidth] : [], + fill: [yConfig.fill || 'none'], + icon: yConfig.icon ? [yConfig.icon] : [], }, }, ], diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index 7aef40b1481dc..8907db4954f99 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -15,6 +15,7 @@ import { createMockDatasource, createMockFramePublicAPI } from '../mocks'; import { LensIconChartBar } from '../assets/chart_bar'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; +import { Datatable } from 'src/plugins/expressions'; function exampleState(): State { return { @@ -216,8 +217,8 @@ describe('xy_visualization', () => { }); describe('#getSupportedLayers', () => { - it('should return a single layer type', () => { - expect(xyVisualization.getSupportedLayers()).toHaveLength(1); + it('should return a double layer types', () => { + expect(xyVisualization.getSupportedLayers()).toHaveLength(2); }); it('should return the icon for the visualization type', () => { @@ -317,6 +318,42 @@ describe('xy_visualization', () => { accessors: [], }); }); + + it('should add a dimension to a threshold layer', () => { + expect( + xyVisualization.setDimension({ + frame, + prevState: { + ...exampleState(), + layers: [ + { + layerId: 'threshold', + layerType: layerTypes.THRESHOLD, + seriesType: 'line', + accessors: [], + }, + ], + }, + layerId: 'threshold', + groupId: 'xThreshold', + columnId: 'newCol', + }).layers[0] + ).toEqual({ + layerId: 'threshold', + layerType: layerTypes.THRESHOLD, + seriesType: 'line', + accessors: ['newCol'], + yConfig: [ + { + axisMode: 'bottom', + forAccessor: 'newCol', + icon: undefined, + lineStyle: 'solid', + lineWidth: 1, + }, + ], + }); + }); }); describe('#removeDimension', () => { @@ -504,6 +541,300 @@ describe('xy_visualization', () => { expect(ops.filter(filterOperations).map((x) => x.dataType)).toEqual(['number']); }); + describe('thresholds', () => { + beforeEach(() => { + frame.datasourceLayers = { + first: mockDatasource.publicAPIMock, + threshold: mockDatasource.publicAPIMock, + }; + }); + + function getStateWithBaseThreshold(): State { + return { + ...exampleState(), + layers: [ + { + layerId: 'first', + layerType: layerTypes.DATA, + seriesType: 'area', + splitAccessor: undefined, + xAccessor: undefined, + accessors: ['a'], + }, + { + layerId: 'threshold', + layerType: layerTypes.THRESHOLD, + seriesType: 'line', + accessors: [], + yConfig: [{ axisMode: 'left', forAccessor: 'a' }], + }, + ], + }; + } + + it('should support static value', () => { + const state = getStateWithBaseThreshold(); + state.layers[0].accessors = []; + state.layers[1].yConfig = undefined; + + expect( + xyVisualization.getConfiguration({ + state: getStateWithBaseThreshold(), + frame, + layerId: 'threshold', + }).supportStaticValue + ).toBeTruthy(); + }); + + it('should return no threshold groups for a empty data layer', () => { + const state = getStateWithBaseThreshold(); + state.layers[0].accessors = []; + state.layers[1].yConfig = undefined; + + const options = xyVisualization.getConfiguration({ + state, + frame, + layerId: 'threshold', + }).groups; + + expect(options).toHaveLength(0); + }); + + it('should return a group for the vertical left axis', () => { + const options = xyVisualization.getConfiguration({ + state: getStateWithBaseThreshold(), + frame, + layerId: 'threshold', + }).groups; + + expect(options).toHaveLength(1); + expect(options[0].groupId).toBe('yThresholdLeft'); + }); + + it('should return a group for the vertical right axis', () => { + const state = getStateWithBaseThreshold(); + state.layers[0].yConfig = [{ axisMode: 'right', forAccessor: 'a' }]; + state.layers[1].yConfig![0].axisMode = 'right'; + + const options = xyVisualization.getConfiguration({ + state, + frame, + layerId: 'threshold', + }).groups; + + expect(options).toHaveLength(1); + expect(options[0].groupId).toBe('yThresholdRight'); + }); + + it('should compute no groups for thresholds when the only data accessor available is a date histogram', () => { + const state = getStateWithBaseThreshold(); + state.layers[0].xAccessor = 'b'; + state.layers[0].accessors = []; + state.layers[1].yConfig = []; // empty the configuration + // set the xAccessor as date_histogram + frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + if (accessor === 'b') { + return { + dataType: 'date', + isBucketed: true, + scale: 'interval', + label: 'date_histogram', + }; + } + return null; + }); + + const options = xyVisualization.getConfiguration({ + state, + frame, + layerId: 'threshold', + }).groups; + + expect(options).toHaveLength(0); + }); + + it('should mark horizontal group is invalid when xAccessor is changed to a date histogram', () => { + const state = getStateWithBaseThreshold(); + state.layers[0].xAccessor = 'b'; + state.layers[0].accessors = []; + state.layers[1].yConfig![0].axisMode = 'bottom'; + // set the xAccessor as date_histogram + frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + if (accessor === 'b') { + return { + dataType: 'date', + isBucketed: true, + scale: 'interval', + label: 'date_histogram', + }; + } + return null; + }); + + const options = xyVisualization.getConfiguration({ + state, + frame, + layerId: 'threshold', + }).groups; + + expect(options[0]).toEqual( + expect.objectContaining({ + invalid: true, + groupId: 'xThreshold', + }) + ); + }); + + it('should return groups in a specific order (left, right, bottom)', () => { + const state = getStateWithBaseThreshold(); + state.layers[0].xAccessor = 'c'; + state.layers[0].accessors = ['a', 'b']; + // invert them on purpose + state.layers[0].yConfig = [ + { axisMode: 'right', forAccessor: 'b' }, + { axisMode: 'left', forAccessor: 'a' }, + ]; + state.layers[1].yConfig = [ + { forAccessor: 'c', axisMode: 'bottom' }, + { forAccessor: 'b', axisMode: 'right' }, + { forAccessor: 'a', axisMode: 'left' }, + ]; + // set the xAccessor as number histogram + frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + if (accessor === 'c') { + return { + dataType: 'number', + isBucketed: true, + scale: 'interval', + label: 'histogram', + }; + } + return null; + }); + + const [left, right, bottom] = xyVisualization.getConfiguration({ + state, + frame, + layerId: 'threshold', + }).groups; + + expect(left.groupId).toBe('yThresholdLeft'); + expect(right.groupId).toBe('yThresholdRight'); + expect(bottom.groupId).toBe('xThreshold'); + }); + + it('should ignore terms operation for xAccessor', () => { + const state = getStateWithBaseThreshold(); + state.layers[0].xAccessor = 'b'; + state.layers[0].accessors = []; + state.layers[1].yConfig = []; // empty the configuration + // set the xAccessor as top values + frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + if (accessor === 'b') { + return { + dataType: 'string', + isBucketed: true, + scale: 'ordinal', + label: 'top values', + }; + } + return null; + }); + + const options = xyVisualization.getConfiguration({ + state, + frame, + layerId: 'threshold', + }).groups; + + expect(options).toHaveLength(0); + }); + + it('should mark horizontal group is invalid when accessor is changed to a terms operation', () => { + const state = getStateWithBaseThreshold(); + state.layers[0].xAccessor = 'b'; + state.layers[0].accessors = []; + state.layers[1].yConfig![0].axisMode = 'bottom'; + // set the xAccessor as date_histogram + frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + if (accessor === 'b') { + return { + dataType: 'string', + isBucketed: true, + scale: 'ordinal', + label: 'top values', + }; + } + return null; + }); + + const options = xyVisualization.getConfiguration({ + state, + frame, + layerId: 'threshold', + }).groups; + + expect(options[0]).toEqual( + expect.objectContaining({ + invalid: true, + groupId: 'xThreshold', + }) + ); + }); + + it('differ vertical axis if the formatters are not compatibles between each other', () => { + const tables: Record = { + first: { + type: 'datatable', + rows: [], + columns: [ + { + id: 'xAccessorId', + name: 'horizontal axis', + meta: { + type: 'date', + params: { params: { id: 'date', params: { pattern: 'HH:mm' } } }, + }, + }, + { + id: 'yAccessorId', + name: 'left axis', + meta: { + type: 'number', + params: { id: 'number' }, + }, + }, + { + id: 'yAccessorId2', + name: 'right axis', + meta: { + type: 'number', + params: { id: 'bytes' }, + }, + }, + ], + }, + }; + + const state = getStateWithBaseThreshold(); + state.layers[0].accessors = ['yAccessorId', 'yAccessorId2']; + state.layers[1].yConfig = []; // empty the configuration + + const options = xyVisualization.getConfiguration({ + state, + frame: { ...frame, activeData: tables }, + layerId: 'threshold', + }).groups; + + expect(options).toEqual( + expect.arrayContaining([ + expect.objectContaining({ groupId: 'yThresholdLeft' }), + expect.objectContaining({ groupId: 'yThresholdRight' }), + ]) + ); + }); + }); + describe('color assignment', () => { function callConfig(layerConfigOverride: Partial) { const baseState = exampleState(); diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index 026c2827cedbd..ed1cc015806c5 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { uniq } from 'lodash'; +import { groupBy, uniq } from 'lodash'; import { render } from 'react-dom'; import { Position } from '@elastic/charts'; import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; @@ -14,15 +14,10 @@ import { i18n } from '@kbn/i18n'; import { PaletteRegistry } from 'src/plugins/charts/public'; import { FieldFormatsStart } from 'src/plugins/field_formats/public'; import { getSuggestions } from './xy_suggestions'; -import { XyToolbar, DimensionEditor, LayerHeader } from './xy_config_panel'; -import type { - Visualization, - OperationMetadata, - VisualizationType, - AccessorConfig, - DatasourcePublicAPI, -} from '../types'; -import { State, visualizationTypes, XYState } from './types'; +import { XyToolbar, DimensionEditor } from './xy_config_panel'; +import { LayerHeader } from './xy_config_panel/layer_header'; +import type { Visualization, OperationMetadata, VisualizationType, AccessorConfig } from '../types'; +import { State, visualizationTypes } from './types'; import { SeriesType, XYLayerConfig } from '../../common/expressions'; import { LayerType, layerTypes } from '../../common'; import { isHorizontalChart } from './state_helpers'; @@ -32,6 +27,19 @@ import { LensIconChartMixedXy } from '../assets/chart_mixed_xy'; import { LensIconChartBarHorizontal } from '../assets/chart_bar_horizontal'; import { getAccessorColorConfig, getColorAssignments } from './color_assignment'; import { getColumnToLabelMap } from './state_helpers'; +import { LensIconChartBarThreshold } from '../assets/chart_bar_threshold'; +import { generateId } from '../id_generator'; +import { + getGroupsAvailableInData, + getGroupsRelatedToData, + getGroupsToShow, + getStaticValue, +} from './threshold_helpers'; +import { + checkScaleOperation, + checkXAccessorCompatibility, + getAxisName, +} from './visualization_helpers'; const defaultIcon = LensIconChartBarStacked; const defaultSeriesType = 'bar_stacked'; @@ -186,6 +194,39 @@ export const getXyVisualization = ({ }, getSupportedLayers(state, frame) { + const thresholdGroupIds = [ + { + id: 'yThresholdLeft', + label: 'yLeft' as const, + }, + { + id: 'yThresholdRight', + label: 'yRight' as const, + }, + { + id: 'xThreshold', + label: 'x' as const, + }, + ]; + + const dataLayers = + state?.layers.filter(({ layerType = layerTypes.DATA }) => layerType === layerTypes.DATA) || + []; + const filledDataLayers = dataLayers.filter( + ({ accessors, xAccessor }) => accessors.length || xAccessor + ); + const layerHasNumberHistogram = checkScaleOperation( + 'interval', + 'number', + frame?.datasourceLayers || {} + ); + const thresholdGroups = getGroupsRelatedToData( + thresholdGroupIds, + state, + frame?.datasourceLayers || {}, + frame?.activeData + ); + const layers = [ { type: layerTypes.DATA, @@ -194,6 +235,36 @@ export const getXyVisualization = ({ }), icon: LensIconChartMixedXy, }, + { + type: layerTypes.THRESHOLD, + label: i18n.translate('xpack.lens.xyChart.addThresholdLayerLabel', { + defaultMessage: 'Add threshold layer', + }), + icon: LensIconChartBarThreshold, + disabled: + !filledDataLayers.length || + (!dataLayers.some(layerHasNumberHistogram) && + dataLayers.every(({ accessors }) => !accessors.length)), + tooltipContent: filledDataLayers.length + ? undefined + : i18n.translate('xpack.lens.xyChart.addThresholdLayerLabelDisabledHelp', { + defaultMessage: 'Add some data to enable threshold layer', + }), + initialDimensions: state + ? thresholdGroups.map(({ id, label }) => ({ + groupId: id, + columnId: generateId(), + dataType: 'number', + label: getAxisName(label, { isHorizontal: isHorizontalChart(state?.layers || []) }), + staticValue: getStaticValue( + dataLayers, + label, + { activeData: frame?.activeData }, + layerHasNumberHistogram + ), + })) + : undefined, + }, ]; return layers; @@ -233,8 +304,70 @@ export const getXyVisualization = ({ const isDataLayer = !layer.layerType || layer.layerType === layerTypes.DATA; if (!isDataLayer) { + const idToIndex = sortedAccessors.reduce>((memo, id, index) => { + memo[id] = index; + return memo; + }, {}); + const { bottom, left, right } = groupBy( + [...(layer.yConfig || [])].sort( + ({ forAccessor: forA }, { forAccessor: forB }) => idToIndex[forA] - idToIndex[forB] + ), + ({ axisMode }) => { + return axisMode; + } + ); + const groupsToShow = getGroupsToShow( + [ + // When a threshold layer panel is added, a static threshold should automatically be included by default + // in the first available axis, in the following order: vertical left, vertical right, horizontal. + { + config: left, + id: 'yThresholdLeft', + label: 'yLeft', + dataTestSubj: 'lnsXY_yThresholdLeftPanel', + }, + { + config: right, + id: 'yThresholdRight', + label: 'yRight', + dataTestSubj: 'lnsXY_yThresholdRightPanel', + }, + { + config: bottom, + id: 'xThreshold', + label: 'x', + dataTestSubj: 'lnsXY_xThresholdPanel', + }, + ], + state, + frame.datasourceLayers, + frame?.activeData + ); return { - groups: [], + supportFieldFormat: false, + supportStaticValue: true, + // Each thresholds layer panel will have sections for each available axis + // (horizontal axis, vertical axis left, vertical axis right). + // Only axes that support numeric thresholds should be shown + groups: groupsToShow.map(({ config = [], id, label, dataTestSubj, valid }) => ({ + groupId: id, + groupLabel: getAxisName(label, { isHorizontal }), + accessors: config.map(({ forAccessor, color }) => ({ + columnId: forAccessor, + color: color || mappedAccessors.find(({ columnId }) => columnId === forAccessor)?.color, + triggerIcon: 'color', + })), + filterOperations: isNumericMetric, + supportsMoreColumns: true, + required: false, + enableDimensionEditor: true, + dataTestSubj, + invalid: !valid, + invalidMessage: i18n.translate('xpack.lens.configure.invalidThresholdDimension', { + defaultMessage: + 'This threshold is assigned to an axis that no longer exists. You may move this threshold to another available axis or remove it.', + }), + })), }; } @@ -305,6 +438,30 @@ export const getXyVisualization = ({ newLayer.splitAccessor = columnId; } + if (newLayer.layerType === layerTypes.THRESHOLD) { + newLayer.accessors = [...newLayer.accessors.filter((a) => a !== columnId), columnId]; + const hasYConfig = newLayer.yConfig?.some(({ forAccessor }) => forAccessor === columnId); + if (!hasYConfig) { + newLayer.yConfig = [ + ...(newLayer.yConfig || []), + // TODO: move this + // add a default config if none is available + { + forAccessor: columnId, + axisMode: + groupId === 'xThreshold' + ? 'bottom' + : groupId === 'yThresholdRight' + ? 'right' + : 'left', + icon: undefined, + lineStyle: 'solid', + lineWidth: 1, + }, + ]; + } + } + return { ...prevState, layers: prevState.layers.map((l) => (l.layerId === layerId ? newLayer : l)), @@ -331,7 +488,24 @@ export const getXyVisualization = ({ newLayer.yConfig = newLayer.yConfig.filter(({ forAccessor }) => forAccessor !== columnId); } - const newLayers = prevState.layers.map((l) => (l.layerId === layerId ? newLayer : l)); + let newLayers = prevState.layers.map((l) => (l.layerId === layerId ? newLayer : l)); + // // check if there's any threshold layer and pull it off if all data layers have no dimensions set + const layersByType = groupBy(newLayers, ({ layerType }) => layerType); + // // check for data layers if they all still have xAccessors + const groupsAvailable = getGroupsAvailableInData( + layersByType[layerTypes.DATA], + frame.datasourceLayers, + frame?.activeData + ); + if ( + (Object.keys(groupsAvailable) as Array<'x' | 'yLeft' | 'yRight'>).every( + (id) => !groupsAvailable[id] + ) + ) { + newLayers = newLayers.filter( + ({ layerType, accessors }) => layerType === layerTypes.DATA || accessors.length + ); + } return { ...prevState, @@ -510,19 +684,6 @@ function validateLayersForDimension( }; } -function getAxisName(axis: 'x' | 'y', { isHorizontal }: { isHorizontal: boolean }) { - const vertical = i18n.translate('xpack.lens.xyChart.verticalAxisLabel', { - defaultMessage: 'Vertical axis', - }); - const horizontal = i18n.translate('xpack.lens.xyChart.horizontalAxisLabel', { - defaultMessage: 'Horizontal axis', - }); - if (axis === 'x') { - return isHorizontal ? vertical : horizontal; - } - return isHorizontal ? horizontal : vertical; -} - // i18n ids cannot be dynamically generated, hence the function below function getMessageIdsForDimension(dimension: string, layers: number[], isHorizontal: boolean) { const layersList = layers.map((i: number) => i + 1).join(', '); @@ -566,76 +727,6 @@ function newLayerState( }; } -// min requirement for the bug: -// * 2 or more layers -// * at least one with date histogram -// * at least one with interval function -function checkXAccessorCompatibility( - state: XYState, - datasourceLayers: Record -) { - const errors = []; - const hasDateHistogramSet = state.layers.some( - checkScaleOperation('interval', 'date', datasourceLayers) - ); - const hasNumberHistogram = state.layers.some( - checkScaleOperation('interval', 'number', datasourceLayers) - ); - const hasOrdinalAxis = state.layers.some( - checkScaleOperation('ordinal', undefined, datasourceLayers) - ); - if (state.layers.length > 1 && hasDateHistogramSet && hasNumberHistogram) { - errors.push({ - shortMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXShort', { - defaultMessage: `Wrong data type for {axis}.`, - values: { - axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), - }, - }), - longMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXLong', { - defaultMessage: `Data type mismatch for the {axis}. Cannot mix date and number interval types.`, - values: { - axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), - }, - }), - }); - } - if (state.layers.length > 1 && (hasDateHistogramSet || hasNumberHistogram) && hasOrdinalAxis) { - errors.push({ - shortMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXShort', { - defaultMessage: `Wrong data type for {axis}.`, - values: { - axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), - }, - }), - longMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXOrdinalLong', { - defaultMessage: `Data type mismatch for the {axis}, use a different function.`, - values: { - axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), - }, - }), - }); - } - return errors; -} - -function checkScaleOperation( - scaleType: 'ordinal' | 'interval' | 'ratio', - dataType: 'date' | 'number' | 'string' | undefined, - datasourceLayers: Record -) { - return (layer: XYLayerConfig) => { - const datasourceAPI = datasourceLayers[layer.layerId]; - if (!layer.xAccessor) { - return false; - } - const operation = datasourceAPI?.getOperationForColumnId(layer.xAccessor); - return Boolean( - operation && (!dataType || operation.dataType === dataType) && operation.scale === scaleType - ); - }; -} - function getLayersByType(state: State, byType?: string) { return state.layers.filter(({ layerType = layerTypes.DATA }) => byType ? layerType === byType : true diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization_helpers.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization_helpers.tsx new file mode 100644 index 0000000000000..22c3c7e895323 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/visualization_helpers.tsx @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { DatasourcePublicAPI } from '../types'; +import { XYState } from './types'; +import { isHorizontalChart } from './state_helpers'; +import { XYLayerConfig } from '../../common/expressions'; + +export function getAxisName( + axis: 'x' | 'y' | 'yLeft' | 'yRight', + { isHorizontal }: { isHorizontal: boolean } +) { + const vertical = i18n.translate('xpack.lens.xyChart.verticalAxisLabel', { + defaultMessage: 'Vertical axis', + }); + const horizontal = i18n.translate('xpack.lens.xyChart.horizontalAxisLabel', { + defaultMessage: 'Horizontal axis', + }); + if (axis === 'x') { + return isHorizontal ? vertical : horizontal; + } + if (axis === 'y') { + return isHorizontal ? horizontal : vertical; + } + const verticalLeft = i18n.translate('xpack.lens.xyChart.verticalLeftAxisLabel', { + defaultMessage: 'Vertical left axis', + }); + const verticalRight = i18n.translate('xpack.lens.xyChart.verticalRightAxisLabel', { + defaultMessage: 'Vertical right axis', + }); + const horizontalTop = i18n.translate('xpack.lens.xyChart.horizontalLeftAxisLabel', { + defaultMessage: 'Horizontal top axis', + }); + const horizontalBottom = i18n.translate('xpack.lens.xyChart.horizontalRightAxisLabel', { + defaultMessage: 'Horizontal bottom axis', + }); + if (axis === 'yLeft') { + return isHorizontal ? horizontalTop : verticalLeft; + } + return isHorizontal ? horizontalBottom : verticalRight; +} + +// min requirement for the bug: +// * 2 or more layers +// * at least one with date histogram +// * at least one with interval function +export function checkXAccessorCompatibility( + state: XYState, + datasourceLayers: Record +) { + const errors = []; + const hasDateHistogramSet = state.layers.some( + checkScaleOperation('interval', 'date', datasourceLayers) + ); + const hasNumberHistogram = state.layers.some( + checkScaleOperation('interval', 'number', datasourceLayers) + ); + const hasOrdinalAxis = state.layers.some( + checkScaleOperation('ordinal', undefined, datasourceLayers) + ); + if (state.layers.length > 1 && hasDateHistogramSet && hasNumberHistogram) { + errors.push({ + shortMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXShort', { + defaultMessage: `Wrong data type for {axis}.`, + values: { + axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), + }, + }), + longMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXLong', { + defaultMessage: `Data type mismatch for the {axis}. Cannot mix date and number interval types.`, + values: { + axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), + }, + }), + }); + } + if (state.layers.length > 1 && (hasDateHistogramSet || hasNumberHistogram) && hasOrdinalAxis) { + errors.push({ + shortMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXShort', { + defaultMessage: `Wrong data type for {axis}.`, + values: { + axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), + }, + }), + longMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXOrdinalLong', { + defaultMessage: `Data type mismatch for the {axis}, use a different function.`, + values: { + axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), + }, + }), + }); + } + return errors; +} + +export function checkScaleOperation( + scaleType: 'ordinal' | 'interval' | 'ratio', + dataType: 'date' | 'number' | 'string' | undefined, + datasourceLayers: Record +) { + return (layer: XYLayerConfig) => { + const datasourceAPI = datasourceLayers[layer.layerId]; + if (!layer.xAccessor) { + return false; + } + const operation = datasourceAPI?.getOperationForColumnId(layer.xAccessor); + return Boolean( + operation && (!dataType || operation.dataType === dataType) && operation.scale === scaleType + ); + }; +} diff --git a/x-pack/plugins/lens/public/xy_visualization/axis_settings_popover.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/axis_settings_popover.test.tsx similarity index 98% rename from x-pack/plugins/lens/public/xy_visualization/axis_settings_popover.test.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/axis_settings_popover.test.tsx index aa287795c8181..ebe0e536a4d77 100644 --- a/x-pack/plugins/lens/public/xy_visualization/axis_settings_popover.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/axis_settings_popover.test.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { shallowWithIntl as shallow } from '@kbn/test/jest'; import { AxisSettingsPopover, AxisSettingsPopoverProps } from './axis_settings_popover'; -import { ToolbarPopover } from '../shared_components'; -import { layerTypes } from '../../common'; +import { ToolbarPopover } from '../../shared_components'; +import { layerTypes } from '../../../common'; describe('Axes Settings', () => { let props: AxisSettingsPopoverProps; diff --git a/x-pack/plugins/lens/public/xy_visualization/axis_settings_popover.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/axis_settings_popover.tsx similarity index 96% rename from x-pack/plugins/lens/public/xy_visualization/axis_settings_popover.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/axis_settings_popover.tsx index 2285cd1a7a43a..e0a30bdb2c511 100644 --- a/x-pack/plugins/lens/public/xy_visualization/axis_settings_popover.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/axis_settings_popover.tsx @@ -20,15 +20,15 @@ import { EuiFieldNumber, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { XYLayerConfig, AxesSettingsConfig, AxisExtentConfig } from '../../common/expressions'; -import { ToolbarPopover, useDebouncedValue } from '../shared_components'; -import { isHorizontalChart } from './state_helpers'; -import { EuiIconAxisBottom } from '../assets/axis_bottom'; -import { EuiIconAxisLeft } from '../assets/axis_left'; -import { EuiIconAxisRight } from '../assets/axis_right'; -import { EuiIconAxisTop } from '../assets/axis_top'; -import { ToolbarButtonProps } from '../../../../../src/plugins/kibana_react/public'; -import { validateExtent } from './axes_configuration'; +import { XYLayerConfig, AxesSettingsConfig, AxisExtentConfig } from '../../../common/expressions'; +import { ToolbarPopover, useDebouncedValue } from '../../shared_components'; +import { isHorizontalChart } from '../state_helpers'; +import { EuiIconAxisBottom } from '../../assets/axis_bottom'; +import { EuiIconAxisLeft } from '../../assets/axis_left'; +import { EuiIconAxisRight } from '../../assets/axis_right'; +import { EuiIconAxisTop } from '../../assets/axis_top'; +import { ToolbarButtonProps } from '../../../../../../src/plugins/kibana_react/public'; +import { validateExtent } from '../axes_configuration'; type AxesSettingsConfigKeys = keyof AxesSettingsConfig; diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/color_picker.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/color_picker.tsx new file mode 100644 index 0000000000000..5a6458a4654d0 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/color_picker.tsx @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import './xy_config_panel.scss'; +import React, { useMemo, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { debounce } from 'lodash'; +import { EuiFormRow, EuiColorPicker, EuiColorPickerProps, EuiToolTip, EuiIcon } from '@elastic/eui'; +import type { PaletteRegistry } from 'src/plugins/charts/public'; +import type { VisualizationDimensionEditorProps } from '../../types'; +import { State } from '../types'; +import { FormatFactory } from '../../../common'; +import { getSeriesColor } from '../state_helpers'; +import { getAccessorColorConfig, getColorAssignments } from '../color_assignment'; +import { getSortedAccessors } from '../to_expression'; +import { updateLayer } from '.'; +import { TooltipWrapper } from '../../shared_components'; + +const tooltipContent = { + auto: i18n.translate('xpack.lens.configPanel.color.tooltip.auto', { + defaultMessage: 'Lens automatically picks colors for you unless you specify a custom color.', + }), + custom: i18n.translate('xpack.lens.configPanel.color.tooltip.custom', { + defaultMessage: 'Clear the custom color to return to “Auto” mode.', + }), + disabled: i18n.translate('xpack.lens.configPanel.color.tooltip.disabled', { + defaultMessage: + 'Individual series cannot be custom colored when the layer includes a “Break down by.“', + }), +}; + +export const ColorPicker = ({ + state, + setState, + layerId, + accessor, + frame, + formatFactory, + paletteService, + label, + disableHelpTooltip, +}: VisualizationDimensionEditorProps & { + formatFactory: FormatFactory; + paletteService: PaletteRegistry; + label?: string; + disableHelpTooltip?: boolean; +}) => { + const index = state.layers.findIndex((l) => l.layerId === layerId); + const layer = state.layers[index]; + const disabled = Boolean(layer.splitAccessor); + + const overwriteColor = getSeriesColor(layer, accessor); + const currentColor = useMemo(() => { + if (overwriteColor || !frame.activeData) return overwriteColor; + + const datasource = frame.datasourceLayers[layer.layerId]; + const sortedAccessors: string[] = getSortedAccessors(datasource, layer); + + const colorAssignments = getColorAssignments( + state.layers, + { tables: frame.activeData }, + formatFactory + ); + const mappedAccessors = getAccessorColorConfig( + colorAssignments, + frame, + { + ...layer, + accessors: sortedAccessors.filter((sorted) => layer.accessors.includes(sorted)), + }, + paletteService + ); + + return mappedAccessors.find((a) => a.columnId === accessor)?.color || null; + }, [overwriteColor, frame, paletteService, state.layers, accessor, formatFactory, layer]); + + const [color, setColor] = useState(currentColor); + + const handleColor: EuiColorPickerProps['onChange'] = (text, output) => { + setColor(text); + if (output.isValid || text === '') { + updateColorInState(text, output); + } + }; + + const updateColorInState: EuiColorPickerProps['onChange'] = useMemo( + () => + debounce((text, output) => { + const newYConfigs = [...(layer.yConfig || [])]; + const existingIndex = newYConfigs.findIndex((yConfig) => yConfig.forAccessor === accessor); + if (existingIndex !== -1) { + if (text === '') { + newYConfigs[existingIndex] = { ...newYConfigs[existingIndex], color: undefined }; + } else { + newYConfigs[existingIndex] = { ...newYConfigs[existingIndex], color: output.hex }; + } + } else { + newYConfigs.push({ + forAccessor: accessor, + color: output.hex, + }); + } + setState(updateLayer(state, { ...layer, yConfig: newYConfigs }, index)); + }, 256), + [state, setState, layer, accessor, index] + ); + + const inputLabel = + label ?? + i18n.translate('xpack.lens.xyChart.seriesColor.label', { + defaultMessage: 'Series color', + }); + + const colorPicker = ( + + ); + + return ( + + + {inputLabel} + {!disableHelpTooltip && ( + <> + {''} + + + )} + + + } + > + {disabled ? ( + + {colorPicker} + + ) : ( + colorPicker + )} + + ); +}; diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/index.tsx similarity index 72% rename from x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/index.tsx index cd90fa52cd402..1427a3d28ea39 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/index.tsx @@ -6,24 +6,15 @@ */ import './xy_config_panel.scss'; -import React, { useMemo, useState, memo, useCallback } from 'react'; +import React, { memo, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { Position, ScaleType, VerticalAlignment, HorizontalAlignment } from '@elastic/charts'; -import { debounce } from 'lodash'; import { EuiButtonGroup, EuiFlexGroup, EuiFlexItem, EuiFormRow, htmlIdGenerator, - EuiColorPicker, - EuiColorPickerProps, - EuiToolTip, - EuiIcon, - EuiPopover, - EuiSelectable, - EuiText, - EuiPopoverTitle, } from '@elastic/eui'; import type { PaletteRegistry } from 'src/plugins/charts/public'; import type { @@ -31,30 +22,34 @@ import type { VisualizationToolbarProps, VisualizationDimensionEditorProps, FramePublicAPI, -} from '../types'; -import { State, visualizationTypes, XYState } from './types'; -import type { FormatFactory } from '../../common'; +} from '../../types'; +import { State, visualizationTypes, XYState } from '../types'; +import type { FormatFactory } from '../../../common'; import { SeriesType, YAxisMode, AxesSettingsConfig, AxisExtentConfig, -} from '../../common/expressions'; -import { isHorizontalChart, isHorizontalSeries, getSeriesColor } from './state_helpers'; -import { trackUiEvent } from '../lens_ui_telemetry'; -import { LegendSettingsPopover } from '../shared_components'; +} from '../../../common/expressions'; +import { isHorizontalChart, isHorizontalSeries } from '../state_helpers'; +import { trackUiEvent } from '../../lens_ui_telemetry'; +import { LegendSettingsPopover } from '../../shared_components'; import { AxisSettingsPopover } from './axis_settings_popover'; -import { getAxesConfiguration, GroupsConfiguration } from './axes_configuration'; -import { PalettePicker, TooltipWrapper } from '../shared_components'; -import { getAccessorColorConfig, getColorAssignments } from './color_assignment'; -import { getScaleType, getSortedAccessors } from './to_expression'; -import { VisualOptionsPopover } from './visual_options_popover/visual_options_popover'; -import { ToolbarButton } from '../../../../../src/plugins/kibana_react/public'; +import { getAxesConfiguration, GroupsConfiguration } from '../axes_configuration'; +import { VisualOptionsPopover } from './visual_options_popover'; +import { getScaleType } from '../to_expression'; +import { ColorPicker } from './color_picker'; +import { ThresholdPanel } from './threshold_panel'; +import { PalettePicker, TooltipWrapper } from '../../shared_components'; type UnwrapArray = T extends Array ? P : T; type AxesSettingsConfigKeys = keyof AxesSettingsConfig; -function updateLayer(state: State, layer: UnwrapArray, index: number): State { +export function updateLayer( + state: State, + layer: UnwrapArray, + index: number +): State { const newLayers = [...state.layers]; newLayers[index] = layer; @@ -92,90 +87,6 @@ const legendOptions: Array<{ }, ]; -export function LayerHeader(props: VisualizationLayerWidgetProps) { - const [isPopoverOpen, setPopoverIsOpen] = useState(false); - const { state, layerId } = props; - const horizontalOnly = isHorizontalChart(state.layers); - const index = state.layers.findIndex((l) => l.layerId === layerId); - const layer = state.layers[index]; - if (!layer) { - return null; - } - - const currentVisType = visualizationTypes.find(({ id }) => id === layer.seriesType)!; - - const createTrigger = function () { - return ( - setPopoverIsOpen(!isPopoverOpen)} - fullWidth - size="s" - > - <> - - - {currentVisType.fullLabel || currentVisType.label} - - - - ); - }; - - return ( - <> - setPopoverIsOpen(false)} - display="block" - panelPaddingSize="s" - ownFocus - > - - {i18n.translate('xpack.lens.layerPanel.layerVisualizationType', { - defaultMessage: 'Layer visualization type', - })} - -
    - - singleSelection="always" - options={visualizationTypes - .filter((t) => isHorizontalSeries(t.id as SeriesType) === horizontalOnly) - .map((t) => ({ - value: t.id, - key: t.id, - checked: t.id === currentVisType.id ? 'on' : undefined, - prepend: , - label: t.fullLabel || t.label, - 'data-test-subj': `lnsXY_seriesType-${t.id}`, - }))} - onChange={(newOptions) => { - const chosenType = newOptions.find(({ checked }) => checked === 'on'); - if (!chosenType) { - return; - } - const id = chosenType.value!; - trackUiEvent('xy_change_layer_display'); - props.setState(updateLayer(state, { ...layer, seriesType: id as SeriesType }, index)); - setPopoverIsOpen(false); - }} - > - {(list) => <>{list}} - -
    -
    - - ); -} - export function LayerContextMenu(props: VisualizationLayerWidgetProps) { const { state, layerId } = props; const horizontalOnly = isHorizontalChart(state.layers); @@ -622,7 +533,7 @@ export const XyToolbar = memo(function XyToolbar(props: VisualizationToolbarProp ); }); -const idPrefix = htmlIdGenerator()(); +export const idPrefix = htmlIdGenerator()(); export function DimensionEditor( props: VisualizationDimensionEditorProps & { @@ -653,6 +564,10 @@ export function DimensionEditor( ); } + if (layer.layerType === 'threshold') { + return ; + } + return ( <> @@ -728,140 +643,3 @@ export function DimensionEditor( ); } - -const tooltipContent = { - auto: i18n.translate('xpack.lens.configPanel.color.tooltip.auto', { - defaultMessage: 'Lens automatically picks colors for you unless you specify a custom color.', - }), - custom: i18n.translate('xpack.lens.configPanel.color.tooltip.custom', { - defaultMessage: 'Clear the custom color to return to “Auto” mode.', - }), - disabled: i18n.translate('xpack.lens.configPanel.color.tooltip.disabled', { - defaultMessage: - 'Individual series cannot be custom colored when the layer includes a “Break down by.“', - }), -}; - -const ColorPicker = ({ - state, - setState, - layerId, - accessor, - frame, - formatFactory, - paletteService, -}: VisualizationDimensionEditorProps & { - formatFactory: FormatFactory; - paletteService: PaletteRegistry; -}) => { - const index = state.layers.findIndex((l) => l.layerId === layerId); - const layer = state.layers[index]; - const disabled = !!layer.splitAccessor; - - const overwriteColor = getSeriesColor(layer, accessor); - const currentColor = useMemo(() => { - if (overwriteColor || !frame.activeData) return overwriteColor; - - const datasource = frame.datasourceLayers[layer.layerId]; - const sortedAccessors: string[] = getSortedAccessors(datasource, layer); - - const colorAssignments = getColorAssignments( - state.layers, - { tables: frame.activeData }, - formatFactory - ); - const mappedAccessors = getAccessorColorConfig( - colorAssignments, - frame, - { - ...layer, - accessors: sortedAccessors.filter((sorted) => layer.accessors.includes(sorted)), - }, - paletteService - ); - - return mappedAccessors.find((a) => a.columnId === accessor)?.color || null; - }, [overwriteColor, frame, paletteService, state.layers, accessor, formatFactory, layer]); - - const [color, setColor] = useState(currentColor); - - const handleColor: EuiColorPickerProps['onChange'] = (text, output) => { - setColor(text); - if (output.isValid || text === '') { - updateColorInState(text, output); - } - }; - - const updateColorInState: EuiColorPickerProps['onChange'] = useMemo( - () => - debounce((text, output) => { - const newYConfigs = [...(layer.yConfig || [])]; - const existingIndex = newYConfigs.findIndex((yConfig) => yConfig.forAccessor === accessor); - if (existingIndex !== -1) { - if (text === '') { - newYConfigs[existingIndex] = { ...newYConfigs[existingIndex], color: undefined }; - } else { - newYConfigs[existingIndex] = { ...newYConfigs[existingIndex], color: output.hex }; - } - } else { - newYConfigs.push({ - forAccessor: accessor, - color: output.hex, - }); - } - setState(updateLayer(state, { ...layer, yConfig: newYConfigs }, index)); - }, 256), - [state, setState, layer, accessor, index] - ); - - const colorPicker = ( - - ); - - return ( - - - {i18n.translate('xpack.lens.xyChart.seriesColor.label', { - defaultMessage: 'Series color', - })}{' '} - - -
    - } - > - {disabled ? ( - - {colorPicker} - - ) : ( - colorPicker - )} - - ); -}; diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/layer_header.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/layer_header.tsx new file mode 100644 index 0000000000000..dde4de0dd4bc3 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/layer_header.tsx @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import './xy_config_panel.scss'; +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiIcon, EuiPopover, EuiSelectable, EuiText, EuiPopoverTitle } from '@elastic/eui'; +import type { VisualizationLayerWidgetProps } from '../../types'; +import { State, visualizationTypes } from '../types'; +import { layerTypes } from '../../../common'; +import { SeriesType } from '../../../common/expressions'; +import { isHorizontalChart, isHorizontalSeries } from '../state_helpers'; +import { trackUiEvent } from '../../lens_ui_telemetry'; +import { StaticHeader } from '../../shared_components'; +import { ToolbarButton } from '../../../../../../src/plugins/kibana_react/public'; +import { LensIconChartBarThreshold } from '../../assets/chart_bar_threshold'; +import { updateLayer } from '.'; + +export function LayerHeader(props: VisualizationLayerWidgetProps) { + const [isPopoverOpen, setPopoverIsOpen] = useState(false); + const { state, layerId } = props; + const horizontalOnly = isHorizontalChart(state.layers); + const index = state.layers.findIndex((l) => l.layerId === layerId); + const layer = state.layers[index]; + if (!layer) { + return null; + } + // if it's a threshold just draw a static text + if (layer.layerType === layerTypes.THRESHOLD) { + return ( + + ); + } + const currentVisType = visualizationTypes.find(({ id }) => id === layer.seriesType)!; + + const createTrigger = function () { + return ( + setPopoverIsOpen(!isPopoverOpen)} + fullWidth + size="s" + > + <> + + + {currentVisType.fullLabel || currentVisType.label} + + + + ); + }; + + return ( + <> + setPopoverIsOpen(false)} + display="block" + panelPaddingSize="s" + ownFocus + > + + {i18n.translate('xpack.lens.layerPanel.layerVisualizationType', { + defaultMessage: 'Layer visualization type', + })} + +
    + + singleSelection="always" + options={visualizationTypes + .filter((t) => isHorizontalSeries(t.id as SeriesType) === horizontalOnly) + .map((t) => ({ + value: t.id, + key: t.id, + checked: t.id === currentVisType.id ? 'on' : undefined, + prepend: , + label: t.fullLabel || t.label, + 'data-test-subj': `lnsXY_seriesType-${t.id}`, + }))} + onChange={(newOptions) => { + const chosenType = newOptions.find(({ checked }) => checked === 'on'); + if (!chosenType) { + return; + } + const id = chosenType.value!; + trackUiEvent('xy_change_layer_display'); + props.setState(updateLayer(state, { ...layer, seriesType: id as SeriesType }, index)); + setPopoverIsOpen(false); + }} + > + {(list) => <>{list}} + +
    +
    + + ); +} diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/threshold_panel.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/threshold_panel.tsx new file mode 100644 index 0000000000000..1e5b90e41b623 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/threshold_panel.tsx @@ -0,0 +1,326 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import './xy_config_panel.scss'; +import React, { useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiButtonGroup, EuiComboBox, EuiFormRow, EuiIcon, EuiRange } from '@elastic/eui'; +import type { PaletteRegistry } from 'src/plugins/charts/public'; +import type { VisualizationDimensionEditorProps } from '../../types'; +import { State } from '../types'; +import { FormatFactory } from '../../../common'; +import { YConfig } from '../../../common/expressions'; +import { LineStyle, FillStyle } from '../../../common/expressions/xy_chart'; + +import { ColorPicker } from './color_picker'; +import { updateLayer, idPrefix } from '.'; +import { useDebouncedValue } from '../../shared_components'; + +const icons = [ + { + value: 'none', + label: i18n.translate('xpack.lens.xyChart.thresholds.noIconLabel', { defaultMessage: 'None' }), + }, + { + value: 'asterisk', + label: i18n.translate('xpack.lens.xyChart.thresholds.asteriskIconLabel', { + defaultMessage: 'Asterisk', + }), + }, + { + value: 'bell', + label: i18n.translate('xpack.lens.xyChart.thresholds.bellIconLabel', { + defaultMessage: 'Bell', + }), + }, + { + value: 'bolt', + label: i18n.translate('xpack.lens.xyChart.thresholds.boltIconLabel', { + defaultMessage: 'Bolt', + }), + }, + { + value: 'bug', + label: i18n.translate('xpack.lens.xyChart.thresholds.bugIconLabel', { + defaultMessage: 'Bug', + }), + }, + { + value: 'editorComment', + label: i18n.translate('xpack.lens.xyChart.thresholds.commentIconLabel', { + defaultMessage: 'Comment', + }), + }, + { + value: 'alert', + label: i18n.translate('xpack.lens.xyChart.thresholds.alertIconLabel', { + defaultMessage: 'Alert', + }), + }, + { + value: 'flag', + label: i18n.translate('xpack.lens.xyChart.thresholds.flagIconLabel', { + defaultMessage: 'Flag', + }), + }, + { + value: 'tag', + label: i18n.translate('xpack.lens.xyChart.thresholds.tagIconLabel', { + defaultMessage: 'Tag', + }), + }, +]; + +const IconView = (props: { value?: string; label: string }) => { + if (!props.value) return null; + return ( + + + {` ${props.label}`} + + ); +}; + +const IconSelect = ({ + value, + onChange, +}: { + value?: string; + onChange: (newIcon: string) => void; +}) => { + const selectedIcon = icons.find((option) => value === option.value) || icons[0]; + + return ( + { + onChange(selection[0].value!); + }} + singleSelection={{ asPlainText: true }} + renderOption={IconView} + compressed + /> + ); +}; + +export const ThresholdPanel = ( + props: VisualizationDimensionEditorProps & { + formatFactory: FormatFactory; + paletteService: PaletteRegistry; + } +) => { + const { state, setState, layerId, accessor } = props; + const index = state.layers.findIndex((l) => l.layerId === layerId); + const layer = state.layers[index]; + + const setYConfig = useCallback( + (yConfig: Partial | undefined) => { + if (yConfig == null) { + return; + } + setState((currState) => { + const currLayer = currState.layers[index]; + const newYConfigs = [...(currLayer.yConfig || [])]; + const existingIndex = newYConfigs.findIndex( + (yAxisConfig) => yAxisConfig.forAccessor === accessor + ); + if (existingIndex !== -1) { + newYConfigs[existingIndex] = { ...newYConfigs[existingIndex], ...yConfig }; + } else { + newYConfigs.push({ forAccessor: accessor, ...yConfig }); + } + return updateLayer(currState, { ...currLayer, yConfig: newYConfigs }, index); + }); + }, + [accessor, index, setState] + ); + + const currentYConfig = layer.yConfig?.find((yConfig) => yConfig.forAccessor === accessor); + + return ( + <> + + + { + const newMode = id.replace(idPrefix, '') as LineStyle; + setYConfig({ forAccessor: accessor, lineStyle: newMode }); + }} + /> + + + { + setYConfig({ forAccessor: accessor, lineWidth: value }); + }} + /> + + + { + const newMode = id.replace(idPrefix, '') as FillStyle; + setYConfig({ forAccessor: accessor, fill: newMode }); + }} + /> + + + { + setYConfig({ forAccessor: accessor, icon: newIcon }); + }} + /> + + + ); +}; + +const minRange = 1; +const maxRange = 10; + +function getSafeValue(value: number | '', prevValue: number, min: number, max: number) { + if (value === '') { + return prevValue; + } + return Math.max(minRange, Math.min(value, maxRange)); +} + +const LineThicknessSlider = ({ + value, + onChange, +}: { + value: number; + onChange: (value: number) => void; +}) => { + const onChangeWrapped = useCallback( + (newValue) => { + if (Number.isInteger(newValue)) { + onChange(getSafeValue(newValue, newValue, minRange, maxRange)); + } + }, + [onChange] + ); + const { inputValue, handleInputChange } = useDebouncedValue( + { value, onChange: onChangeWrapped }, + { allowFalsyValue: true } + ); + + return ( + { + const newValue = e.currentTarget.value; + handleInputChange(newValue === '' ? '' : Number(newValue)); + }} + onBlur={() => { + handleInputChange(getSafeValue(inputValue, value, minRange, maxRange)); + }} + /> + ); +}; diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/fill_opacity_option.test.tsx similarity index 100% rename from x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/fill_opacity_option.test.tsx diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/fill_opacity_option.tsx similarity index 95% rename from x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/fill_opacity_option.tsx index eb8d35c54a99b..09b381dd03f7a 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/fill_opacity_option.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFormRow, EuiRange } from '@elastic/eui'; -import { useDebouncedValue } from '../../shared_components'; +import { useDebouncedValue } from '../../../shared_components'; export interface FillOpacityOptionProps { /** diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/index.tsx similarity index 93% rename from x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/index.tsx index 6d0e5c2d55b70..2a19897445e63 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/index.tsx @@ -7,14 +7,14 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ToolbarPopover, TooltipWrapper } from '../../shared_components'; +import { ToolbarPopover, TooltipWrapper } from '../../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; import { LineCurveOption } from './line_curve_option'; import { FillOpacityOption } from './fill_opacity_option'; -import { XYState } from '../types'; -import { hasHistogramSeries } from '../state_helpers'; -import { ValidLayer } from '../../../common/expressions'; -import type { FramePublicAPI } from '../../types'; +import { XYState } from '../../types'; +import { hasHistogramSeries } from '../../state_helpers'; +import { ValidLayer } from '../../../../common/expressions'; +import type { FramePublicAPI } from '../../../types'; function getValueLabelDisableReason({ isAreaPercentage, diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/line_curve_option.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/line_curve_option.test.tsx similarity index 100% rename from x-pack/plugins/lens/public/xy_visualization/visual_options_popover/line_curve_option.test.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/line_curve_option.test.tsx diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/line_curve_option.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/line_curve_option.tsx similarity index 95% rename from x-pack/plugins/lens/public/xy_visualization/visual_options_popover/line_curve_option.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/line_curve_option.tsx index 6080a8c68e57d..96926412afb8a 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/line_curve_option.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/line_curve_option.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFormRow, EuiSwitch } from '@elastic/eui'; -import type { XYCurveType } from '../../../common/expressions'; +import type { XYCurveType } from '../../../../common/expressions'; export interface LineCurveOptionProps { /** diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_value_option.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_value_option.test.tsx similarity index 100% rename from x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_value_option.test.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_value_option.test.tsx diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_values_option.tsx similarity index 97% rename from x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_values_option.tsx index 3dba8757903e9..b12e2d2f57112 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/missing_values_option.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButtonGroup, EuiFormRow, EuiIconTip, EuiSuperSelect, EuiText } from '@elastic/eui'; -import { fittingFunctionDefinitions } from '../../../common/expressions'; -import type { FittingFunction, ValueLabelConfig } from '../../../common/expressions'; +import { fittingFunctionDefinitions } from '../../../../common/expressions'; +import type { FittingFunction, ValueLabelConfig } from '../../../../common/expressions'; export interface MissingValuesOptionProps { valueLabels?: ValueLabelConfig; diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/visual_options_popover.test.tsx similarity index 96% rename from x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/visual_options_popover.test.tsx index cd6a20c37dd38..0136612c46705 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/visual_options_popover/visual_options_popover.test.tsx @@ -8,14 +8,14 @@ import React from 'react'; import { shallowWithIntl as shallow } from '@kbn/test/jest'; import { Position } from '@elastic/charts'; -import type { FramePublicAPI } from '../../types'; -import { createMockDatasource, createMockFramePublicAPI } from '../../mocks'; -import { State } from '../types'; -import { VisualOptionsPopover } from './visual_options_popover'; -import { ToolbarPopover } from '../../shared_components'; +import type { FramePublicAPI } from '../../../types'; +import { createMockDatasource, createMockFramePublicAPI } from '../../../mocks'; +import { State } from '../../types'; +import { VisualOptionsPopover } from '.'; +import { ToolbarPopover } from '../../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; import { FillOpacityOption } from './fill_opacity_option'; -import { layerTypes } from '../../../common'; +import { layerTypes } from '../../../../common'; describe('Visual options popover', () => { let frame: FramePublicAPI; diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.scss b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/xy_config_panel.scss similarity index 100% rename from x-pack/plugins/lens/public/xy_visualization/xy_config_panel.scss rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/xy_config_panel.scss diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/xy_config_panel.test.tsx similarity index 98% rename from x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/xy_config_panel.test.tsx index 9ca9021382fda..e5b1870c73404 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/xy_config_panel.test.tsx @@ -8,15 +8,15 @@ import React from 'react'; import { mountWithIntl as mount, shallowWithIntl as shallow } from '@kbn/test/jest'; import { EuiButtonGroupProps, EuiButtonGroup } from '@elastic/eui'; -import { LayerContextMenu, XyToolbar, DimensionEditor } from './xy_config_panel'; +import { LayerContextMenu, XyToolbar, DimensionEditor } from '.'; import { AxisSettingsPopover } from './axis_settings_popover'; -import { FramePublicAPI } from '../types'; -import { State } from './types'; +import { FramePublicAPI } from '../../types'; +import { State } from '../types'; import { Position } from '@elastic/charts'; -import { createMockFramePublicAPI, createMockDatasource } from '../mocks'; +import { createMockFramePublicAPI, createMockDatasource } from '../../mocks'; import { chartPluginMock } from 'src/plugins/charts/public/mocks'; import { EuiColorPicker } from '@elastic/eui'; -import { layerTypes } from '../../common'; +import { layerTypes } from '../../../common'; describe('XY Config panels', () => { let frame: FramePublicAPI; diff --git a/x-pack/plugins/lens/server/index.ts b/x-pack/plugins/lens/server/index.ts index 08f1eb1562739..e2117506e9b72 100644 --- a/x-pack/plugins/lens/server/index.ts +++ b/x-pack/plugins/lens/server/index.ts @@ -19,6 +19,7 @@ import { configSchema, ConfigSchema } from '../config'; export const config: PluginConfigDescriptor = { schema: configSchema, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; export const plugin = (initializerContext: PluginInitializerContext) => diff --git a/x-pack/plugins/license_management/server/index.ts b/x-pack/plugins/license_management/server/index.ts index 7a24845c981e9..e78ffe07b50c0 100644 --- a/x-pack/plugins/license_management/server/index.ts +++ b/x-pack/plugins/license_management/server/index.ts @@ -17,4 +17,5 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { ui: true, }, + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; diff --git a/x-pack/plugins/lists/server/index.ts b/x-pack/plugins/lists/server/index.ts index 250b5e79ed109..7e1283927aa86 100644 --- a/x-pack/plugins/lists/server/index.ts +++ b/x-pack/plugins/lists/server/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginInitializerContext } from '../../../../src/core/server'; +import { PluginConfigDescriptor, PluginInitializerContext } from '../../../../src/core/server'; import { ConfigSchema } from './config'; import { ListPlugin } from './plugin'; @@ -19,6 +19,9 @@ export { export { ExceptionListClient } from './services/exception_lists/exception_list_client'; export type { ListPluginSetup, ListsApiRequestHandlerContext } from './types'; -export const config = { schema: ConfigSchema }; +export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], + schema: ConfigSchema, +}; export const plugin = (initializerContext: PluginInitializerContext): ListPlugin => new ListPlugin(initializerContext); diff --git a/x-pack/plugins/lists/server/plugin.ts b/x-pack/plugins/lists/server/plugin.ts index 6a1b0733c1867..7fa1bc460723a 100644 --- a/x-pack/plugins/lists/server/plugin.ts +++ b/x-pack/plugins/lists/server/plugin.ts @@ -27,9 +27,7 @@ import { getUser } from './get_user'; import { initSavedObjects } from './saved_objects'; import { ExceptionListClient } from './services/exception_lists/exception_list_client'; -export class ListPlugin - implements Plugin, ListsPluginStart, {}, PluginsStart> -{ +export class ListPlugin implements Plugin { private readonly logger: Logger; private readonly config: ConfigType; private spaces: SpacesServiceStart | undefined | null; @@ -40,7 +38,7 @@ export class ListPlugin this.config = this.initializerContext.config.get(); } - public async setup(core: CoreSetup): Promise { + public setup(core: CoreSetup): ListPluginSetup { const { config } = this; initSavedObjects(core.savedObjects); @@ -70,7 +68,7 @@ export class ListPlugin }; } - public start(core: CoreStart, plugins: PluginsStart): void { + public start(core: CoreStart, plugins: PluginsStart): ListsPluginStart { this.logger.debug('Starting plugin'); this.security = plugins.security; this.spaces = plugins.spaces?.spacesService; diff --git a/x-pack/plugins/logstash/server/index.ts b/x-pack/plugins/logstash/server/index.ts index 4606a518fa8c5..33f3777297f63 100644 --- a/x-pack/plugins/logstash/server/index.ts +++ b/x-pack/plugins/logstash/server/index.ts @@ -15,4 +15,5 @@ export const config: PluginConfigDescriptor = { schema: schema.object({ enabled: schema.boolean({ defaultValue: true }), }), + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; diff --git a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts index 740da8493c53c..244ebc59efd17 100644 --- a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts @@ -23,6 +23,7 @@ import { KBN_IS_TILE_COMPLETE, KBN_METADATA_FEATURE, KBN_VECTOR_SHAPE_TYPE_COUNTS, + LAYER_TYPE, } from '../constants'; export type Attribution = { @@ -56,7 +57,6 @@ export type LayerDescriptor = { alpha?: number; attribution?: Attribution; id: string; - joins?: JoinDescriptor[]; label?: string | null; areLabelsOnTop?: boolean; minZoom?: number; @@ -70,9 +70,12 @@ export type LayerDescriptor = { }; export type VectorLayerDescriptor = LayerDescriptor & { + type: LAYER_TYPE.VECTOR | LAYER_TYPE.TILED_VECTOR | LAYER_TYPE.BLENDED_VECTOR; + joins?: JoinDescriptor[]; style: VectorStyleDescriptor; }; export type HeatmapLayerDescriptor = LayerDescriptor & { + type: LAYER_TYPE.HEATMAP; style: HeatmapStyleDescriptor; }; diff --git a/x-pack/plugins/maps/common/index.ts b/x-pack/plugins/maps/common/index.ts index c1b5d26fca292..8374a4d0dbaa3 100644 --- a/x-pack/plugins/maps/common/index.ts +++ b/x-pack/plugins/maps/common/index.ts @@ -12,6 +12,7 @@ export { FIELD_ORIGIN, INITIAL_LOCATION, LABEL_BORDER_SIZES, + LAYER_TYPE, MAP_SAVED_OBJECT_TYPE, SOURCE_TYPES, STYLE_TYPE, diff --git a/x-pack/plugins/maps/common/migrations/add_type_to_termjoin.ts b/x-pack/plugins/maps/common/migrations/add_type_to_termjoin.ts index d40d85f9b6192..e46bf6a1a6e7f 100644 --- a/x-pack/plugins/maps/common/migrations/add_type_to_termjoin.ts +++ b/x-pack/plugins/maps/common/migrations/add_type_to_termjoin.ts @@ -6,8 +6,8 @@ */ import { MapSavedObjectAttributes } from '../map_saved_object_type'; -import { JoinDescriptor, LayerDescriptor } from '../descriptor_types'; -import { LAYER_TYPE, SOURCE_TYPES } from '../constants'; +import { JoinDescriptor, LayerDescriptor, VectorLayerDescriptor } from '../descriptor_types'; +import { SOURCE_TYPES } from '../constants'; // enforce type property on joins. It's possible older saved-objects do not have this correctly filled in // e.g. sample-data was missing the right.type field. @@ -24,14 +24,15 @@ export function addTypeToTermJoin({ const layerList: LayerDescriptor[] = JSON.parse(attributes.layerListJSON); layerList.forEach((layer: LayerDescriptor) => { - if (layer.type !== LAYER_TYPE.VECTOR) { + if (!('joins' in layer)) { return; } - if (!layer.joins) { + const vectorLayer = layer as VectorLayerDescriptor; + if (!vectorLayer.joins) { return; } - layer.joins.forEach((join: JoinDescriptor) => { + vectorLayer.joins.forEach((join: JoinDescriptor) => { if (!join.right) { return; } diff --git a/x-pack/plugins/maps/common/migrations/references.ts b/x-pack/plugins/maps/common/migrations/references.ts index d48be6bd56fbe..41d9dc063fe47 100644 --- a/x-pack/plugins/maps/common/migrations/references.ts +++ b/x-pack/plugins/maps/common/migrations/references.ts @@ -9,7 +9,7 @@ import { SavedObjectReference } from '../../../../../src/core/types'; import { MapSavedObjectAttributes } from '../map_saved_object_type'; -import { LayerDescriptor } from '../descriptor_types'; +import { LayerDescriptor, VectorLayerDescriptor } from '../descriptor_types'; interface IndexPatternReferenceDescriptor { indexPatternId?: string; @@ -44,21 +44,24 @@ export function extractReferences({ sourceDescriptor.indexPatternRefName = refName; } - // Extract index-pattern references from join - const joins = layer.joins ? layer.joins : []; - joins.forEach((join, joinIndex) => { - if ('indexPatternId' in join.right) { - const sourceDescriptor = join.right as IndexPatternReferenceDescriptor; - const refName = `layer_${layerIndex}_join_${joinIndex}_index_pattern`; - extractedReferences.push({ - name: refName, - type: 'index-pattern', - id: sourceDescriptor.indexPatternId!, - }); - delete sourceDescriptor.indexPatternId; - sourceDescriptor.indexPatternRefName = refName; - } - }); + if ('joins' in layer) { + // Extract index-pattern references from join + const vectorLayer = layer as VectorLayerDescriptor; + const joins = vectorLayer.joins ? vectorLayer.joins : []; + joins.forEach((join, joinIndex) => { + if ('indexPatternId' in join.right) { + const sourceDescriptor = join.right as IndexPatternReferenceDescriptor; + const refName = `layer_${layerIndex}_join_${joinIndex}_index_pattern`; + extractedReferences.push({ + name: refName, + type: 'index-pattern', + id: sourceDescriptor.indexPatternId!, + }); + delete sourceDescriptor.indexPatternId; + sourceDescriptor.indexPatternRefName = refName; + } + }); + } }); return { @@ -99,16 +102,19 @@ export function injectReferences({ delete sourceDescriptor.indexPatternRefName; } - // Inject index-pattern references into join - const joins = layer.joins ? layer.joins : []; - joins.forEach((join) => { - if ('indexPatternRefName' in join.right) { - const sourceDescriptor = join.right as IndexPatternReferenceDescriptor; - const reference = findReference(sourceDescriptor.indexPatternRefName!, references); - sourceDescriptor.indexPatternId = reference.id; - delete sourceDescriptor.indexPatternRefName; - } - }); + if ('joins' in layer) { + // Inject index-pattern references into join + const vectorLayer = layer as VectorLayerDescriptor; + const joins = vectorLayer.joins ? vectorLayer.joins : []; + joins.forEach((join) => { + if ('indexPatternRefName' in join.right) { + const sourceDescriptor = join.right as IndexPatternReferenceDescriptor; + const reference = findReference(sourceDescriptor.indexPatternRefName!, references); + sourceDescriptor.indexPatternId = reference.id; + delete sourceDescriptor.indexPatternRefName; + } + }); + } }); return { diff --git a/x-pack/plugins/maps/public/api/index.ts b/x-pack/plugins/maps/public/api/index.ts index 186fd98c90bf6..feded3e16f375 100644 --- a/x-pack/plugins/maps/public/api/index.ts +++ b/x-pack/plugins/maps/public/api/index.ts @@ -6,6 +6,7 @@ */ export { MapsStartApi } from './start_api'; +export { MapsSetupApi } from './setup_api'; export { createLayerDescriptors } from './create_layer_descriptors'; export { registerLayerWizard, registerSource } from './register'; export { suggestEMSTermJoinConfig } from './ems'; diff --git a/x-pack/plugins/maps/public/api/setup_api.ts b/x-pack/plugins/maps/public/api/setup_api.ts new file mode 100644 index 0000000000000..1b4fee968aad4 --- /dev/null +++ b/x-pack/plugins/maps/public/api/setup_api.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SourceRegistryEntry } from '../classes/sources/source_registry'; +import type { LayerWizard } from '../classes/layers/layer_wizard_registry'; + +export interface MapsSetupApi { + registerLayerWizard(layerWizard: LayerWizard): Promise; + registerSource(entry: SourceRegistryEntry): Promise; +} diff --git a/x-pack/plugins/maps/public/api/start_api.ts b/x-pack/plugins/maps/public/api/start_api.ts index e4213fe07a49c..eea440b8b2afc 100644 --- a/x-pack/plugins/maps/public/api/start_api.ts +++ b/x-pack/plugins/maps/public/api/start_api.ts @@ -6,8 +6,6 @@ */ import type { LayerDescriptor } from '../../common/descriptor_types'; -import type { SourceRegistryEntry } from '../classes/sources/source_registry'; -import type { LayerWizard } from '../classes/layers/layer_wizard_registry'; import type { CreateLayerDescriptorParams } from '../classes/sources/es_search_source'; import type { SampleValuesConfig, EMSTermJoinConfig } from '../ems_autosuggest'; @@ -22,7 +20,5 @@ export interface MapsStartApi { params: CreateLayerDescriptorParams ) => Promise; }; - registerLayerWizard(layerWizard: LayerWizard): Promise; - registerSource(entry: SourceRegistryEntry): Promise; suggestEMSTermJoinConfig(config: SampleValuesConfig): Promise; } diff --git a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts index d2734265f3bc3..a158892be9d09 100644 --- a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts @@ -33,7 +33,6 @@ import { SizeDynamicOptions, DynamicStylePropertyOptions, StylePropertyOptions, - LayerDescriptor, Timeslice, VectorLayerDescriptor, VectorSourceRequestMeta, @@ -179,7 +178,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { mapColors: string[] ): VectorLayerDescriptor { const layerDescriptor = VectorLayer.createDescriptor(options, mapColors); - layerDescriptor.type = BlendedVectorLayer.type; + layerDescriptor.type = LAYER_TYPE.BLENDED_VECTOR; return layerDescriptor; } @@ -256,7 +255,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { return false; } - async cloneDescriptor(): Promise { + async cloneDescriptor(): Promise { const clonedDescriptor = await super.cloneDescriptor(); // Use super getDisplayName instead of instance getDisplayName to avoid getting 'Clustered Clone of Clustered' diff --git a/x-pack/plugins/maps/public/classes/layers/layer.test.ts b/x-pack/plugins/maps/public/classes/layers/layer.test.ts index 83a936f377c7f..194b41680872c 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/layer.test.ts @@ -9,21 +9,6 @@ import { AbstractLayer } from './layer'; import { ISource } from '../sources/source'; -import { - AGG_TYPE, - FIELD_ORIGIN, - LAYER_STYLE_TYPE, - SOURCE_TYPES, - VECTOR_STYLES, -} from '../../../common/constants'; -import { ESTermSourceDescriptor, VectorStyleDescriptor } from '../../../common/descriptor_types'; -import { getDefaultDynamicProperties } from '../styles/vector/vector_style_defaults'; - -jest.mock('uuid/v4', () => { - return function () { - return '12345'; - }; -}); class MockLayer extends AbstractLayer {} @@ -36,111 +21,11 @@ class MockSource { return {}; } - getDisplayName() { - return 'mySource'; - } - async supportsFitToBounds() { return this._fitToBounds; } } -describe('cloneDescriptor', () => { - describe('with joins', () => { - const styleDescriptor = { - type: LAYER_STYLE_TYPE.VECTOR, - properties: { - ...getDefaultDynamicProperties(), - }, - } as VectorStyleDescriptor; - // @ts-expect-error - styleDescriptor.properties[VECTOR_STYLES.FILL_COLOR].options.field = { - name: '__kbnjoin__count__557d0f15', - origin: FIELD_ORIGIN.JOIN, - }; - // @ts-expect-error - styleDescriptor.properties[VECTOR_STYLES.LINE_COLOR].options.field = { - name: 'bytes', - origin: FIELD_ORIGIN.SOURCE, - }; - // @ts-expect-error - styleDescriptor.properties[VECTOR_STYLES.LABEL_BORDER_COLOR].options.field = { - name: '__kbnjoin__count__6666666666', - origin: FIELD_ORIGIN.JOIN, - }; - - test('Should update data driven styling properties using join fields', async () => { - const layerDescriptor = AbstractLayer.createDescriptor({ - style: styleDescriptor, - joins: [ - { - leftField: 'iso2', - right: { - id: '557d0f15', - indexPatternId: 'myIndexPattern', - indexPatternTitle: 'logs-*', - metrics: [{ type: AGG_TYPE.COUNT }], - term: 'myTermField', - type: SOURCE_TYPES.ES_TERM_SOURCE, - applyGlobalQuery: true, - applyGlobalTime: true, - applyForceRefresh: true, - }, - }, - ], - }); - const layer = new MockLayer({ - layerDescriptor, - source: new MockSource() as unknown as ISource, - }); - const clonedDescriptor = await layer.cloneDescriptor(); - const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties; - // Should update style field belonging to join - // @ts-expect-error - expect(clonedStyleProps[VECTOR_STYLES.FILL_COLOR].options.field.name).toEqual( - '__kbnjoin__count__12345' - ); - // Should not update style field belonging to source - // @ts-expect-error - expect(clonedStyleProps[VECTOR_STYLES.LINE_COLOR].options.field.name).toEqual('bytes'); - // Should not update style feild belonging to different join - // @ts-expect-error - expect(clonedStyleProps[VECTOR_STYLES.LABEL_BORDER_COLOR].options.field.name).toEqual( - '__kbnjoin__count__6666666666' - ); - }); - - test('Should update data driven styling properties using join fields when metrics are not provided', async () => { - const layerDescriptor = AbstractLayer.createDescriptor({ - style: styleDescriptor, - joins: [ - { - leftField: 'iso2', - right: { - id: '557d0f15', - indexPatternId: 'myIndexPattern', - indexPatternTitle: 'logs-*', - term: 'myTermField', - type: 'joinSource', - } as unknown as ESTermSourceDescriptor, - }, - ], - }); - const layer = new MockLayer({ - layerDescriptor, - source: new MockSource() as unknown as ISource, - }); - const clonedDescriptor = await layer.cloneDescriptor(); - const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties; - // Should update style field belonging to join - // @ts-expect-error - expect(clonedStyleProps[VECTOR_STYLES.FILL_COLOR].options.field.name).toEqual( - '__kbnjoin__count__12345' - ); - }); - }); -}); - describe('isFittable', () => { [ { diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index 0700e54a3fe87..e1043a33f28ad 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -16,23 +16,16 @@ import uuid from 'uuid/v4'; import { FeatureCollection } from 'geojson'; import { DataRequest } from '../util/data_request'; import { - AGG_TYPE, - FIELD_ORIGIN, LAYER_TYPE, MAX_ZOOM, MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER, MIN_ZOOM, SOURCE_BOUNDS_DATA_REQUEST_ID, SOURCE_DATA_REQUEST_ID, - SOURCE_TYPES, - STYLE_TYPE, } from '../../../common/constants'; import { copyPersistentState } from '../../reducers/copy_persistent_state'; import { - AggDescriptor, Attribution, - ESTermSourceDescriptor, - JoinDescriptor, LayerDescriptor, MapExtent, StyleDescriptor, @@ -42,7 +35,6 @@ import { import { ImmutableSourceProperty, ISource, SourceEditorArgs } from '../sources/source'; import { DataRequestContext } from '../../actions'; import { IStyle } from '../styles/style'; -import { getJoinAggKey } from '../../../common/get_agg_key'; import { LICENSED_FEATURES } from '../../licensed_features'; import { IESSource } from '../sources/es_source'; @@ -97,8 +89,6 @@ export interface ILayer { isPreviewLayer: () => boolean; areLabelsOnTop: () => boolean; supportsLabelsOnTop: () => boolean; - showJoinEditor(): boolean; - getJoinsDisabledReason(): string | null; isFittable(): Promise; isIncludeInFitToBounds(): boolean; getLicensedFeatures(): Promise; @@ -177,56 +167,6 @@ export class AbstractLayer implements ILayer { const displayName = await this.getDisplayName(); clonedDescriptor.label = `Clone of ${displayName}`; clonedDescriptor.sourceDescriptor = this.getSource().cloneDescriptor(); - - if (clonedDescriptor.joins) { - clonedDescriptor.joins.forEach((joinDescriptor: JoinDescriptor) => { - if (joinDescriptor.right && joinDescriptor.right.type === SOURCE_TYPES.TABLE_SOURCE) { - throw new Error( - 'Cannot clone table-source. Should only be used in MapEmbeddable, not in UX' - ); - } - const termSourceDescriptor: ESTermSourceDescriptor = - joinDescriptor.right as ESTermSourceDescriptor; - - // todo: must tie this to generic thing - const originalJoinId = joinDescriptor.right.id!; - - // right.id is uuid used to track requests in inspector - joinDescriptor.right.id = uuid(); - - // Update all data driven styling properties using join fields - if (clonedDescriptor.style && 'properties' in clonedDescriptor.style) { - const metrics = - termSourceDescriptor.metrics && termSourceDescriptor.metrics.length - ? termSourceDescriptor.metrics - : [{ type: AGG_TYPE.COUNT }]; - metrics.forEach((metricsDescriptor: AggDescriptor) => { - const originalJoinKey = getJoinAggKey({ - aggType: metricsDescriptor.type, - aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', - rightSourceId: originalJoinId, - }); - const newJoinKey = getJoinAggKey({ - aggType: metricsDescriptor.type, - aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', - rightSourceId: joinDescriptor.right.id!, - }); - - Object.keys(clonedDescriptor.style.properties).forEach((key) => { - const styleProp = clonedDescriptor.style.properties[key]; - if ( - styleProp.type === STYLE_TYPE.DYNAMIC && - styleProp.options.field && - styleProp.options.field.origin === FIELD_ORIGIN.JOIN && - styleProp.options.field.name === originalJoinKey - ) { - styleProp.options.field.name = newJoinKey; - } - }); - }); - } - }); - } return clonedDescriptor; } @@ -234,14 +174,6 @@ export class AbstractLayer implements ILayer { return `${this.getId()}${MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER}${layerNameSuffix}`; } - showJoinEditor(): boolean { - return this.getSource().showJoinEditor(); - } - - getJoinsDisabledReason() { - return this.getSource().getJoinsDisabledReason(); - } - isPreviewLayer(): boolean { return !!this._descriptor.__isPreviewLayer; } diff --git a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx index 30ec789cf8106..9b5298685865a 100644 --- a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx @@ -48,7 +48,7 @@ export class TiledVectorLayer extends VectorLayer { mapColors?: string[] ): VectorLayerDescriptor { const layerDescriptor = super.createDescriptor(descriptor, mapColors); - layerDescriptor.type = TiledVectorLayer.type; + layerDescriptor.type = LAYER_TYPE.TILED_VECTOR; if (!layerDescriptor.style) { const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors ? mapColors : []); diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/index.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/index.ts index 3c8449c5aa4ae..cb964f77613da 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/index.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/index.ts @@ -7,6 +7,7 @@ export { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from './utils'; export { + isVectorLayer, IVectorLayer, VectorLayer, VectorLayerArguments, diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.test.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.test.tsx new file mode 100644 index 0000000000000..618be0b21cd73 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.test.tsx @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable max-classes-per-file */ + +jest.mock('../../styles/vector/vector_style', () => ({ + VectorStyle: class MockVectorStyle {}, +})); + +jest.mock('uuid/v4', () => { + return function () { + return '12345'; + }; +}); + +import { + AGG_TYPE, + FIELD_ORIGIN, + LAYER_STYLE_TYPE, + SOURCE_TYPES, + VECTOR_STYLES, +} from '../../../../common/constants'; +import { ESTermSourceDescriptor, VectorStyleDescriptor } from '../../../../common/descriptor_types'; +import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults'; +import { IVectorSource } from '../../sources/vector_source'; +import { VectorLayer } from './vector_layer'; + +class MockSource { + cloneDescriptor() { + return {}; + } + + getDisplayName() { + return 'mySource'; + } +} + +describe('cloneDescriptor', () => { + describe('with joins', () => { + const styleDescriptor = { + type: LAYER_STYLE_TYPE.VECTOR, + properties: { + ...getDefaultDynamicProperties(), + }, + } as VectorStyleDescriptor; + // @ts-expect-error + styleDescriptor.properties[VECTOR_STYLES.FILL_COLOR].options.field = { + name: '__kbnjoin__count__557d0f15', + origin: FIELD_ORIGIN.JOIN, + }; + // @ts-expect-error + styleDescriptor.properties[VECTOR_STYLES.LINE_COLOR].options.field = { + name: 'bytes', + origin: FIELD_ORIGIN.SOURCE, + }; + // @ts-expect-error + styleDescriptor.properties[VECTOR_STYLES.LABEL_BORDER_COLOR].options.field = { + name: '__kbnjoin__count__6666666666', + origin: FIELD_ORIGIN.JOIN, + }; + + test('Should update data driven styling properties using join fields', async () => { + const layerDescriptor = VectorLayer.createDescriptor({ + style: styleDescriptor, + joins: [ + { + leftField: 'iso2', + right: { + id: '557d0f15', + indexPatternId: 'myIndexPattern', + indexPatternTitle: 'logs-*', + metrics: [{ type: AGG_TYPE.COUNT }], + term: 'myTermField', + type: SOURCE_TYPES.ES_TERM_SOURCE, + applyGlobalQuery: true, + applyGlobalTime: true, + applyForceRefresh: true, + }, + }, + ], + }); + const layer = new VectorLayer({ + layerDescriptor, + source: new MockSource() as unknown as IVectorSource, + }); + const clonedDescriptor = await layer.cloneDescriptor(); + const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties; + // Should update style field belonging to join + // @ts-expect-error + expect(clonedStyleProps[VECTOR_STYLES.FILL_COLOR].options.field.name).toEqual( + '__kbnjoin__count__12345' + ); + // Should not update style field belonging to source + // @ts-expect-error + expect(clonedStyleProps[VECTOR_STYLES.LINE_COLOR].options.field.name).toEqual('bytes'); + // Should not update style feild belonging to different join + // @ts-expect-error + expect(clonedStyleProps[VECTOR_STYLES.LABEL_BORDER_COLOR].options.field.name).toEqual( + '__kbnjoin__count__6666666666' + ); + }); + + test('Should update data driven styling properties using join fields when metrics are not provided', async () => { + const layerDescriptor = VectorLayer.createDescriptor({ + style: styleDescriptor, + joins: [ + { + leftField: 'iso2', + right: { + id: '557d0f15', + indexPatternId: 'myIndexPattern', + indexPatternTitle: 'logs-*', + term: 'myTermField', + type: 'joinSource', + } as unknown as ESTermSourceDescriptor, + }, + ], + }); + const layer = new VectorLayer({ + layerDescriptor, + source: new MockSource() as unknown as IVectorSource, + }); + const clonedDescriptor = await layer.cloneDescriptor(); + const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties; + // Should update style field belonging to join + // @ts-expect-error + expect(clonedStyleProps[VECTOR_STYLES.FILL_COLOR].options.field.name).toEqual( + '__kbnjoin__count__12345' + ); + }); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index fb310496ac9ed..3faf92715451c 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import uuid from 'uuid/v4'; import type { Map as MbMap, AnyLayer as MbLayer, @@ -19,6 +20,7 @@ import { i18n } from '@kbn/i18n'; import { AbstractLayer } from '../layer'; import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; import { + AGG_TYPE, FEATURE_ID_PROPERTY_NAME, SOURCE_META_DATA_REQUEST_ID, SOURCE_FORMATTERS_DATA_REQUEST_ID, @@ -29,8 +31,11 @@ import { FIELD_ORIGIN, KBN_TOO_MANY_FEATURES_IMAGE_ID, FieldFormatter, + SOURCE_TYPES, + STYLE_TYPE, SUPPORTS_FEATURE_EDITING_REQUEST_ID, KBN_IS_TILE_COMPLETE, + VECTOR_STYLES, } from '../../../../common/constants'; import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property'; import { DataRequestAbortError } from '../../util/data_request'; @@ -48,8 +53,11 @@ import { TimesliceMaskConfig, } from '../../util/mb_filter_expressions'; import { + AggDescriptor, DynamicStylePropertyOptions, DataFilters, + ESTermSourceDescriptor, + JoinDescriptor, StyleMetaDescriptor, Timeslice, VectorLayerDescriptor, @@ -71,6 +79,11 @@ import { ITermJoinSource } from '../../sources/term_join_source'; import { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from './utils'; import { JoinState, performInnerJoins } from './perform_inner_joins'; import { buildVectorRequestMeta } from '../build_vector_request_meta'; +import { getJoinAggKey } from '../../../../common/get_agg_key'; + +export function isVectorLayer(layer: ILayer) { + return (layer as IVectorLayer).canShowTooltip !== undefined; +} export interface VectorLayerArguments { source: IVectorSource; @@ -83,11 +96,13 @@ export interface IVectorLayer extends ILayer { getFields(): Promise; getStyleEditorFields(): Promise; getJoins(): InnerJoin[]; + getJoinsDisabledReason(): string | null; getValidJoins(): InnerJoin[]; getSource(): IVectorSource; getFeatureById(id: string | number): Feature | null; getPropertiesForTooltip(properties: GeoJsonProperties): Promise; hasJoins(): boolean; + showJoinEditor(): boolean; canShowTooltip(): boolean; supportsFeatureEditing(): boolean; getLeftJoinFields(): Promise; @@ -113,8 +128,8 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { options: Partial, mapColors?: string[] ): VectorLayerDescriptor { - const layerDescriptor = super.createDescriptor(options); - layerDescriptor.type = VectorLayer.type; + const layerDescriptor = super.createDescriptor(options) as VectorLayerDescriptor; + layerDescriptor.type = LAYER_TYPE.VECTOR; if (!options.style) { const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors ? mapColors : []); @@ -125,7 +140,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { layerDescriptor.joins = []; } - return layerDescriptor as VectorLayerDescriptor; + return layerDescriptor; } constructor({ @@ -147,6 +162,62 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { ); } + async cloneDescriptor(): Promise { + const clonedDescriptor = (await super.cloneDescriptor()) as VectorLayerDescriptor; + if (clonedDescriptor.joins) { + clonedDescriptor.joins.forEach((joinDescriptor: JoinDescriptor) => { + if (joinDescriptor.right && joinDescriptor.right.type === SOURCE_TYPES.TABLE_SOURCE) { + throw new Error( + 'Cannot clone table-source. Should only be used in MapEmbeddable, not in UX' + ); + } + const termSourceDescriptor: ESTermSourceDescriptor = + joinDescriptor.right as ESTermSourceDescriptor; + + // todo: must tie this to generic thing + const originalJoinId = joinDescriptor.right.id!; + + // right.id is uuid used to track requests in inspector + joinDescriptor.right.id = uuid(); + + // Update all data driven styling properties using join fields + if (clonedDescriptor.style && 'properties' in clonedDescriptor.style) { + const metrics = + termSourceDescriptor.metrics && termSourceDescriptor.metrics.length + ? termSourceDescriptor.metrics + : [{ type: AGG_TYPE.COUNT }]; + metrics.forEach((metricsDescriptor: AggDescriptor) => { + const originalJoinKey = getJoinAggKey({ + aggType: metricsDescriptor.type, + aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', + rightSourceId: originalJoinId, + }); + const newJoinKey = getJoinAggKey({ + aggType: metricsDescriptor.type, + aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', + rightSourceId: joinDescriptor.right.id!, + }); + + Object.keys(clonedDescriptor.style.properties).forEach((key) => { + const styleProp = clonedDescriptor.style.properties[key as VECTOR_STYLES]; + if ('type' in styleProp && styleProp.type === STYLE_TYPE.DYNAMIC) { + const options = styleProp.options as DynamicStylePropertyOptions; + if ( + options.field && + options.field.origin === FIELD_ORIGIN.JOIN && + options.field.name === originalJoinKey + ) { + options.field.name = newJoinKey; + } + } + }); + }); + } + }); + } + return clonedDescriptor; + } + getSource(): IVectorSource { return super.getSource() as IVectorSource; } @@ -176,6 +247,10 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { return this._joins.slice(); } + getJoinsDisabledReason() { + return this.getSource().getJoinsDisabledReason(); + } + getValidJoins() { return this.getJoins().filter((join) => { return join.hasCompleteConfig(); @@ -192,6 +267,10 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { return this.getValidJoins().length > 0; } + showJoinEditor(): boolean { + return this.getSource().showJoinEditor(); + } + isInitialDataLoadComplete() { const sourceDataRequest = this.getSourceDataRequest(); if (!sourceDataRequest || !sourceDataRequest.hasData()) { diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx index a955cb336e55e..34a30ae9ec977 100644 --- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx @@ -243,6 +243,14 @@ export class MVTSingleLayerVectorSource async getDefaultFields(): Promise>> { return {}; } + + showJoinEditor(): boolean { + return false; + } + + getJoinsDisabledReason(): string | null { + return null; + } } registerSource({ diff --git a/x-pack/plugins/maps/public/classes/sources/source.ts b/x-pack/plugins/maps/public/classes/sources/source.ts index 5b2fc16d18b41..4c2cffcf8b070 100644 --- a/x-pack/plugins/maps/public/classes/sources/source.ts +++ b/x-pack/plugins/maps/public/classes/sources/source.ts @@ -53,8 +53,6 @@ export interface ISource { isESSource(): boolean; renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs): ReactElement | null; supportsFitToBounds(): Promise; - showJoinEditor(): boolean; - getJoinsDisabledReason(): string | null; cloneDescriptor(): AbstractSourceDescriptor; getFieldNames(): string[]; getApplyGlobalQuery(): boolean; @@ -155,14 +153,6 @@ export class AbstractSource implements ISource { return 0; } - showJoinEditor(): boolean { - return false; - } - - getJoinsDisabledReason(): string | null { - return null; - } - isESSource(): boolean { return false; } diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx index bc3807a8247b1..3c0adf64216e6 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx @@ -59,6 +59,8 @@ export interface IVectorSource extends ISource { getFields(): Promise; getFieldByName(fieldName: string): IField | null; getLeftJoinFields(): Promise; + showJoinEditor(): boolean; + getJoinsDisabledReason(): string | null; /* * Vector layer avoids unnecessarily re-fetching source data. @@ -122,6 +124,10 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc return []; } + getJoinsDisabledReason(): string | null { + return null; + } + async getGeoJsonWithMeta( layerName: string, searchFilters: VectorSourceRequestMeta, diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/__snapshots__/edit_layer_panel.test.tsx.snap b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/__snapshots__/edit_layer_panel.test.tsx.snap index 24f15674a0504..5fb1cc6f72585 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/__snapshots__/edit_layer_panel.test.tsx.snap +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/__snapshots__/edit_layer_panel.test.tsx.snap @@ -93,6 +93,7 @@ exports[`EditLayerPanel is rendered 1`] = `
    mockSourceSettings @@ -112,6 +114,7 @@ exports[`EditLayerPanel is rendered 1`] = ` { return true; }, + canShowTooltip: () => { + return true; + }, supportsElasticsearchFilters: () => { return false; }, @@ -76,6 +79,9 @@ const mockLayer = { hasErrors: () => { return false; }, + supportsFitToBounds: () => { + return true; + }, } as unknown as ILayer; const defaultProps = { diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/edit_layer_panel.tsx b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/edit_layer_panel.tsx index da72969684216..424c4b8e16bec 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/edit_layer_panel.tsx +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/edit_layer_panel.tsx @@ -33,7 +33,7 @@ import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; import { LAYER_TYPE } from '../../../common/constants'; import { getData, getCore } from '../../kibana_services'; import { ILayer } from '../../classes/layers/layer'; -import { IVectorLayer } from '../../classes/layers/vector_layer'; +import { isVectorLayer, IVectorLayer } from '../../classes/layers/vector_layer'; import { ImmutableSourceProperty, OnSourceChangeArgs } from '../../classes/sources/source'; import { IField } from '../../classes/fields/field'; @@ -111,11 +111,12 @@ export class EditLayerPanel extends Component { }; async _loadLeftJoinFields() { - if ( - !this.props.selectedLayer || - !this.props.selectedLayer.showJoinEditor() || - (this.props.selectedLayer as IVectorLayer).getLeftJoinFields === undefined - ) { + if (!this.props.selectedLayer || !isVectorLayer(this.props.selectedLayer)) { + return; + } + + const vectorLayer = this.props.selectedLayer as IVectorLayer; + if (!vectorLayer.showJoinEditor() || vectorLayer.getLeftJoinFields === undefined) { return; } @@ -182,7 +183,11 @@ export class EditLayerPanel extends Component { } _renderJoinSection() { - if (!this.props.selectedLayer || !this.props.selectedLayer.showJoinEditor()) { + if (!this.props.selectedLayer || !isVectorLayer(this.props.selectedLayer)) { + return; + } + const vectorLayer = this.props.selectedLayer as IVectorLayer; + if (!vectorLayer.showJoinEditor()) { return null; } @@ -190,7 +195,7 @@ export class EditLayerPanel extends Component { diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/index.ts b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/index.ts index b78ffb3874e30..84caa45741a62 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/index.ts +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/index.ts @@ -13,11 +13,18 @@ import { LAYER_TYPE } from '../../../common/constants'; import { getSelectedLayer } from '../../selectors/map_selectors'; import { updateSourceProp } from '../../actions'; import { MapStoreState } from '../../reducers/store'; +import { isVectorLayer, IVectorLayer } from '../../classes/layers/vector_layer'; function mapStateToProps(state: MapStoreState) { const selectedLayer = getSelectedLayer(state); + let key = 'none'; + if (selectedLayer) { + key = isVectorLayer(selectedLayer) + ? `${selectedLayer.getId()}${(selectedLayer as IVectorLayer).showJoinEditor()}` + : selectedLayer.getId(); + } return { - key: selectedLayer ? `${selectedLayer.getId()}${selectedLayer.showJoinEditor()}` : '', + key, selectedLayer, }; } diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.test.tsx b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.test.tsx index 27a345cdf2dda..6da05ef0b4092 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { ILayer } from '../../../classes/layers/layer'; +import { IVectorLayer } from '../../../classes/layers/vector_layer'; import { JoinEditor } from './join_editor'; import { shallow } from 'enzyme'; import { JoinDescriptor } from '../../../../common/descriptor_types'; @@ -48,7 +48,7 @@ const defaultProps = { test('Should render join editor', () => { const component = shallow( - + ); expect(component).toMatchSnapshot(); }); @@ -57,7 +57,7 @@ test('Should render callout when joins are disabled', () => { const component = shallow( ); expect(component).toMatchSnapshot(); diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.tsx b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.tsx index e0d630994566d..e99ec6a688092 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.tsx +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/join_editor/join_editor.tsx @@ -20,7 +20,7 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { Join } from './resources/join'; -import { ILayer } from '../../../classes/layers/layer'; +import { IVectorLayer } from '../../../classes/layers/vector_layer'; import { JoinDescriptor } from '../../../../common/descriptor_types'; import { SOURCE_TYPES } from '../../../../common/constants'; @@ -31,10 +31,10 @@ export interface JoinField { export interface Props { joins: JoinDescriptor[]; - layer: ILayer; + layer: IVectorLayer; layerDisplayName: string; leftJoinFields: JoinField[]; - onChange: (layer: ILayer, joins: JoinDescriptor[]) => void; + onChange: (layer: IVectorLayer, joins: JoinDescriptor[]) => void; } export function JoinEditor({ joins, layer, onChange, leftJoinFields, layerDisplayName }: Props) { diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx index 3567501455734..c2ad75d9cb335 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx @@ -35,7 +35,7 @@ import { TooltipPopover } from './tooltip_popover'; import { FeatureGeometryFilterForm } from './features_tooltip'; import { EXCLUDE_TOO_MANY_FEATURES_BOX } from '../../../classes/util/mb_filter_expressions'; import { ILayer } from '../../../classes/layers/layer'; -import { IVectorLayer } from '../../../classes/layers/vector_layer'; +import { IVectorLayer, isVectorLayer } from '../../../classes/layers/vector_layer'; import { RenderToolTipContent } from '../../../classes/tooltips/tooltip_property'; function justifyAnchorLocation( @@ -58,10 +58,6 @@ function justifyAnchorLocation( return popupAnchorLocation; } -function isVectorLayer(layer: ILayer) { - return (layer as IVectorLayer).canShowTooltip !== undefined; -} - export interface Props { addFilters: ((filters: Filter[], actionId: string) => Promise) | null; closeOnClickTooltip: (tooltipId: string) => void; diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/__snapshots__/toc_entry.test.tsx.snap b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/__snapshots__/toc_entry.test.tsx.snap index 42618d099ffcf..5beaf12029d2f 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/__snapshots__/toc_entry.test.tsx.snap +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/__snapshots__/toc_entry.test.tsx.snap @@ -24,10 +24,11 @@ exports[`TOCEntry is rendered 1`] = ` "isVisible": [Function], "renderLegendDetails": [Function], "showAtZoomLevel": [Function], + "supportsFitToBounds": [Function], } } openLayerSettings={[Function]} - supportsFitToBounds={false} + supportsFitToBounds={true} />
    +
    +
    +
    +
    + { return true; }, + supportsFitToBounds: () => { + return true; + }, } as unknown as ILayer; const defaultProps = { diff --git a/x-pack/plugins/maps/public/index.ts b/x-pack/plugins/maps/public/index.ts index 29cc20c706296..19850e004e6b8 100644 --- a/x-pack/plugins/maps/public/index.ts +++ b/x-pack/plugins/maps/public/index.ts @@ -18,11 +18,26 @@ export const plugin: PluginInitializer = ( }; export { MAP_SAVED_OBJECT_TYPE } from '../common/constants'; +export type { PreIndexedShape } from '../common/elasticsearch_util'; -export type { RenderTooltipContentParams } from './classes/tooltips/tooltip_property'; +export type { + ITooltipProperty, + RenderTooltipContentParams, +} from './classes/tooltips/tooltip_property'; -export { MapsStartApi } from './api'; +export type { MapsSetupApi, MapsStartApi } from './api'; export type { MapEmbeddable, MapEmbeddableInput, MapEmbeddableOutput } from './embeddable'; export type { EMSTermJoinConfig, SampleValuesConfig } from './ems_autosuggest'; + +export type { IVectorSource, GeoJsonWithMeta } from './classes/sources/vector_source/vector_source'; +export type { ImmutableSourceProperty, SourceEditorArgs } from './classes/sources/source'; +export type { Attribution } from '../common/descriptor_types'; +export type { + BoundsRequestMeta, + SourceTooltipConfig, +} from './classes/sources/vector_source/vector_source'; +export type { IField } from './classes/fields/field'; +export type { LayerWizard, RenderWizardArguments } from './classes/layers/layer_wizard_registry'; +export type { DataRequest } from './classes/util/data_request'; diff --git a/x-pack/plugins/maps/public/plugin.ts b/x-pack/plugins/maps/public/plugin.ts index 784f4e8f4b9d9..8f6e74adfc2fd 100644 --- a/x-pack/plugins/maps/public/plugin.ts +++ b/x-pack/plugins/maps/public/plugin.ts @@ -51,6 +51,7 @@ import { createLayerDescriptors, registerLayerWizard, registerSource, + MapsSetupApi, MapsStartApi, suggestEMSTermJoinConfig, } from './api'; @@ -138,7 +139,7 @@ export class MapsPlugin this._initializerContext = initializerContext; } - public setup(core: CoreSetup, plugins: MapsPluginSetupDependencies) { + public setup(core: CoreSetup, plugins: MapsPluginSetupDependencies): MapsSetupApi { registerLicensedFeatures(plugins.licensing); const config = this._initializerContext.config.get(); @@ -194,6 +195,11 @@ export class MapsPlugin plugins.expressions.registerFunction(createTileMapFn); plugins.expressions.registerRenderer(tileMapRenderer); plugins.visualizations.createBaseVisualization(tileMapVisType); + + return { + registerLayerWizard, + registerSource, + }; } public start(core: CoreStart, plugins: MapsPluginStartDependencies): MapsStartApi { @@ -211,8 +217,6 @@ export class MapsPlugin return { createLayerDescriptors, - registerLayerWizard, - registerSource, suggestEMSTermJoinConfig, }; } diff --git a/x-pack/plugins/maps/server/index.ts b/x-pack/plugins/maps/server/index.ts index b57f9ec9c29b1..603273efe0d95 100644 --- a/x-pack/plugins/maps/server/index.ts +++ b/x-pack/plugins/maps/server/index.ts @@ -22,7 +22,8 @@ export const config: PluginConfigDescriptor = { preserveDrawingBuffer: true, }, schema: configSchema, - deprecations: () => [ + deprecations: ({ deprecate }) => [ + deprecate('enabled', '8.0.0'), ( completeConfig: Record, rootPath: string, diff --git a/x-pack/plugins/maps/server/maps_telemetry/util.ts b/x-pack/plugins/maps/server/maps_telemetry/util.ts index ff9339fca76cb..27190c9b82142 100644 --- a/x-pack/plugins/maps/server/maps_telemetry/util.ts +++ b/x-pack/plugins/maps/server/maps_telemetry/util.ts @@ -10,6 +10,7 @@ import { ESGeoGridSourceDescriptor, ESSearchSourceDescriptor, LayerDescriptor, + VectorLayerDescriptor, } from '../../common/descriptor_types'; import { GRID_RESOLUTION, @@ -265,8 +266,7 @@ export function getTermJoinsPerCluster( ): TELEMETRY_TERM_JOIN_COUNTS_PER_CLUSTER { return getCountsByCluster(layerLists, (layerDescriptor: LayerDescriptor) => { return layerDescriptor.type === LAYER_TYPE.VECTOR && - layerDescriptor.joins && - layerDescriptor.joins.length + (layerDescriptor as VectorLayerDescriptor)?.joins?.length ? TELEMETRY_TERM_JOIN : null; }); diff --git a/x-pack/plugins/maps/server/tutorials/ems/index.ts b/x-pack/plugins/maps/server/tutorials/ems/index.ts index 3c63850f87291..94da7c6258faa 100644 --- a/x-pack/plugins/maps/server/tutorials/ems/index.ts +++ b/x-pack/plugins/maps/server/tutorials/ems/index.ts @@ -78,5 +78,6 @@ Indexing EMS administrative boundaries in Elasticsearch allows for search on bou previewImagePath: '/plugins/maps/assets/boundaries_screenshot.png', onPrem: instructions, elasticCloud: instructions, + integrationBrowserCategories: ['upload_file'], }); } diff --git a/x-pack/plugins/metrics_entities/server/index.ts b/x-pack/plugins/metrics_entities/server/index.ts index b4d35eb90f486..c8f9d81347bdb 100644 --- a/x-pack/plugins/metrics_entities/server/index.ts +++ b/x-pack/plugins/metrics_entities/server/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginInitializerContext } from '../../../../src/core/server'; +import { PluginConfigDescriptor, PluginInitializerContext } from '../../../../src/core/server'; import { ConfigSchema } from './config'; import { MetricsEntitiesPlugin } from './plugin'; @@ -13,7 +13,10 @@ import { MetricsEntitiesPlugin } from './plugin'; // This exports static code and TypeScript types, // as well as, Kibana Platform `plugin()` initializer. -export const config = { schema: ConfigSchema }; +export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], + schema: ConfigSchema, +}; export const plugin = (initializerContext: PluginInitializerContext): MetricsEntitiesPlugin => { return new MetricsEntitiesPlugin(initializerContext); }; diff --git a/x-pack/plugins/ml/public/application/components/validate_job/validate_job_view.test.js b/x-pack/plugins/ml/public/application/components/validate_job/validate_job_view.test.js index 067b03d938ee8..8ec83d8679e87 100644 --- a/x-pack/plugins/ml/public/application/components/validate_job/validate_job_view.test.js +++ b/x-pack/plugins/ml/public/application/components/validate_job/validate_job_view.test.js @@ -41,7 +41,7 @@ function prepareTest(messages) { }; const kibana = { services: { - notifications: { toasts: { addDanger: jest.fn() } }, + notifications: { toasts: { addDanger: jest.fn(), addError: jest.fn() } }, }, }; diff --git a/x-pack/plugins/ml/public/application/explorer/anomalies_map.tsx b/x-pack/plugins/ml/public/application/explorer/anomalies_map.tsx index 182a8a37fadfc..28f346c0148c6 100644 --- a/x-pack/plugins/ml/public/application/explorer/anomalies_map.tsx +++ b/x-pack/plugins/ml/public/application/explorer/anomalies_map.tsx @@ -18,6 +18,7 @@ import { } from '@elastic/eui'; import { FIELD_ORIGIN, + LAYER_TYPE, SOURCE_TYPES, STYLE_TYPE, COLOR_MAP_TYPE, @@ -125,7 +126,7 @@ export const getChoroplethAnomaliesLayer = ( isTimeAware: true, }, visible: false, - type: 'VECTOR', + type: LAYER_TYPE.VECTOR, }; }; diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js index c714b388c826f..ddb46edc7b921 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js @@ -79,8 +79,12 @@ function ExplorerChartContainer({ let isCancelled = false; const generateLink = async () => { if (!isCancelled && series.functionDescription !== ML_JOB_AGGREGATION.LAT_LONG) { - const singleMetricViewerLink = await getExploreSeriesLink(mlLocator, series, timefilter); - setExplorerSeriesLink(singleMetricViewerLink); + try { + const singleMetricViewerLink = await getExploreSeriesLink(mlLocator, series, timefilter); + setExplorerSeriesLink(singleMetricViewerLink); + } catch (error) { + setExplorerSeriesLink(''); + } } }; generateLink(); diff --git a/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.test.ts b/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.test.ts index fbe0ff650cc2d..6ffb74131bf6e 100644 --- a/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.test.ts +++ b/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.test.ts @@ -12,6 +12,10 @@ import { BucketSpanEstimatorData } from '../../../common/types/job_service'; import { estimateBucketSpanFactory } from './bucket_span_estimator'; +jest.mock('../../lib/log', () => ({ + mlLog: { warn: jest.fn() }, +})); + const callAs = { search: () => Promise.resolve({ body: {} }), cluster: { getSettings: () => Promise.resolve({ body: {} }) }, diff --git a/x-pack/plugins/monitoring/server/lib/ccs_utils.test.js b/x-pack/plugins/monitoring/common/ccs_utils.test.js similarity index 100% rename from x-pack/plugins/monitoring/server/lib/ccs_utils.test.js rename to x-pack/plugins/monitoring/common/ccs_utils.test.js diff --git a/x-pack/plugins/monitoring/server/lib/ccs_utils.ts b/x-pack/plugins/monitoring/common/ccs_utils.ts similarity index 96% rename from x-pack/plugins/monitoring/server/lib/ccs_utils.ts rename to x-pack/plugins/monitoring/common/ccs_utils.ts index 1d899456913b9..7efe6e43ddbbd 100644 --- a/x-pack/plugins/monitoring/server/lib/ccs_utils.ts +++ b/x-pack/plugins/monitoring/common/ccs_utils.ts @@ -6,7 +6,8 @@ */ import { isFunction, get } from 'lodash'; -import type { MonitoringConfig } from '../config'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import type { MonitoringConfig } from '../server/config'; type Config = Partial & { get?: (key: string) => any; diff --git a/x-pack/plugins/monitoring/common/types/alerts.ts b/x-pack/plugins/monitoring/common/types/alerts.ts index 17bbffce19a18..1f68b0c55a046 100644 --- a/x-pack/plugins/monitoring/common/types/alerts.ts +++ b/x-pack/plugins/monitoring/common/types/alerts.ts @@ -48,12 +48,16 @@ export interface CommonAlertParams { duration: string; threshold?: number; limit?: string; + filterQuery?: string; + filterQueryText?: string; [key: string]: unknown; } export interface ThreadPoolRejectionsAlertParams { threshold: number; duration: string; + filterQuery?: string; + filterQueryText?: string; } export interface AlertEnableAction { diff --git a/x-pack/plugins/monitoring/common/types/es.ts b/x-pack/plugins/monitoring/common/types/es.ts index a9d020813ce84..a01e1c383a8e6 100644 --- a/x-pack/plugins/monitoring/common/types/es.ts +++ b/x-pack/plugins/monitoring/common/types/es.ts @@ -156,7 +156,7 @@ export interface ElasticsearchLegacySource { heap_max_in_bytes?: number; }; }; - fs: { + fs?: { available_in_bytes?: number; total_in_bytes?: number; }; @@ -497,7 +497,7 @@ export interface ElasticsearchMetricbeatSource { }; nodes?: { versions?: string[]; - count?: number; + count?: number | {}; jvm?: { max_uptime?: { ms?: number; diff --git a/x-pack/plugins/monitoring/public/alerts/ccr_read_exceptions_alert/index.tsx b/x-pack/plugins/monitoring/public/alerts/ccr_read_exceptions_alert/index.tsx index 1de9a175026a6..64eab04cbd5ce 100644 --- a/x-pack/plugins/monitoring/public/alerts/ccr_read_exceptions_alert/index.tsx +++ b/x-pack/plugins/monitoring/public/alerts/ccr_read_exceptions_alert/index.tsx @@ -15,6 +15,7 @@ import { RULE_REQUIRES_APP_CONTEXT, } from '../../../common/constants'; import { AlertTypeParams } from '../../../../alerting/common'; +import { MonitoringConfig } from '../../types'; interface ValidateOptions extends AlertTypeParams { duration: string; @@ -36,7 +37,9 @@ const validate = (inputValues: ValidateOptions): ValidationResult => { return validationResult; }; -export function createCCRReadExceptionsAlertType(): AlertTypeModel { +export function createCCRReadExceptionsAlertType( + config: MonitoringConfig +): AlertTypeModel { return { id: RULE_CCR_READ_EXCEPTIONS, description: RULE_DETAILS[RULE_CCR_READ_EXCEPTIONS].description, @@ -45,7 +48,11 @@ export function createCCRReadExceptionsAlertType(): AlertTypeModel ( - + ), validate, defaultActionMessage: '{{context.internalFullMessage}}', diff --git a/x-pack/plugins/monitoring/public/alerts/components/param_details_form/expression.tsx b/x-pack/plugins/monitoring/public/alerts/components/param_details_form/expression.tsx index df17ce1a911a0..827eed955d535 100644 --- a/x-pack/plugins/monitoring/public/alerts/components/param_details_form/expression.tsx +++ b/x-pack/plugins/monitoring/public/alerts/components/param_details_form/expression.tsx @@ -5,14 +5,23 @@ * 2.0. */ -import React, { Fragment } from 'react'; -import { EuiForm, EuiSpacer } from '@elastic/eui'; +import React, { Fragment, useCallback } from 'react'; +import { EuiForm, EuiFormRow, EuiSpacer } from '@elastic/eui'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { debounce } from 'lodash'; +import { i18n } from '@kbn/i18n'; import { CommonAlertParamDetails } from '../../../../common/types/alerts'; import { AlertParamDuration } from '../../flyout_expressions/alert_param_duration'; import { AlertParamType } from '../../../../common/enums'; import { AlertParamPercentage } from '../../flyout_expressions/alert_param_percentage'; import { AlertParamNumber } from '../../flyout_expressions/alert_param_number'; import { AlertParamTextField } from '../../flyout_expressions/alert_param_textfield'; +import { MonitoringConfig } from '../../../types'; +import { useDerivedIndexPattern } from './use_derived_index_pattern'; +import { KueryBar } from '../../../components/kuery_bar'; +import { convertKueryToElasticSearchQuery } from '../../../lib/kuery'; + +const FILTER_TYPING_DEBOUNCE_MS = 500; export interface Props { alertParams: { [property: string]: any }; @@ -20,10 +29,14 @@ export interface Props { setAlertProperty: (property: string, value: any) => void; errors: { [key: string]: string[] }; paramDetails: CommonAlertParamDetails; + data: DataPublicPluginStart; + config?: MonitoringConfig; } export const Expression: React.FC = (props) => { - const { alertParams, paramDetails, setAlertParams, errors } = props; + const { alertParams, paramDetails, setAlertParams, errors, config, data } = props; + + const { derivedIndexPattern } = useDerivedIndexPattern(data, config); const alertParamsUi = Object.keys(paramDetails).map((alertParamName) => { const details = paramDetails[alertParamName]; @@ -77,10 +90,44 @@ export const Expression: React.FC = (props) => { } }); + const onFilterChange = useCallback( + (filter: string) => { + setAlertParams('filterQueryText', filter); + setAlertParams( + 'filterQuery', + convertKueryToElasticSearchQuery(filter, derivedIndexPattern) || '' + ); + }, + [setAlertParams, derivedIndexPattern] + ); + + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const debouncedOnFilterChange = useCallback(debounce(onFilterChange, FILTER_TYPING_DEBOUNCE_MS), [ + onFilterChange, + ]); + return ( - {alertParamsUi} - + + {alertParamsUi} + + + + + + ); }; diff --git a/x-pack/plugins/monitoring/public/alerts/components/param_details_form/use_derived_index_pattern.tsx b/x-pack/plugins/monitoring/public/alerts/components/param_details_form/use_derived_index_pattern.tsx new file mode 100644 index 0000000000000..1a4d88d690b84 --- /dev/null +++ b/x-pack/plugins/monitoring/public/alerts/components/param_details_form/use_derived_index_pattern.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useState } from 'react'; +import { DataPublicPluginStart, IFieldType, IIndexPattern } from 'src/plugins/data/public'; +import { + INDEX_PATTERN_BEATS, + INDEX_PATTERN_ELASTICSEARCH, + INDEX_PATTERN_KIBANA, + INDEX_PATTERN_LOGSTASH, +} from '../../../../common/constants'; +import { prefixIndexPattern } from '../../../../common/ccs_utils'; +import { MonitoringConfig } from '../../../types'; + +const INDEX_PATTERNS = `${INDEX_PATTERN_ELASTICSEARCH},${INDEX_PATTERN_KIBANA},${INDEX_PATTERN_LOGSTASH},${INDEX_PATTERN_BEATS}`; + +export const useDerivedIndexPattern = ( + data: DataPublicPluginStart, + config?: MonitoringConfig +): { loading: boolean; derivedIndexPattern: IIndexPattern } => { + const indexPattern = prefixIndexPattern(config || ({} as MonitoringConfig), INDEX_PATTERNS, '*'); + const [loading, setLoading] = useState(true); + const [fields, setFields] = useState([]); + useEffect(() => { + (async function fetchData() { + const result = await data.indexPatterns.getFieldsForWildcard({ + pattern: indexPattern, + }); + setFields(result); + setLoading(false); + })(); + }, [indexPattern, data.indexPatterns]); + return { + loading, + derivedIndexPattern: { + title: indexPattern, + fields, + }, + }; +}; diff --git a/x-pack/plugins/monitoring/public/alerts/cpu_usage_alert/cpu_usage_alert.tsx b/x-pack/plugins/monitoring/public/alerts/cpu_usage_alert/cpu_usage_alert.tsx index ec7a583ec2ba1..f0e0a413435f9 100644 --- a/x-pack/plugins/monitoring/public/alerts/cpu_usage_alert/cpu_usage_alert.tsx +++ b/x-pack/plugins/monitoring/public/alerts/cpu_usage_alert/cpu_usage_alert.tsx @@ -11,8 +11,11 @@ import { AlertTypeModel } from '../../../../triggers_actions_ui/public/types'; import { RULE_CPU_USAGE, RULE_DETAILS, RULE_REQUIRES_APP_CONTEXT } from '../../../common/constants'; import { validate, MonitoringAlertTypeParams } from '../components/param_details_form/validation'; import { Expression, Props } from '../components/param_details_form/expression'; +import { MonitoringConfig } from '../../types'; -export function createCpuUsageAlertType(): AlertTypeModel { +export function createCpuUsageAlertType( + config: MonitoringConfig +): AlertTypeModel { return { id: RULE_CPU_USAGE, description: RULE_DETAILS[RULE_CPU_USAGE].description, @@ -21,7 +24,11 @@ export function createCpuUsageAlertType(): AlertTypeModel ( - + ), validate, defaultActionMessage: '{{context.internalFullMessage}}', diff --git a/x-pack/plugins/monitoring/public/alerts/disk_usage_alert/index.tsx b/x-pack/plugins/monitoring/public/alerts/disk_usage_alert/index.tsx index 779945da0c9e0..5f9f9536ae567 100644 --- a/x-pack/plugins/monitoring/public/alerts/disk_usage_alert/index.tsx +++ b/x-pack/plugins/monitoring/public/alerts/disk_usage_alert/index.tsx @@ -16,8 +16,11 @@ import { RULE_DETAILS, RULE_REQUIRES_APP_CONTEXT, } from '../../../common/constants'; +import { MonitoringConfig } from '../../types'; -export function createDiskUsageAlertType(): AlertTypeModel { +export function createDiskUsageAlertType( + config: MonitoringConfig +): AlertTypeModel { return { id: RULE_DISK_USAGE, description: RULE_DETAILS[RULE_DISK_USAGE].description, @@ -26,7 +29,11 @@ export function createDiskUsageAlertType(): AlertTypeModel ( - + ), validate, defaultActionMessage: '{{context.internalFullMessage}}', diff --git a/x-pack/plugins/monitoring/public/alerts/large_shard_size_alert/index.tsx b/x-pack/plugins/monitoring/public/alerts/large_shard_size_alert/index.tsx index e0f595abe7602..afaf20d60d882 100644 --- a/x-pack/plugins/monitoring/public/alerts/large_shard_size_alert/index.tsx +++ b/x-pack/plugins/monitoring/public/alerts/large_shard_size_alert/index.tsx @@ -15,6 +15,7 @@ import { RULE_REQUIRES_APP_CONTEXT, } from '../../../common/constants'; import { AlertTypeParams } from '../../../../alerting/common'; +import { MonitoringConfig } from '../../types'; interface ValidateOptions extends AlertTypeParams { indexPattern: string; @@ -36,7 +37,9 @@ const validate = (inputValues: ValidateOptions): ValidationResult => { return validationResult; }; -export function createLargeShardSizeAlertType(): AlertTypeModel { +export function createLargeShardSizeAlertType( + config: MonitoringConfig +): AlertTypeModel { return { id: RULE_LARGE_SHARD_SIZE, description: RULE_DETAILS[RULE_LARGE_SHARD_SIZE].description, @@ -45,7 +48,11 @@ export function createLargeShardSizeAlertType(): AlertTypeModel return `${docLinks.links.monitoring.alertsKibanaLargeShardSize}`; }, alertParamsExpression: (props: Props) => ( - + ), validate, defaultActionMessage: '{{context.internalFullMessage}}', diff --git a/x-pack/plugins/monitoring/public/alerts/legacy_alert/expression.tsx b/x-pack/plugins/monitoring/public/alerts/legacy_alert/expression.tsx new file mode 100644 index 0000000000000..fe6adf66c1d4f --- /dev/null +++ b/x-pack/plugins/monitoring/public/alerts/legacy_alert/expression.tsx @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useCallback } from 'react'; +import { debounce } from 'lodash'; +import { EuiSpacer, EuiForm, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useDerivedIndexPattern } from '../components/param_details_form/use_derived_index_pattern'; +import { convertKueryToElasticSearchQuery } from '../../lib/kuery'; +import { KueryBar } from '../../components/kuery_bar'; +import { Props } from '../components/param_details_form/expression'; + +const FILTER_TYPING_DEBOUNCE_MS = 500; + +export const Expression = ({ alertParams, config, setAlertParams, data }: Props) => { + const { derivedIndexPattern } = useDerivedIndexPattern(data, config); + const onFilterChange = useCallback( + (filter: string) => { + setAlertParams('filterQueryText', filter); + setAlertParams( + 'filterQuery', + convertKueryToElasticSearchQuery(filter, derivedIndexPattern) || '' + ); + }, + [setAlertParams, derivedIndexPattern] + ); + + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const debouncedOnFilterChange = useCallback(debounce(onFilterChange, FILTER_TYPING_DEBOUNCE_MS), [ + onFilterChange, + ]); + return ( + + + + + + + ); +}; diff --git a/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx b/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx index cac4873bc0c79..a6c22035c5a5a 100644 --- a/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx +++ b/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx @@ -5,9 +5,7 @@ * 2.0. */ -import React, { Fragment } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiTextColor, EuiSpacer } from '@elastic/eui'; +import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { AlertTypeModel } from '../../../../triggers_actions_ui/public/types'; import { @@ -15,8 +13,11 @@ import { LEGACY_RULE_DETAILS, RULE_REQUIRES_APP_CONTEXT, } from '../../../common/constants'; +import { MonitoringConfig } from '../../types'; +import { Expression } from './expression'; +import { Props } from '../components/param_details_form/expression'; -export function createLegacyAlertTypes(): AlertTypeModel[] { +export function createLegacyAlertTypes(config: MonitoringConfig): AlertTypeModel[] { return LEGACY_RULES.map((legacyAlert) => { return { id: legacyAlert, @@ -25,17 +26,7 @@ export function createLegacyAlertTypes(): AlertTypeModel[] { documentationUrl(docLinks) { return `${docLinks.links.monitoring.alertsKibanaClusterAlerts}`; }, - alertParamsExpression: () => ( - - - - {i18n.translate('xpack.monitoring.alerts.legacyAlert.expressionText', { - defaultMessage: 'There is nothing to configure.', - })} - - - - ), + alertParamsExpression: (props: Props) => , defaultActionMessage: '{{context.internalFullMessage}}', validate: () => ({ errors: {} }), requiresAppContext: RULE_REQUIRES_APP_CONTEXT, diff --git a/x-pack/plugins/monitoring/public/alerts/memory_usage_alert/index.tsx b/x-pack/plugins/monitoring/public/alerts/memory_usage_alert/index.tsx index 3e55b6d5454ff..2fe0c9b77c0eb 100644 --- a/x-pack/plugins/monitoring/public/alerts/memory_usage_alert/index.tsx +++ b/x-pack/plugins/monitoring/public/alerts/memory_usage_alert/index.tsx @@ -16,8 +16,11 @@ import { RULE_DETAILS, RULE_REQUIRES_APP_CONTEXT, } from '../../../common/constants'; +import { MonitoringConfig } from '../../types'; -export function createMemoryUsageAlertType(): AlertTypeModel { +export function createMemoryUsageAlertType( + config: MonitoringConfig +): AlertTypeModel { return { id: RULE_MEMORY_USAGE, description: RULE_DETAILS[RULE_MEMORY_USAGE].description, @@ -26,7 +29,11 @@ export function createMemoryUsageAlertType(): AlertTypeModel ( - + ), validate, defaultActionMessage: '{{context.internalFullMessage}}', diff --git a/x-pack/plugins/monitoring/public/alerts/thread_pool_rejections_alert/index.tsx b/x-pack/plugins/monitoring/public/alerts/thread_pool_rejections_alert/index.tsx index 7fd9438e1cea3..e8a15ad835581 100644 --- a/x-pack/plugins/monitoring/public/alerts/thread_pool_rejections_alert/index.tsx +++ b/x-pack/plugins/monitoring/public/alerts/thread_pool_rejections_alert/index.tsx @@ -13,6 +13,7 @@ import { Expression, Props } from '../components/param_details_form/expression'; import { AlertTypeModel } from '../../../../triggers_actions_ui/public/types'; import { CommonAlertParamDetails } from '../../../common/types/alerts'; import { RULE_REQUIRES_APP_CONTEXT } from '../../../common/constants'; +import { MonitoringConfig } from '../../types'; interface ThreadPoolTypes { [key: string]: unknown; @@ -26,7 +27,8 @@ interface ThreadPoolRejectionAlertDetails { export function createThreadPoolRejectionsAlertType( alertId: string, - threadPoolAlertDetails: ThreadPoolRejectionAlertDetails + threadPoolAlertDetails: ThreadPoolRejectionAlertDetails, + config: MonitoringConfig ): AlertTypeModel { return { id: alertId, @@ -38,7 +40,7 @@ export function createThreadPoolRejectionsAlertType( alertParamsExpression: (props: Props) => ( <> - + ), validate: (inputValues: ThreadPoolTypes) => { diff --git a/x-pack/plugins/monitoring/public/application/hooks/use_table.ts b/x-pack/plugins/monitoring/public/application/hooks/use_table.ts new file mode 100644 index 0000000000000..60264f3657fe3 --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/hooks/use_table.ts @@ -0,0 +1,162 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useState, useCallback } from 'react'; +import { EUI_SORT_ASCENDING } from '../../../common/constants'; +import { euiTableStorageGetter, euiTableStorageSetter } from '../../components/table'; +import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; + +interface Pagination { + pageSize: number; + initialPageSize: number; + pageIndex: number; + initialPageIndex: number; + pageSizeOptions: number[]; + totalItemCount: number; +} + +interface Page { + size: number; + index: number; +} + +interface Sorting { + sort: { + field: string; + direction: string; + }; +} + +const PAGE_SIZE_OPTIONS = [5, 10, 20, 50]; + +const DEFAULT_PAGINATION = { + pageSize: 20, + initialPageSize: 20, + pageIndex: 0, + initialPageIndex: 0, + pageSizeOptions: PAGE_SIZE_OPTIONS, + totalItemCount: 0, +}; + +const getPaginationInitialState = (page: Page | undefined) => { + const pagination = DEFAULT_PAGINATION; + + if (page) { + pagination.initialPageSize = page.size; + pagination.pageSize = page.size; + pagination.initialPageIndex = page.index; + pagination.pageIndex = page.index; + } + + return { + ...pagination, + pageSizeOptions: PAGE_SIZE_OPTIONS, + }; +}; + +export function useTable(storageKey: string) { + const storage = new Storage(window.localStorage); + const getLocalStorageData = euiTableStorageGetter(storageKey); + const setLocalStorageData = euiTableStorageSetter(storageKey); + + const storageData = getLocalStorageData(storage); + // get initial state from localstorage + const [pagination, setPagination] = useState( + getPaginationInitialState(storageData.page) + ); + + const updateTotalItemCount = useCallback( + (num) => { + // only update pagination state if different + if (num === pagination.totalItemCount) return; + setPagination({ + ...pagination, + totalItemCount: num, + }); + }, + [setPagination, pagination] + ); + + // get initial state from localStorage + const [sorting, setSorting] = useState(storageData.sort || { sort: {} }); + const cleanSortingData = (sortData: Sorting) => { + const sort = sortData || { sort: {} }; + + if (!sort.sort.field) { + sort.sort.field = 'name'; + } + if (!sort.sort.direction) { + sort.sort.direction = EUI_SORT_ASCENDING; + } + + return sort; + }; + + const [query, setQuery] = useState(''); + + const onTableChange = () => { + // we are already updating the state in fetchMoreData. We would need to check in react + // if both methods are needed or we can clean one of them + // For now I just keep it so existing react components don't break + }; + + const getPaginationRouteOptions = useCallback(() => { + if (!pagination || !sorting) { + return {}; + } + + return { + pagination: { + size: pagination.pageSize, + index: pagination.pageIndex, + }, + ...sorting, + queryText: query, + }; + }, [pagination, query, sorting]); + + const getPaginationTableProps = () => { + return { + sorting, + pagination, + onTableChange, + fetchMoreData: ({ + page, + sort, + queryText, + }: { + page: Page; + sort: Sorting; + queryText: string; + }) => { + setPagination({ + ...pagination, + ...{ + initialPageSize: page.size, + pageSize: page.size, + initialPageIndex: page.index, + pageIndex: page.index, + pageSizeOptions: PAGE_SIZE_OPTIONS, + }, + }); + setSorting(cleanSortingData(sort)); + setQuery(queryText); + + setLocalStorageData(storage, { + page, + sort, + }); + }, + }; + }; + + return { + getPaginationRouteOptions, + getPaginationTableProps, + updateTotalItemCount, + }; +} diff --git a/x-pack/plugins/monitoring/public/application/index.tsx b/x-pack/plugins/monitoring/public/application/index.tsx index 6db9343035237..85dc5286efa42 100644 --- a/x-pack/plugins/monitoring/public/application/index.tsx +++ b/x-pack/plugins/monitoring/public/application/index.tsx @@ -18,8 +18,11 @@ import { GlobalStateProvider } from './global_state_context'; import { ExternalConfigContext, ExternalConfig } from './external_config_context'; import { createPreserveQueryHistory } from './preserve_query_history'; import { RouteInit } from './route_init'; +import { NoDataPage } from './pages/no_data'; import { ElasticsearchOverviewPage } from './pages/elasticsearch/overview'; -import { CODE_PATH_ELASTICSEARCH } from '../../common/constants'; +import { BeatsOverviewPage } from './pages/beats/overview'; +import { CODE_PATH_ELASTICSEARCH, CODE_PATH_BEATS } from '../../common/constants'; +import { ElasticsearchNodesPage } from './pages/elasticsearch/nodes_page'; import { MonitoringTimeContainer } from './hooks/use_monitoring_time'; import { BreadcrumbContainer } from './hooks/use_breadcrumbs'; @@ -54,7 +57,7 @@ const MonitoringApp: React.FC<{ - + {/* ElasticSearch Views */} + + + + {/* Beats Views */} + + = () => { - return
    No data page
    ; -}; - const Home: React.FC<{}> = () => { return
    Home page (Cluster listing)
    ; }; diff --git a/x-pack/plugins/monitoring/public/application/pages/beats/beats_template.tsx b/x-pack/plugins/monitoring/public/application/pages/beats/beats_template.tsx new file mode 100644 index 0000000000000..90df1b49aa5d7 --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/beats/beats_template.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { PageTemplate } from '../page_template'; +import { TabMenuItem, PageTemplateProps } from '../page_template'; + +interface BeatsTemplateProps extends PageTemplateProps { + cluster: any; +} + +export const BeatsTemplate: React.FC = ({ cluster, ...props }) => { + const tabs: TabMenuItem[] = [ + { + id: 'overview', + label: i18n.translate('xpack.monitoring.beatsNavigation.overviewLinkText', { + defaultMessage: 'Overview', + }), + route: '/beats', + }, + { + id: 'instances', + label: i18n.translate('xpack.monitoring.beatsNavigation.instancesLinkText', { + defaultMessage: 'Instances', + }), + route: '/beats/beats', + }, + ]; + + return ; +}; diff --git a/x-pack/plugins/monitoring/public/application/pages/beats/overview.tsx b/x-pack/plugins/monitoring/public/application/pages/beats/overview.tsx new file mode 100644 index 0000000000000..3efad7b82549c --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/beats/overview.tsx @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useContext, useState, useCallback, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { find } from 'lodash'; +import { ComponentProps } from '../../route_init'; +import { BeatsTemplate } from './beats_template'; +import { GlobalStateContext } from '../../global_state_context'; +import { useCharts } from '../../hooks/use_charts'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +// @ts-ignore +import { BeatsOverview } from '../../../components/beats/overview'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; + +export const BeatsOverviewPage: React.FC = ({ clusters }) => { + const globalState = useContext(GlobalStateContext); + const { zoomInfo, onBrush } = useCharts(); + const { services } = useKibana<{ data: any }>(); + const clusterUuid = globalState.cluster_uuid; + const ccs = globalState.ccs; + const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context); + const cluster = find(clusters, { + cluster_uuid: clusterUuid, + }) as any; + + const [data, setData] = useState(null); + + const title = i18n.translate('xpack.monitoring.beats.overview.routeTitle', { + defaultMessage: 'Beats - Overview', + }); + + const pageTitle = i18n.translate('xpack.monitoring.beats.overview.pageTitle', { + defaultMessage: 'Beats overview', + }); + + useEffect(() => { + if (cluster) { + generateBreadcrumbs(cluster.cluster_name, { + inBeats: true, + }); + } + }, [cluster, generateBreadcrumbs]); + + const getPageData = useCallback(async () => { + const bounds = services.data?.query.timefilter.timefilter.getBounds(); + const url = `../api/monitoring/v1/clusters/${clusterUuid}/beats`; + + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + }), + }); + + setData(response); + }, [ccs, clusterUuid, services.data?.query.timefilter.timefilter, services.http]); + + const renderOverview = (overviewData: any) => { + if (overviewData === null) { + return null; + } + return ; + }; + + return ( + +
    {renderOverview(data)}
    +
    + ); +}; diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/nodes_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/nodes_page.tsx new file mode 100644 index 0000000000000..652fe83231441 --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/nodes_page.tsx @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useContext, useState, useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; +import { find } from 'lodash'; +import { ElasticsearchTemplate } from './elasticsearch_template'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { GlobalStateContext } from '../../global_state_context'; +import { ExternalConfigContext } from '../../external_config_context'; +import { ElasticsearchNodes } from '../../../components/elasticsearch'; +import { ComponentProps } from '../../route_init'; +import { SetupModeRenderer } from '../../setup_mode/setup_mode_renderer'; +import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; +import { useTable } from '../../hooks/use_table'; + +interface SetupModeProps { + setupMode: any; + flyoutComponent: any; + bottomBarComponent: any; +} + +export const ElasticsearchNodesPage: React.FC = ({ clusters }) => { + const globalState = useContext(GlobalStateContext); + const { showCgroupMetricsElasticsearch } = useContext(ExternalConfigContext); + const { services } = useKibana<{ data: any }>(); + const { getPaginationRouteOptions, updateTotalItemCount, getPaginationTableProps } = + useTable('elasticsearch.nodes'); + const clusterUuid = globalState.cluster_uuid; + const ccs = globalState.ccs; + const cluster = find(clusters, { + cluster_uuid: clusterUuid, + }); + const [data, setData] = useState({} as any); + + const title = i18n.translate('xpack.monitoring.elasticsearch.nodes.routeTitle', { + defaultMessage: 'Elasticsearch - Nodes', + }); + + const pageTitle = i18n.translate('xpack.monitoring.elasticsearch.nodes.pageTitle', { + defaultMessage: 'Elasticsearch nodes', + }); + + const getPageData = useCallback(async () => { + const bounds = services.data?.query.timefilter.timefilter.getBounds(); + const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/nodes`; + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + ccs, + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + ...getPaginationRouteOptions(), + }), + }); + + setData(response); + updateTotalItemCount(response.totalNodeCount); + }, [ + ccs, + clusterUuid, + services.data?.query.timefilter.timefilter, + services.http, + getPaginationRouteOptions, + updateTotalItemCount, + ]); + + return ( + +
    + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> +
    +
    + ); +}; diff --git a/x-pack/plugins/monitoring/public/application/pages/no_data/enabler.ts b/x-pack/plugins/monitoring/public/application/pages/no_data/enabler.ts new file mode 100644 index 0000000000000..6225e3863b2f7 --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/no_data/enabler.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// From x-pack/plugins/monitoring/public/lib/elasticsearch_settings/enabler.js +export class Enabler { + http: any; + updateModel: any; + + constructor(http: any, updateModel: (properties: any) => void) { + this.http = http; + this.updateModel = updateModel; + } + + async enableCollectionInterval() { + try { + this.updateModel({ isCollectionIntervalUpdating: true }); + + await this.http.fetch('../api/monitoring/v1/elasticsearch_settings/set/collection_interval', { + method: 'PUT', + }); + this.updateModel({ + isCollectionIntervalUpdated: true, + isCollectionIntervalUpdating: false, + }); + } catch (err) { + this.updateModel({ + errors: (err as any).data, + isCollectionIntervalUpdated: false, + isCollectionIntervalUpdating: false, + }); + } + } + + async enableCollectionEnabled() { + try { + this.updateModel({ isCollectionEnabledUpdating: true }); + await this.http.fetch('../api/monitoring/v1/elasticsearch_settings/set/collection_enabled', { + method: 'PUT', + }); + + this.updateModel({ + isCollectionEnabledUpdated: true, + isCollectionEnabledUpdating: false, + }); + } catch (err) { + this.updateModel({ + errors: (err as any).data, + isCollectionEnabledUpdated: false, + isCollectionEnabledUpdating: false, + }); + } + } +} diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/index.ts b/x-pack/plugins/monitoring/public/application/pages/no_data/index.ts similarity index 70% rename from x-pack/plugins/uptime/public/components/overview/empty_state/index.ts rename to x-pack/plugins/monitoring/public/application/pages/no_data/index.ts index 5ffcc15ed404b..7fa176d0e6adf 100644 --- a/x-pack/plugins/uptime/public/components/overview/empty_state/index.ts +++ b/x-pack/plugins/monitoring/public/application/pages/no_data/index.ts @@ -5,5 +5,4 @@ * 2.0. */ -export { EmptyStateComponent } from './empty_state'; -export { EmptyState } from './empty_state_container'; +export { NoDataPage } from './no_data_page'; diff --git a/x-pack/plugins/monitoring/public/application/pages/no_data/no_data_page.tsx b/x-pack/plugins/monitoring/public/application/pages/no_data/no_data_page.tsx new file mode 100644 index 0000000000000..b05bd783b2ff2 --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/no_data/no_data_page.tsx @@ -0,0 +1,240 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useContext, useState } from 'react'; +import { Redirect } from 'react-router-dom'; + +import { i18n } from '@kbn/i18n'; +// @ts-ignore +import { NoData } from '../../../components/no_data'; +import { PageTemplate } from '../page_template'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { CODE_PATH_LICENSE, STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../../common/constants'; +import { Legacy } from '../../../legacy_shims'; +import { Enabler } from './enabler'; +import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs'; +import { initSetupModeState } from '../../setup_mode/setup_mode'; +import { GlobalStateContext } from '../../global_state_context'; + +const CODE_PATHS = [CODE_PATH_LICENSE]; + +interface NoDataPageSetupDeps { + http: any; + data: any; +} + +interface SettingsChecker { + message: string; + api: string; + next?: SettingsChecker; +} + +const clusterCheckers: SettingsChecker[] = [ + { + message: i18n.translate('xpack.monitoring.noData.checker.clusterSettings', { + defaultMessage: 'Checking cluster settings API on production cluster', + }), + api: '../api/monitoring/v1/elasticsearch_settings/check/cluster', + }, + { + message: i18n.translate('xpack.monitoring.noData.checker.nodesSettings', { + defaultMessage: 'Checking nodes settings API on production cluster', + }), + api: '../api/monitoring/v1/elasticsearch_settings/check/nodes', + }, +]; + +export const NoDataPage = () => { + const title = i18n.translate('xpack.monitoring.noData.routeTitle', { + defaultMessage: 'Setup Monitoring', + }); + + const { services } = useKibana(); + const [shouldRedirect, setShouldRedirect] = useState(false); + + const [model, setModel] = useState({ + errors: [], // errors can happen from trying to check or set ES settings + checkMessage: null, // message to show while waiting for api response + isLoading: true, // flag for in-progress state of checking for no data reason + isCollectionEnabledUpdating: false, // flags to indicate whether to show a spinner while waiting for ajax + isCollectionEnabledUpdated: false, + isCollectionIntervalUpdating: false, + isCollectionIntervalUpdated: false, + } as any); + + const { update: updateBreadcrumbs } = useContext(BreadcrumbContainer.Context); + updateBreadcrumbs([ + { + 'data-test-subj': 'breadcrumbClusters', + text: 'Clusters', + href: '#/home', + ignoreGlobalState: true, + }, + ]); + + const globalState = useContext(GlobalStateContext); + initSetupModeState(globalState, services.http); + + // From x-pack/plugins/monitoring/public/views/no_data/model_updater.js + const updateModel = useCallback( + (properties: any) => { + setModel((previousModel: any) => { + const updated = { ...previousModel }; + const keys = Object.keys(properties); + + keys.forEach((key) => { + if (Array.isArray(updated[key])) { + updated[key].push(properties[key]); + } else { + updated[key] = properties[key]; + } + }); + + return updated; + }); + }, + [setModel] + ); + + const getPageData = useCallback(async () => { + let catchReason; + try { + const clusters = await getClusters(services); + + if (clusters && clusters.length) { + setShouldRedirect(true); + return; + } + } catch (err) { + if (err && err.status === 503) { + catchReason = { + property: 'custom', + message: err.data.message, + }; + } + } + + if (catchReason) { + updateModel({ reason: catchReason }); + } else { + await startChecks(clusterCheckers, services.http, updateModel); + } + }, [services, updateModel]); + + const enabler = new Enabler(services.http, updateModel); + + return ( + + {shouldRedirect ? ( + + ) : ( + + )} + + ); +}; + +async function getClusters(services: NoDataPageSetupDeps): Promise { + const url = '../api/monitoring/v1/clusters'; + const bounds = services.data?.query.timefilter.timefilter.getBounds(); + const min = bounds.min.toISOString(); + const max = bounds.max.toISOString(); + + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + css: undefined, + timeRange: { + min, + max, + }, + codePaths: CODE_PATHS, + }), + }); + + return formatClusters(response); +} + +// From x-pack/plugins/monitoring/public/lib/elasticsearch_settings/start_checks.js +const mapCheckers = (_checkers: SettingsChecker[]) => { + return _checkers.map((current, checkerIndex) => { + const next = _checkers[checkerIndex + 1]; + if (next !== undefined) { + current.next = next; + } + + return current; + }); +}; + +// From x-pack/plugins/monitoring/public/lib/elasticsearch_settings/start_checks.js +function startChecks( + checkers: SettingsChecker[], + http: { fetch: any }, + updateModel: (properties: any) => void +) { + const runCheck = async (currentChecker: SettingsChecker): Promise => { + updateModel({ checkMessage: currentChecker.message }); + + const { found, reason, error, errorReason } = await executeCheck(currentChecker, http); + + if (error) { + updateModel({ errors: errorReason }); + if (currentChecker.next) { + return runCheck(currentChecker.next); + } + } else if (found) { + return updateModel({ + reason, + isLoading: false, + checkMessage: null, + }); + } else if (currentChecker.next) { + return runCheck(currentChecker.next); + } + + // dead end + updateModel({ + reason: null, + isLoading: false, + checkMessage: null, + }); + }; + + const _checkers = mapCheckers(checkers); + return runCheck(_checkers[0]); +} + +async function executeCheck(checker: SettingsChecker, http: { fetch: any }): Promise { + try { + const response = await http.fetch(checker.api, { + method: 'GET', + }); + const { found, reason } = response; + + return { found, reason }; + } catch (err: any) { + const { data } = err; + + return { + error: true, + found: false, + errorReason: data, + }; + } +} + +function formatClusters(clusters: any): any[] { + return clusters.map(formatCluster); +} + +function formatCluster(cluster: any) { + if (cluster.cluster_uuid === STANDALONE_CLUSTER_CLUSTER_UUID) { + cluster.cluster_name = 'Standalone Cluster'; + } + return cluster; +} diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/index.d.ts b/x-pack/plugins/monitoring/public/components/elasticsearch/index.d.ts index 4460b8432134b..615e79a0bf154 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/index.d.ts +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/index.d.ts @@ -6,3 +6,4 @@ */ export const ElasticsearchOverview: FunctionComponent; +export const ElasticsearchNodes: FunctionComponent; diff --git a/x-pack/plugins/monitoring/public/components/kuery_bar/autocomplete_field.tsx b/x-pack/plugins/monitoring/public/components/kuery_bar/autocomplete_field.tsx new file mode 100644 index 0000000000000..522256ea49b98 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/kuery_bar/autocomplete_field.tsx @@ -0,0 +1,316 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiFieldSearch, EuiOutsideClickDetector, EuiPanel } from '@elastic/eui'; +import React from 'react'; +import { QuerySuggestion } from '../../../../../../src/plugins/data/public'; +import { euiStyled } from '../../../../../../src/plugins/kibana_react/common'; +import { composeStateUpdaters } from '../../lib/typed_react'; +import { SuggestionItem } from './suggestion_item'; + +interface AutocompleteFieldProps { + isLoadingSuggestions: boolean; + isValid: boolean; + loadSuggestions: (value: string, cursorPosition: number, maxCount?: number) => void; + onSubmit?: (value: string) => void; + onChange?: (value: string) => void; + placeholder?: string; + suggestions: QuerySuggestion[]; + value: string; + disabled?: boolean; + autoFocus?: boolean; + 'aria-label'?: string; +} + +interface AutocompleteFieldState { + areSuggestionsVisible: boolean; + isFocused: boolean; + selectedIndex: number | null; +} + +export class AutocompleteField extends React.Component< + AutocompleteFieldProps, + AutocompleteFieldState +> { + public readonly state: AutocompleteFieldState = { + areSuggestionsVisible: false, + isFocused: false, + selectedIndex: null, + }; + + private inputElement: HTMLInputElement | null = null; + + public render() { + const { + suggestions, + isLoadingSuggestions, + isValid, + placeholder, + value, + disabled, + 'aria-label': ariaLabel, + } = this.props; + const { areSuggestionsVisible, selectedIndex } = this.state; + + return ( + + + + {areSuggestionsVisible && !isLoadingSuggestions && suggestions.length > 0 ? ( + + {suggestions.map((suggestion, suggestionIndex) => ( + + ))} + + ) : null} + + + ); + } + + public componentDidMount() { + if (this.inputElement && this.props.autoFocus) { + this.inputElement.focus(); + } + } + + public componentDidUpdate(prevProps: AutocompleteFieldProps) { + const hasNewValue = prevProps.value !== this.props.value; + const hasNewSuggestions = prevProps.suggestions !== this.props.suggestions; + + if (hasNewValue) { + this.updateSuggestions(); + } + + if (hasNewValue && this.props.value === '') { + this.submit(); + } + + if (hasNewSuggestions && this.state.isFocused) { + this.showSuggestions(); + } + } + + private handleChangeInputRef = (element: HTMLInputElement | null) => { + this.inputElement = element; + }; + + private handleChange = (evt: React.ChangeEvent) => { + this.changeValue(evt.currentTarget.value); + }; + + private handleKeyDown = (evt: React.KeyboardEvent) => { + const { suggestions } = this.props; + + switch (evt.key) { + case 'ArrowUp': + evt.preventDefault(); + if (suggestions.length > 0) { + this.setState( + composeStateUpdaters(withSuggestionsVisible, withPreviousSuggestionSelected) + ); + } + break; + case 'ArrowDown': + evt.preventDefault(); + if (suggestions.length > 0) { + this.setState(composeStateUpdaters(withSuggestionsVisible, withNextSuggestionSelected)); + } else { + this.updateSuggestions(); + } + break; + case 'Enter': + evt.preventDefault(); + if (this.state.selectedIndex !== null) { + this.applySelectedSuggestion(); + } else { + this.submit(); + } + break; + case 'Escape': + evt.preventDefault(); + this.setState(withSuggestionsHidden); + break; + } + }; + + private handleKeyUp = (evt: React.KeyboardEvent) => { + switch (evt.key) { + case 'ArrowLeft': + case 'ArrowRight': + case 'Home': + case 'End': + this.updateSuggestions(); + break; + } + }; + + private handleFocus = () => { + this.setState(composeStateUpdaters(withSuggestionsVisible, withFocused)); + }; + + private handleBlur = () => { + this.setState(composeStateUpdaters(withSuggestionsHidden, withUnfocused)); + }; + + private selectSuggestionAt = (index: number) => () => { + this.setState(withSuggestionAtIndexSelected(index)); + }; + + private applySelectedSuggestion = () => { + if (this.state.selectedIndex !== null) { + this.applySuggestionAt(this.state.selectedIndex)(); + } + }; + + private applySuggestionAt = (index: number) => () => { + const { value, suggestions } = this.props; + const selectedSuggestion = suggestions[index]; + + if (!selectedSuggestion) { + return; + } + + const newValue = + value.substr(0, selectedSuggestion.start) + + selectedSuggestion.text + + value.substr(selectedSuggestion.end); + + this.setState(withSuggestionsHidden); + this.changeValue(newValue); + this.focusInputElement(); + }; + + private changeValue = (value: string) => { + const { onChange } = this.props; + + if (onChange) { + onChange(value); + } + }; + + private focusInputElement = () => { + if (this.inputElement) { + this.inputElement.focus(); + } + }; + + private showSuggestions = () => { + this.setState(withSuggestionsVisible); + }; + + private submit = () => { + const { isValid, onSubmit, value } = this.props; + + if (isValid && onSubmit) { + onSubmit(value); + } + + this.setState(withSuggestionsHidden); + }; + + private updateSuggestions = () => { + const inputCursorPosition = this.inputElement ? this.inputElement.selectionStart || 0 : 0; + this.props.loadSuggestions(this.props.value, inputCursorPosition, 200); + }; +} + +const withPreviousSuggestionSelected = ( + state: AutocompleteFieldState, + props: AutocompleteFieldProps +): AutocompleteFieldState => ({ + ...state, + selectedIndex: + props.suggestions.length === 0 + ? null + : state.selectedIndex !== null + ? (state.selectedIndex + props.suggestions.length - 1) % props.suggestions.length + : Math.max(props.suggestions.length - 1, 0), +}); + +const withNextSuggestionSelected = ( + state: AutocompleteFieldState, + props: AutocompleteFieldProps +): AutocompleteFieldState => ({ + ...state, + selectedIndex: + props.suggestions.length === 0 + ? null + : state.selectedIndex !== null + ? (state.selectedIndex + 1) % props.suggestions.length + : 0, +}); + +const withSuggestionAtIndexSelected = + (suggestionIndex: number) => + (state: AutocompleteFieldState, props: AutocompleteFieldProps): AutocompleteFieldState => ({ + ...state, + selectedIndex: + props.suggestions.length === 0 + ? null + : suggestionIndex >= 0 && suggestionIndex < props.suggestions.length + ? suggestionIndex + : 0, + }); + +const withSuggestionsVisible = (state: AutocompleteFieldState) => ({ + ...state, + areSuggestionsVisible: true, +}); + +const withSuggestionsHidden = (state: AutocompleteFieldState) => ({ + ...state, + areSuggestionsVisible: false, + selectedIndex: null, +}); + +const withFocused = (state: AutocompleteFieldState) => ({ + ...state, + isFocused: true, +}); + +const withUnfocused = (state: AutocompleteFieldState) => ({ + ...state, + isFocused: false, +}); + +const AutocompleteContainer = euiStyled.div` + position: relative; +`; + +const SuggestionsPanel = euiStyled(EuiPanel).attrs(() => ({ + paddingSize: 'none', + hasShadow: true, +}))` + position: absolute; + width: 100%; + margin-top: 2px; + overflow-x: hidden; + overflow-y: scroll; + z-index: ${(props) => props.theme.eui.euiZLevel1}; + max-height: 322px; +`; diff --git a/x-pack/plugins/monitoring/public/components/kuery_bar/index.tsx b/x-pack/plugins/monitoring/public/components/kuery_bar/index.tsx new file mode 100644 index 0000000000000..ca0a8122772f3 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/kuery_bar/index.tsx @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +import React, { useEffect, useState } from 'react'; +import { WithKueryAutocompletion } from './with_kuery_autocompletion'; +import { AutocompleteField } from './autocomplete_field'; +import { esKuery, IIndexPattern, QuerySuggestion } from '../../../../../../src/plugins/data/public'; + +type LoadSuggestionsFn = ( + e: string, + p: number, + m?: number, + transform?: (s: QuerySuggestion[]) => QuerySuggestion[] +) => void; +export type CurryLoadSuggestionsType = (loadSuggestions: LoadSuggestionsFn) => LoadSuggestionsFn; + +interface Props { + derivedIndexPattern: IIndexPattern; + onSubmit: (query: string) => void; + onChange?: (query: string) => void; + value?: string | null; + placeholder?: string; + curryLoadSuggestions?: CurryLoadSuggestionsType; +} + +function validateQuery(query: string) { + try { + esKuery.fromKueryExpression(query); + } catch (err) { + return false; + } + return true; +} + +export const KueryBar = ({ + derivedIndexPattern, + onSubmit, + onChange, + value, + placeholder, + curryLoadSuggestions = defaultCurryLoadSuggestions, +}: Props) => { + const [draftQuery, setDraftQuery] = useState(value || ''); + const [isValid, setValidation] = useState(true); + + // This ensures that if value changes out side this component it will update. + useEffect(() => { + if (value) { + setDraftQuery(value); + } + }, [value]); + + const handleChange = (query: string) => { + setValidation(validateQuery(query)); + setDraftQuery(query); + if (onChange) { + onChange(query); + } + }; + + const filteredDerivedIndexPattern = { + ...derivedIndexPattern, + fields: derivedIndexPattern.fields, + }; + + const defaultPlaceholder = i18n.translate('xpack.monitoring.alerts.kqlSearchFieldPlaceholder', { + defaultMessage: 'Search for monitoring data', + }); + + return ( + + {({ isLoadingSuggestions, loadSuggestions, suggestions }) => ( + + )} + + ); +}; + +const defaultCurryLoadSuggestions: CurryLoadSuggestionsType = + (loadSuggestions) => + (...args) => + loadSuggestions(...args); diff --git a/x-pack/plugins/monitoring/public/components/kuery_bar/suggestion_item.tsx b/x-pack/plugins/monitoring/public/components/kuery_bar/suggestion_item.tsx new file mode 100644 index 0000000000000..3681bf26987cc --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/kuery_bar/suggestion_item.tsx @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiIcon } from '@elastic/eui'; +import { transparentize } from 'polished'; +import React from 'react'; +import { euiStyled } from '../../../../../../src/plugins/kibana_react/common'; +import { QuerySuggestion, QuerySuggestionTypes } from '../../../../../../src/plugins/data/public'; + +interface Props { + isSelected?: boolean; + onClick?: React.MouseEventHandler; + onMouseEnter?: React.MouseEventHandler; + suggestion: QuerySuggestion; +} + +export const SuggestionItem: React.FC = (props) => { + const { isSelected, onClick, onMouseEnter, suggestion } = props; + + return ( + + + + + {suggestion.text} + {suggestion.description} + + ); +}; + +SuggestionItem.defaultProps = { + isSelected: false, +}; + +const SuggestionItemContainer = euiStyled.div<{ + isSelected?: boolean; +}>` + display: flex; + flex-direction: row; + font-size: ${(props) => props.theme.eui.euiFontSizeS}; + height: ${(props) => props.theme.eui.euiSizeXL}; + white-space: nowrap; + background-color: ${(props) => + props.isSelected ? props.theme.eui.euiColorLightestShade : 'transparent'}; +`; + +const SuggestionItemField = euiStyled.div` + align-items: center; + cursor: pointer; + display: flex; + flex-direction: row; + height: ${(props) => props.theme.eui.euiSizeXL}; + padding: ${(props) => props.theme.eui.euiSizeXS}; +`; + +const SuggestionItemIconField = euiStyled(SuggestionItemField)<{ + suggestionType: QuerySuggestionTypes; +}>` + background-color: ${(props) => + transparentize(0.9, getEuiIconColor(props.theme, props.suggestionType))}; + color: ${(props) => getEuiIconColor(props.theme, props.suggestionType)}; + flex: 0 0 auto; + justify-content: center; + width: ${(props) => props.theme.eui.euiSizeXL}; +`; + +const SuggestionItemTextField = euiStyled(SuggestionItemField)` + flex: 2 0 0; + font-family: ${(props) => props.theme.eui.euiCodeFontFamily}; +`; + +const SuggestionItemDescriptionField = euiStyled(SuggestionItemField)` + flex: 3 0 0; + + p { + display: inline; + + span { + font-family: ${(props) => props.theme.eui.euiCodeFontFamily}; + } + } +`; + +const getEuiIconType = (suggestionType: QuerySuggestionTypes) => { + switch (suggestionType) { + case QuerySuggestionTypes.Field: + return 'kqlField'; + case QuerySuggestionTypes.Value: + return 'kqlValue'; + case QuerySuggestionTypes.RecentSearch: + return 'search'; + case QuerySuggestionTypes.Conjunction: + return 'kqlSelector'; + case QuerySuggestionTypes.Operator: + return 'kqlOperand'; + default: + return 'empty'; + } +}; + +const getEuiIconColor = (theme: any, suggestionType: QuerySuggestionTypes): string => { + switch (suggestionType) { + case QuerySuggestionTypes.Field: + return theme?.eui.euiColorVis7; + case QuerySuggestionTypes.Value: + return theme?.eui.euiColorVis0; + case QuerySuggestionTypes.Operator: + return theme?.eui.euiColorVis1; + case QuerySuggestionTypes.Conjunction: + return theme?.eui.euiColorVis2; + case QuerySuggestionTypes.RecentSearch: + default: + return theme?.eui.euiColorMediumShade; + } +}; diff --git a/x-pack/plugins/monitoring/public/components/kuery_bar/with_kuery_autocompletion.tsx b/x-pack/plugins/monitoring/public/components/kuery_bar/with_kuery_autocompletion.tsx new file mode 100644 index 0000000000000..8d79bf4039846 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/kuery_bar/with_kuery_autocompletion.tsx @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { QuerySuggestion, IIndexPattern, DataPublicPluginStart } from 'src/plugins/data/public'; +import { + withKibana, + KibanaReactContextValue, + KibanaServices, +} from '../../../../../../src/plugins/kibana_react/public'; +import { RendererFunction } from '../../lib/typed_react'; + +interface WithKueryAutocompletionLifecycleProps { + kibana: KibanaReactContextValue<{ data: DataPublicPluginStart } & KibanaServices>; + children: RendererFunction<{ + isLoadingSuggestions: boolean; + loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; + suggestions: QuerySuggestion[]; + }>; + indexPattern: IIndexPattern; +} + +interface WithKueryAutocompletionLifecycleState { + // lacking cancellation support in the autocompletion api, + // this is used to keep older, slower requests from clobbering newer ones + currentRequest: { + expression: string; + cursorPosition: number; + } | null; + suggestions: QuerySuggestion[]; +} + +class WithKueryAutocompletionComponent extends React.Component< + WithKueryAutocompletionLifecycleProps, + WithKueryAutocompletionLifecycleState +> { + public readonly state: WithKueryAutocompletionLifecycleState = { + currentRequest: null, + suggestions: [], + }; + + public render() { + const { currentRequest, suggestions } = this.state; + + return this.props.children({ + isLoadingSuggestions: currentRequest !== null, + loadSuggestions: this.loadSuggestions, + suggestions, + }); + } + + private loadSuggestions = async ( + expression: string, + cursorPosition: number, + maxSuggestions?: number, + transformSuggestions?: (s: QuerySuggestion[]) => QuerySuggestion[] + ) => { + const { indexPattern } = this.props; + const language = 'kuery'; + const hasQuerySuggestions = + this.props.kibana.services.data?.autocomplete.hasQuerySuggestions(language); + + if (!hasQuerySuggestions) { + return; + } + + this.setState({ + currentRequest: { + expression, + cursorPosition, + }, + suggestions: [], + }); + + const suggestions = + (await this.props.kibana.services.data.autocomplete.getQuerySuggestions({ + language, + query: expression, + selectionStart: cursorPosition, + selectionEnd: cursorPosition, + indexPatterns: [indexPattern], + boolFilter: [], + })) || []; + + const transformedSuggestions = transformSuggestions + ? transformSuggestions(suggestions) + : suggestions; + + this.setState((state) => + state.currentRequest && + state.currentRequest.expression !== expression && + state.currentRequest.cursorPosition !== cursorPosition + ? state // ignore this result, since a newer request is in flight + : { + ...state, + currentRequest: null, + suggestions: maxSuggestions + ? transformedSuggestions.slice(0, maxSuggestions) + : transformedSuggestions, + } + ); + }; +} + +export const WithKueryAutocompletion = withKibana( + WithKueryAutocompletionComponent +); diff --git a/x-pack/plugins/monitoring/public/components/no_data/no_data.js b/x-pack/plugins/monitoring/public/components/no_data/no_data.js index 1714ace7ceff9..97bf7cacf53e7 100644 --- a/x-pack/plugins/monitoring/public/components/no_data/no_data.js +++ b/x-pack/plugins/monitoring/public/components/no_data/no_data.js @@ -32,9 +32,9 @@ import { CloudDeployment } from './blurbs'; import { getSafeForExternalLink } from '../../lib/get_safe_for_external_link'; function NoDataMessage(props) { - const { isLoading, reason, checkMessage } = props; + const { isLoading, reason, checkMessage, isCollectionEnabledUpdated } = props; - if (isLoading) { + if ((isCollectionEnabledUpdated && !reason) || isLoading) { return ; } diff --git a/x-pack/plugins/monitoring/public/components/table/index.d.ts b/x-pack/plugins/monitoring/public/components/table/index.d.ts new file mode 100644 index 0000000000000..6b54b3d97e5f1 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/table/index.d.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const euiTableStorageGetter: (string) => any; +export const euiTableStorageSetter: (string) => any; diff --git a/x-pack/plugins/monitoring/public/lib/kuery.ts b/x-pack/plugins/monitoring/public/lib/kuery.ts new file mode 100644 index 0000000000000..19706d7664c22 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/kuery.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { esKuery, IIndexPattern } from '../../../../../src/plugins/data/public'; + +export const convertKueryToElasticSearchQuery = ( + kueryExpression: string, + indexPattern: IIndexPattern +) => { + try { + return kueryExpression + ? JSON.stringify( + esKuery.toElasticsearchQuery(esKuery.fromKueryExpression(kueryExpression), indexPattern) + ) + : ''; + } catch (err) { + return ''; + } +}; diff --git a/x-pack/plugins/monitoring/public/lib/setup_mode.tsx b/x-pack/plugins/monitoring/public/lib/setup_mode.tsx index f622f2944a31a..fca7f94731bc5 100644 --- a/x-pack/plugins/monitoring/public/lib/setup_mode.tsx +++ b/x-pack/plugins/monitoring/public/lib/setup_mode.tsx @@ -159,6 +159,8 @@ export const disableElasticsearchInternalCollection = async () => { }; export const toggleSetupMode = (inSetupMode: boolean) => { + if (isReactMigrationEnabled()) return setupModeReact.toggleSetupMode(inSetupMode); + checkAngularState(); const globalState = angularState.injector.get('globalState'); diff --git a/x-pack/plugins/monitoring/public/lib/typed_react.tsx b/x-pack/plugins/monitoring/public/lib/typed_react.tsx new file mode 100644 index 0000000000000..b5b7a440c117c --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/typed_react.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { omit } from 'lodash'; +import React from 'react'; +import { InferableComponentEnhancerWithProps, ConnectedComponent } from 'react-redux'; + +export type RendererResult = React.ReactElement | null; +export type RendererFunction = (args: RenderArgs) => Result; + +export type ChildFunctionRendererProps = { + children: RendererFunction; + initializeOnMount?: boolean; + resetOnUnmount?: boolean; +} & RenderArgs; + +interface ChildFunctionRendererOptions { + onInitialize?: (props: RenderArgs) => void; + onCleanup?: (props: RenderArgs) => void; +} + +export const asChildFunctionRenderer = ( + hoc: InferableComponentEnhancerWithProps, + { onInitialize, onCleanup }: ChildFunctionRendererOptions = {} +): ConnectedComponent< + React.ComponentClass<{}>, + { + children: RendererFunction; + initializeOnMount?: boolean; + resetOnUnmount?: boolean; + } & OwnProps +> => + hoc( + class ChildFunctionRenderer extends React.Component> { + public displayName = 'ChildFunctionRenderer'; + + public componentDidMount() { + if (this.props.initializeOnMount && onInitialize) { + onInitialize(this.getRendererArgs()); + } + } + + public componentWillUnmount() { + if (this.props.resetOnUnmount && onCleanup) { + onCleanup(this.getRendererArgs()); + } + } + + public render() { + return (this.props.children as ChildFunctionRendererProps['children'])( + this.getRendererArgs() + ); + } + + private getRendererArgs = () => + omit(this.props, ['children', 'initializeOnMount', 'resetOnUnmount']) as Pick< + ChildFunctionRendererProps, + keyof InjectedProps + >; + } as any + ); + +export type StateUpdater = ( + prevState: Readonly, + prevProps: Readonly +) => State | null; + +export type PropsOfContainer = Container extends InferableComponentEnhancerWithProps< + infer InjectedProps, + any +> + ? InjectedProps + : never; + +export function composeStateUpdaters(...updaters: Array>) { + return (state: State, props: Props) => + updaters.reduce((currentState, updater) => updater(currentState, props) || currentState, state); +} diff --git a/x-pack/plugins/monitoring/public/plugin.ts b/x-pack/plugins/monitoring/public/plugin.ts index ad71cdbeb106c..aee5072947531 100644 --- a/x-pack/plugins/monitoring/public/plugin.ts +++ b/x-pack/plugins/monitoring/public/plugin.ts @@ -28,14 +28,6 @@ import { RULE_THREAD_POOL_WRITE_REJECTIONS, RULE_DETAILS, } from '../common/constants'; -import { createCpuUsageAlertType } from './alerts/cpu_usage_alert'; -import { createMissingMonitoringDataAlertType } from './alerts/missing_monitoring_data_alert'; -import { createLegacyAlertTypes } from './alerts/legacy_alert'; -import { createDiskUsageAlertType } from './alerts/disk_usage_alert'; -import { createThreadPoolRejectionsAlertType } from './alerts/thread_pool_rejections_alert'; -import { createMemoryUsageAlertType } from './alerts/memory_usage_alert'; -import { createCCRReadExceptionsAlertType } from './alerts/ccr_read_exceptions_alert'; -import { createLargeShardSizeAlertType } from './alerts/large_shard_size_alert'; import { setConfig } from './external_config'; interface MonitoringSetupPluginDependencies { @@ -49,11 +41,11 @@ const HASH_CHANGE = 'hashchange'; export class MonitoringPlugin implements - Plugin + Plugin { constructor(private initializerContext: PluginInitializerContext) {} - public setup( + public async setup( core: CoreSetup, plugins: MonitoringSetupPluginDependencies ) { @@ -86,7 +78,7 @@ export class MonitoringPlugin }); } - this.registerAlerts(plugins); + await this.registerAlerts(plugins, monitoring); const app: App = { id, @@ -152,7 +144,6 @@ export class MonitoringPlugin }; core.application.register(app); - return true; } public start(core: CoreStart, plugins: any) {} @@ -192,29 +183,48 @@ export class MonitoringPlugin ]; } - private registerAlerts(plugins: MonitoringSetupPluginDependencies) { + private async registerAlerts( + plugins: MonitoringSetupPluginDependencies, + config: MonitoringConfig + ) { const { triggersActionsUi: { ruleTypeRegistry }, } = plugins; - ruleTypeRegistry.register(createCpuUsageAlertType()); - ruleTypeRegistry.register(createDiskUsageAlertType()); - ruleTypeRegistry.register(createMemoryUsageAlertType()); + + const { createCpuUsageAlertType } = await import('./alerts/cpu_usage_alert'); + const { createMissingMonitoringDataAlertType } = await import( + './alerts/missing_monitoring_data_alert' + ); + const { createLegacyAlertTypes } = await import('./alerts/legacy_alert'); + const { createDiskUsageAlertType } = await import('./alerts/disk_usage_alert'); + const { createThreadPoolRejectionsAlertType } = await import( + './alerts/thread_pool_rejections_alert' + ); + const { createMemoryUsageAlertType } = await import('./alerts/memory_usage_alert'); + const { createCCRReadExceptionsAlertType } = await import('./alerts/ccr_read_exceptions_alert'); + const { createLargeShardSizeAlertType } = await import('./alerts/large_shard_size_alert'); + + ruleTypeRegistry.register(createCpuUsageAlertType(config)); + ruleTypeRegistry.register(createDiskUsageAlertType(config)); + ruleTypeRegistry.register(createMemoryUsageAlertType(config)); ruleTypeRegistry.register(createMissingMonitoringDataAlertType()); ruleTypeRegistry.register( createThreadPoolRejectionsAlertType( RULE_THREAD_POOL_SEARCH_REJECTIONS, - RULE_DETAILS[RULE_THREAD_POOL_SEARCH_REJECTIONS] + RULE_DETAILS[RULE_THREAD_POOL_SEARCH_REJECTIONS], + config ) ); ruleTypeRegistry.register( createThreadPoolRejectionsAlertType( RULE_THREAD_POOL_WRITE_REJECTIONS, - RULE_DETAILS[RULE_THREAD_POOL_WRITE_REJECTIONS] + RULE_DETAILS[RULE_THREAD_POOL_WRITE_REJECTIONS], + config ) ); - ruleTypeRegistry.register(createCCRReadExceptionsAlertType()); - ruleTypeRegistry.register(createLargeShardSizeAlertType()); - const legacyAlertTypes = createLegacyAlertTypes(); + ruleTypeRegistry.register(createCCRReadExceptionsAlertType(config)); + ruleTypeRegistry.register(createLargeShardSizeAlertType(config)); + const legacyAlertTypes = createLegacyAlertTypes(config); for (const legacyAlertType of legacyAlertTypes) { ruleTypeRegistry.register(legacyAlertType); } diff --git a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts b/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts index 3a50aca7d4b84..e3a3537ea2eaf 100644 --- a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts @@ -88,7 +88,8 @@ export class CCRReadExceptionsRule extends BaseRule { esIndexPattern, startMs, endMs, - Globals.app.config.ui.max_bucket_size + Globals.app.config.ui.max_bucket_size, + params.filterQuery ); return stats.map((stat) => { @@ -278,7 +279,7 @@ export class CCRReadExceptionsRule extends BaseRule { state: AlertingDefaults.ALERT_STATE.firing, remoteCluster, followerIndex, - /* continue to send "remoteClusters" and "followerIndices" values for users still using it though + /* continue to send "remoteClusters" and "followerIndices" values for users still using it though we have replaced it with "remoteCluster" and "followerIndex" in the template due to alerts per index instead of all indices see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ diff --git a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts b/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts index 7fac3b74a1b66..b9b9b90845eea 100644 --- a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts @@ -73,7 +73,12 @@ export class ClusterHealthRule extends BaseRule { if (availableCcs) { esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); } - const healths = await fetchClusterHealth(esClient, clusters, esIndexPattern); + const healths = await fetchClusterHealth( + esClient, + clusters, + esIndexPattern, + params.filterQuery + ); return healths.map((clusterHealth) => { const shouldFire = clusterHealth.health !== AlertClusterHealthType.Green; const severity = diff --git a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts b/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts index 2e57a3c22de1b..7e38efcb819ea 100644 --- a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts @@ -76,7 +76,8 @@ export class CpuUsageRule extends BaseRule { esIndexPattern, startMs, endMs, - Globals.app.config.ui.max_bucket_size + Globals.app.config.ui.max_bucket_size, + params.filterQuery ); return stats.map((stat) => { if (Globals.app.config.ui.container.elasticsearch.enabled) { @@ -203,7 +204,7 @@ export class CpuUsageRule extends BaseRule { internalShortMessage, internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 + /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ nodes: `${firingNode.nodeName}:${firingNode.cpuUsage}`, diff --git a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts b/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts index ae3025c1db92c..bac70baebb4e2 100644 --- a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts @@ -72,7 +72,8 @@ export class DiskUsageRule extends BaseRule { clusters, esIndexPattern, duration as string, - Globals.app.config.ui.max_bucket_size + Globals.app.config.ui.max_bucket_size, + params.filterQuery ); return stats.map((stat) => { @@ -212,7 +213,7 @@ export class DiskUsageRule extends BaseRule { internalShortMessage, internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 + /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ nodes: `${firingNode.nodeName}:${firingNode.diskUsage}`, diff --git a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts index 6a5abcb4975f4..352cac531f8e8 100644 --- a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts @@ -66,7 +66,8 @@ export class ElasticsearchVersionMismatchRule extends BaseRule { esClient, clusters, esIndexPattern, - Globals.app.config.ui.max_bucket_size + Globals.app.config.ui.max_bucket_size, + params.filterQuery ); return elasticsearchVersions.map((elasticsearchVersion) => { diff --git a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts index 90275ea4d23a8..6d9410ed0e5a0 100644 --- a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts @@ -79,7 +79,8 @@ export class KibanaVersionMismatchRule extends BaseRule { esClient, clusters, kibanaIndexPattern, - Globals.app.config.ui.max_bucket_size + Globals.app.config.ui.max_bucket_size, + params.filterQuery ); return kibanaVersions.map((kibanaVersion) => { diff --git a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts b/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts index 86f96daa3b21d..b0370a23159d7 100644 --- a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts @@ -75,7 +75,8 @@ export class LargeShardSizeRule extends BaseRule { esIndexPattern, threshold!, shardIndexPatterns, - Globals.app.config.ui.max_bucket_size + Globals.app.config.ui.max_bucket_size, + params.filterQuery ); return stats.map((stat) => { @@ -211,7 +212,7 @@ export class LargeShardSizeRule extends BaseRule { internalShortMessage, internalFullMessage, state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "shardIndices" values for users still using it though + /* continue to send "shardIndices" values for users still using it though we have replaced it with shardIndex in the template due to alerts per index instead of all indices see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts index 67ea8bd57b491..c26929b05ab26 100644 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts @@ -87,7 +87,7 @@ export class LicenseExpirationRule extends BaseRule { if (availableCcs) { esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); } - const licenses = await fetchLicenses(esClient, clusters, esIndexPattern); + const licenses = await fetchLicenses(esClient, clusters, esIndexPattern, params.filterQuery); return licenses.map((license) => { const { clusterUuid, type, expiryDateMS, status, ccs } = license; diff --git a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts index 0f9ad4dd4b117..e59ed9efbefb2 100644 --- a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts @@ -66,7 +66,8 @@ export class LogstashVersionMismatchRule extends BaseRule { esClient, clusters, logstashIndexPattern, - Globals.app.config.ui.max_bucket_size + Globals.app.config.ui.max_bucket_size, + params.filterQuery ); return logstashVersions.map((logstashVersion) => { diff --git a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts b/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts index 384610e659d47..d94e1234ce813 100644 --- a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts @@ -82,7 +82,8 @@ export class MemoryUsageRule extends BaseRule { esIndexPattern, startMs, endMs, - Globals.app.config.ui.max_bucket_size + Globals.app.config.ui.max_bucket_size, + params.filterQuery ); return stats.map((stat) => { @@ -223,7 +224,7 @@ export class MemoryUsageRule extends BaseRule { internalShortMessage, internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 + /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ nodes: `${firingNode.nodeName}:${firingNode.memoryUsage.toFixed(2)}`, diff --git a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts index 32e4ff738c71b..1b45b19fe89f8 100644 --- a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts @@ -75,7 +75,8 @@ export class MissingMonitoringDataRule extends BaseRule { indexPattern, Globals.app.config.ui.max_bucket_size, now, - now - limit - LIMIT_BUFFER + now - limit - LIMIT_BUFFER, + params.filterQuery ); return missingData.map((missing) => { return { @@ -198,7 +199,7 @@ export class MissingMonitoringDataRule extends BaseRule { internalShortMessage, internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 + /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ nodes: `node: ${firingNode.nodeName}`, diff --git a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts b/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts index 90bd70f32c8cb..6645466f30c73 100644 --- a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts @@ -114,7 +114,8 @@ export class NodesChangedRule extends BaseRule { const nodesFromClusterStats = await fetchNodesFromClusterStats( esClient, clusters, - esIndexPattern + esIndexPattern, + params.filterQuery ); return nodesFromClusterStats.map((nodes) => { const { removed, added, restarted } = getNodeStates(nodes); diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts b/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts index c478b2f687c02..678f8b429167f 100644 --- a/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts +++ b/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts @@ -86,7 +86,8 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule { esIndexPattern, Globals.app.config.ui.max_bucket_size, this.threadPoolType, - duration + duration, + params.filterQuery ); return stats.map((stat) => { @@ -257,7 +258,7 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule { internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, threadPoolType: type, state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "count" value for users before https://github.com/elastic/kibana/pull/102544 + /* continue to send "count" value for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ count: 1, diff --git a/x-pack/plugins/monitoring/server/deprecations.test.js b/x-pack/plugins/monitoring/server/deprecations.test.js index 2931f704a4478..4c12979e97804 100644 --- a/x-pack/plugins/monitoring/server/deprecations.test.js +++ b/x-pack/plugins/monitoring/server/deprecations.test.js @@ -10,12 +10,13 @@ import { deprecations as deprecationsModule } from './deprecations'; describe('monitoring plugin deprecations', function () { let transformDeprecations; + const deprecate = jest.fn(() => jest.fn()); const rename = jest.fn(() => jest.fn()); const renameFromRoot = jest.fn(() => jest.fn()); const fromPath = 'monitoring'; beforeAll(function () { - const deprecations = deprecationsModule({ rename, renameFromRoot }); + const deprecations = deprecationsModule({ deprecate, rename, renameFromRoot }); transformDeprecations = (settings, fromPath, addDeprecation = noop) => { deprecations.forEach((deprecation) => deprecation(settings, fromPath, addDeprecation)); }; diff --git a/x-pack/plugins/monitoring/server/deprecations.ts b/x-pack/plugins/monitoring/server/deprecations.ts index 3e4d1627b0ae2..cb09bbdb5a87c 100644 --- a/x-pack/plugins/monitoring/server/deprecations.ts +++ b/x-pack/plugins/monitoring/server/deprecations.ts @@ -18,10 +18,12 @@ import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY } from '../common/constants'; * @return {Array} array of rename operations and callback function for rename logging */ export const deprecations = ({ + deprecate, rename, renameFromRoot, }: ConfigDeprecationFactory): ConfigDeprecation[] => { return [ + deprecate('enabled', '8.0.0'), // This order matters. The "blanket rename" needs to happen at the end renameFromRoot('xpack.monitoring.max_bucket_size', 'monitoring.ui.max_bucket_size'), renameFromRoot('xpack.monitoring.min_interval_seconds', 'monitoring.ui.min_interval_seconds'), diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_stack_product_usage.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_stack_product_usage.ts index 527ed503c8faf..0d3aab8283688 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_stack_product_usage.ts +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/fetch_stack_product_usage.ts @@ -10,7 +10,7 @@ import { ElasticsearchClient } from 'src/core/server'; import { estypes } from '@elastic/elasticsearch'; import { MonitoringConfig } from '../../../config'; // @ts-ignore -import { prefixIndexPattern } from '../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../common/ccs_utils'; import { StackProductUsage } from '../types'; interface ESResponse { diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/get_stack_products_usage.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/get_stack_products_usage.ts index 7cce1b392112f..25a1892a9f38d 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/get_stack_products_usage.ts +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/lib/get_stack_products_usage.ts @@ -12,7 +12,7 @@ import { MonitoringConfig } from '../../../config'; // @ts-ignore import { getIndexPatterns } from '../../../lib/cluster/get_index_patterns'; // @ts-ignore -import { prefixIndexPattern } from '../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../common/ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH, INDEX_PATTERN_KIBANA, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts index 560751d1297d5..e7a5923207d60 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts @@ -14,7 +14,8 @@ export async function fetchCCRReadExceptions( index: string, startMs: number, endMs: number, - size: number + size: number, + filterQuery?: string ): Promise { const params = { index, @@ -93,6 +94,15 @@ export async function fetchCCRReadExceptions( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const stats: CCRReadExceptionsStats[] = []; // @ts-expect-error declare aggegations type explicitly diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts index 85bfbd9dbd049..b2004f0c7c710 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts @@ -11,7 +11,8 @@ import { ElasticsearchSource, ElasticsearchResponse } from '../../../common/type export async function fetchClusterHealth( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string + index: string, + filterQuery?: string ): Promise { const params = { index, @@ -59,6 +60,15 @@ export async function fetchClusterHealth( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const result = await esClient.search(params); const response: ElasticsearchResponse = result.body as ElasticsearchResponse; return (response.hits?.hits ?? []).map((hit) => { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts index 90cd456f18037..8f0083f1f533f 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts @@ -201,7 +201,9 @@ describe('fetchCpuUsageNodeStats', () => { {} as estypes.SearchResponse ); }); - await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size); + const filterQuery = + '{"bool":{"should":[{"exists":{"field":"cluster_uuid"}}],"minimum_should_match":1}}'; + await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size, filterQuery); expect(params).toStrictEqual({ index: '.monitoring-es-*', filter_path: ['aggregations'], @@ -213,6 +215,9 @@ describe('fetchCpuUsageNodeStats', () => { { terms: { cluster_uuid: ['abc123'] } }, { term: { type: 'node_stats' } }, { range: { timestamp: { format: 'epoch_millis', gte: 0, lte: 0 } } }, + { + bool: { should: [{ exists: { field: 'cluster_uuid' } }], minimum_should_match: 1 }, + }, ], }, }, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts index 6f7d27916a7b1..2ad42870e9958 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts @@ -29,7 +29,8 @@ export async function fetchCpuUsageNodeStats( index: string, startMs: number, endMs: number, - size: number + size: number, + filterQuery?: string ): Promise { // Using pure MS didn't seem to work well with the date_histogram interval // but minutes does @@ -140,6 +141,15 @@ export async function fetchCpuUsageNodeStats( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const stats: AlertCpuUsageNodeStats[] = []; const clusterBuckets = get( diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts index 70f05991d4229..2d4872c0bd895 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts @@ -14,7 +14,8 @@ export async function fetchDiskUsageNodeStats( clusters: AlertCluster[], index: string, duration: string, - size: number + size: number, + filterQuery?: string ): Promise { const clustersIds = clusters.map((cluster) => cluster.clusterUuid); const params = { @@ -99,6 +100,15 @@ export async function fetchDiskUsageNodeStats( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const stats: AlertDiskUsageNodeStats[] = []; // @ts-expect-error declare type for aggregations explicitly diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts index f2f311ac870a5..6ca2e89048df9 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts @@ -12,7 +12,8 @@ export async function fetchElasticsearchVersions( esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, - size: number + size: number, + filterQuery?: string ): Promise { const params = { index, @@ -60,6 +61,15 @@ export async function fetchElasticsearchVersions( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const result = await esClient.search(params); const response: ElasticsearchResponse = result.body as ElasticsearchResponse; return (response.hits?.hits ?? []).map((hit) => { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts index 7e7ea5e6bfdd2..98bb546b43ab9 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts @@ -35,7 +35,8 @@ export async function fetchIndexShardSize( index: string, threshold: number, shardIndexPatterns: string, - size: number + size: number, + filterQuery?: string ): Promise { const params = { index, @@ -104,6 +105,15 @@ export async function fetchIndexShardSize( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.must.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); // @ts-expect-error declare aggegations type explicitly const { buckets: clusterBuckets } = response.aggregations?.clusters; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts index e57b45e2570fa..71813f3a526de 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts @@ -16,7 +16,8 @@ export async function fetchKibanaVersions( esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, - size: number + size: number, + filterQuery?: string ): Promise { const params = { index, @@ -89,6 +90,15 @@ export async function fetchKibanaVersions( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const indexName = get(response, 'aggregations.index.buckets[0].key', ''); const clusterList = get(response, 'aggregations.cluster.buckets', []) as ESAggResponse[]; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts index 38ff82cf29832..b7bdf2fb6be72 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts @@ -11,7 +11,8 @@ import { ElasticsearchSource } from '../../../common/types/es'; export async function fetchLicenses( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string + index: string, + filterQuery?: string ): Promise { const params = { index, @@ -59,6 +60,15 @@ export async function fetchLicenses( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); return ( response?.hits?.hits.map((hit) => { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts index 774ee2551ec07..112c2fe798b10 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts @@ -16,7 +16,8 @@ export async function fetchLogstashVersions( esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, - size: number + size: number, + filterQuery?: string ): Promise { const params = { index, @@ -89,6 +90,15 @@ export async function fetchLogstashVersions( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const indexName = get(response, 'aggregations.index.buckets[0].key', ''); const clusterList = get(response, 'aggregations.cluster.buckets', []) as ESAggResponse[]; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts index f34a8dcff1db7..9403ae5d79a70 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts @@ -15,7 +15,8 @@ export async function fetchMemoryUsageNodeStats( index: string, startMs: number, endMs: number, - size: number + size: number, + filterQuery?: string ): Promise { const clustersIds = clusters.map((cluster) => cluster.clusterUuid); const params = { @@ -92,6 +93,15 @@ export async function fetchMemoryUsageNodeStats( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const stats: AlertMemoryUsageNodeStats[] = []; // @ts-expect-error declare type for aggregations explicitly diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts index 856ca7c919885..cdf0f21b52b09 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts @@ -47,7 +47,8 @@ export async function fetchMissingMonitoringData( index: string, size: number, nowInMs: number, - startMs: number + startMs: number, + filterQuery?: string ): Promise { const endMs = nowInMs; const params = { @@ -117,6 +118,15 @@ export async function fetchMissingMonitoringData( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const clusterBuckets = get( response, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts index dcc8e6516c69b..3dc3e315318fc 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts @@ -26,7 +26,8 @@ function formatNode( export async function fetchNodesFromClusterStats( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string + index: string, + filterQuery?: string ): Promise { const params = { index, @@ -88,6 +89,15 @@ export async function fetchNodesFromClusterStats( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const nodes: AlertClusterStatsNodes[] = []; // @ts-expect-error declare type for aggregations explicitly diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts index 132f7692a7579..0d1d052b5f866 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts @@ -36,7 +36,8 @@ export async function fetchThreadPoolRejectionStats( index: string, size: number, threadType: string, - duration: string + duration: string, + filterQuery?: string ): Promise { const clustersIds = clusters.map((cluster) => cluster.clusterUuid); const params = { @@ -94,6 +95,15 @@ export async function fetchThreadPoolRejectionStats( }, }; + try { + if (filterQuery) { + const filterQueryObject = JSON.parse(filterQuery); + params.body.query.bool.filter.push(filterQueryObject); + } + } catch (e) { + // meh + } + const { body: response } = await esClient.search(params); const stats: AlertThreadPoolRejectionsStats[] = []; // @ts-expect-error declare type for aggregations explicitly diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts index 6eb21165d7256..a2201ca958e35 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts @@ -12,7 +12,7 @@ import { createQuery } from '../create_query'; // @ts-ignore import { ElasticsearchMetric } from '../metrics'; // @ts-ignore -import { parseCrossClusterPrefix } from '../ccs_utils'; +import { parseCrossClusterPrefix } from '../../../common/ccs_utils'; import { getClustersState } from './get_clusters_state'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts index d908d6180772e..ccfe380edec09 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts @@ -6,7 +6,7 @@ */ import { LegacyServer } from '../../types'; -import { prefixIndexPattern } from '../ccs_utils'; +import { prefixIndexPattern } from '../../../common/ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH, INDEX_PATTERN_KIBANA, diff --git a/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts b/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts index c0fa931676870..727e47b62bc92 100644 --- a/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts +++ b/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts @@ -6,7 +6,7 @@ */ // @ts-ignore -import { prefixIndexPattern } from '../ccs_utils'; +import { prefixIndexPattern } from '../../../common/ccs_utils'; import { INFRA_SOURCE_ID } from '../../../common/constants'; import { MonitoringConfig } from '../../config'; import { InfraPluginSetup } from '../../../../infra/server'; diff --git a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.js b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts similarity index 91% rename from x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.js rename to x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts index 7853b8074f375..eda9315842040 100644 --- a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.js +++ b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts @@ -6,6 +6,7 @@ */ import { get, uniq } from 'lodash'; +import { CollectorFetchContext, UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { METRICBEAT_INDEX_NAME_UNIQUE_TOKEN, ELASTICSEARCH_SYSTEM_ID, @@ -15,15 +16,31 @@ import { LOGSTASH_SYSTEM_ID, KIBANA_STATS_TYPE_MONITORING, } from '../../../../common/constants'; +import { LegacyRequest } from '../../../types'; import { getLivesNodes } from '../../elasticsearch/nodes/get_nodes/get_live_nodes'; +interface Bucket { + key: string; + single_type?: { + beat_type: { + buckets: Array<{ key: string }>; + }; + }; +} + const NUMBER_OF_SECONDS_AGO_TO_LOOK = 30; -const getRecentMonitoringDocuments = async (req, indexPatterns, clusterUuid, nodeUuid, size) => { +const getRecentMonitoringDocuments = async ( + req: LegacyRequest, + indexPatterns: Record, + clusterUuid?: string, + nodeUuid?: string, + size?: string +) => { const start = get(req.payload, 'timeRange.min') || `now-${NUMBER_OF_SECONDS_AGO_TO_LOOK}s`; const end = get(req.payload, 'timeRange.max') || 'now'; - const filters = [ + const filters: any[] = [ { range: { timestamp: { @@ -38,7 +55,7 @@ const getRecentMonitoringDocuments = async (req, indexPatterns, clusterUuid, nod filters.push({ term: { cluster_uuid: clusterUuid } }); } - const nodesClause = {}; + const nodesClause: Record = {}; if (nodeUuid) { nodesClause.must = [ { @@ -201,7 +218,7 @@ const getRecentMonitoringDocuments = async (req, indexPatterns, clusterUuid, nod return await callWithRequest(req, 'search', params); }; -async function doesIndexExist(req, index) { +async function doesIndexExist(req: LegacyRequest, index: string) { const params = { index, size: 0, @@ -214,8 +231,8 @@ async function doesIndexExist(req, index) { return get(response, 'hits.total.value', 0) > 0; } -async function detectProducts(req, isLiveCluster) { - const result = { +async function detectProducts(req: LegacyRequest, isLiveCluster: boolean) { + const result: Record> = { [KIBANA_SYSTEM_ID]: { doesExist: true, }, @@ -260,7 +277,7 @@ async function detectProducts(req, isLiveCluster) { return result; } -function getUuidBucketName(productName) { +function getUuidBucketName(productName: string) { switch (productName) { case ELASTICSEARCH_SYSTEM_ID: return 'es_uuids'; @@ -274,7 +291,7 @@ function getUuidBucketName(productName) { } } -function matchesMetricbeatIndex(metricbeatIndex, index) { +function matchesMetricbeatIndex(metricbeatIndex: string, index: string) { if (index.includes(metricbeatIndex)) { return true; } @@ -284,7 +301,7 @@ function matchesMetricbeatIndex(metricbeatIndex, index) { return false; } -function isBeatFromAPM(bucket) { +function isBeatFromAPM(bucket: Bucket) { const beatType = get(bucket, 'single_type.beat_type'); if (!beatType) { return false; @@ -293,7 +310,7 @@ function isBeatFromAPM(bucket) { return get(beatType, 'buckets[0].key') === 'apm-server'; } -async function hasNecessaryPermissions(req) { +async function hasNecessaryPermissions(req: LegacyRequest) { const licenseService = await req.server.plugins.monitoring.info.getLicenseService(); const securityFeature = licenseService.getSecurityFeature(); if (!securityFeature.isAvailable || !securityFeature.isEnabled) { @@ -310,7 +327,7 @@ async function hasNecessaryPermissions(req) { }); // If there is some problem, assume they do not have access return get(response, 'has_all_requested', false); - } catch (err) { + } catch (err: any) { if ( err.message === 'no handler found for uri [/_security/user/_has_privileges] and method [POST]' ) { @@ -336,7 +353,7 @@ async function hasNecessaryPermissions(req) { * @param {*} product The product object, which are stored in PRODUCTS * @param {*} bucket The agg bucket in the response */ -function shouldSkipBucket(product, bucket) { +function shouldSkipBucket(product: { name: string }, bucket: Bucket) { if (product.name === BEATS_SYSTEM_ID && isBeatFromAPM(bucket)) { return true; } @@ -346,18 +363,20 @@ function shouldSkipBucket(product, bucket) { return false; } -async function getLiveKibanaInstance(usageCollection) { +async function getLiveKibanaInstance(usageCollection?: UsageCollectionSetup) { if (!usageCollection) { return null; } const kibanaStatsCollector = usageCollection.getCollectorByType(KIBANA_STATS_TYPE_MONITORING); - if (!(await kibanaStatsCollector.isReady())) { + if (!(await kibanaStatsCollector?.isReady())) { return null; } - return usageCollection.toApiFieldNames(await kibanaStatsCollector.fetch()); + return usageCollection.toApiFieldNames( + (await kibanaStatsCollector!.fetch(undefined as unknown as CollectorFetchContext)) as unknown[] + ); } -async function getLiveElasticsearchClusterUuid(req) { +async function getLiveElasticsearchClusterUuid(req: LegacyRequest) { const params = { path: '/_cluster/state/cluster_uuid', method: 'GET', @@ -368,7 +387,7 @@ async function getLiveElasticsearchClusterUuid(req) { return clusterUuid; } -async function getLiveElasticsearchCollectionEnabled(req) { +async function getLiveElasticsearchCollectionEnabled(req: LegacyRequest) { const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('admin'); const response = await callWithRequest(req, 'transport.request', { method: 'GET', @@ -416,15 +435,15 @@ async function getLiveElasticsearchCollectionEnabled(req) { * @param {*} skipLiveData Optional and will not make any live api calls if set to true */ export const getCollectionStatus = async ( - req, - indexPatterns, - clusterUuid, - nodeUuid, - skipLiveData + req: LegacyRequest, + indexPatterns: Record, + clusterUuid?: string, + nodeUuid?: string, + skipLiveData?: boolean ) => { const config = req.server.config(); const kibanaUuid = config.get('server.uuid'); - const metricbeatIndex = config.get('monitoring.ui.metricbeat.index'); + const metricbeatIndex = config.get('monitoring.ui.metricbeat.index')!; const size = config.get('monitoring.ui.max_bucket_size'); const hasPermissions = await hasNecessaryPermissions(req); @@ -458,10 +477,10 @@ export const getCollectionStatus = async ( const indicesBuckets = get(recentDocuments, 'aggregations.indices.buckets', []); const liveClusterInternalCollectionEnabled = await getLiveElasticsearchCollectionEnabled(req); - const status = PRODUCTS.reduce((products, product) => { + const status: Record = PRODUCTS.reduce((products, product) => { const token = product.token || product.name; const uuidBucketName = getUuidBucketName(product.name); - const indexBuckets = indicesBuckets.filter((bucket) => { + const indexBuckets = indicesBuckets.filter((bucket: Bucket) => { if (bucket.key.includes(token)) { return true; } @@ -473,18 +492,18 @@ export const getCollectionStatus = async ( return false; }); - const productStatus = { + const productStatus: Record = { totalUniqueInstanceCount: 0, totalUniqueInternallyCollectedCount: 0, totalUniqueFullyMigratedCount: 0, totalUniquePartiallyMigratedCount: 0, detected: null, - byUuid: {}, + byUuid: {} as Record, }; - const fullyMigratedUuidsMap = {}; - const internalCollectorsUuidsMap = {}; - const partiallyMigratedUuidsMap = {}; + const fullyMigratedUuidsMap: Record = {}; + const internalCollectorsUuidsMap: Record = {}; + const partiallyMigratedUuidsMap: Record = {}; // If there is no data, then they are a net new user if (!indexBuckets || indexBuckets.length === 0) { @@ -571,7 +590,7 @@ export const getCollectionStatus = async ( product.name === ELASTICSEARCH_SYSTEM_ID && clusterUuid === liveClusterUuid && !liveClusterInternalCollectionEnabled; - const internalTimestamps = []; + const internalTimestamps: number[] = []; for (const indexBucket of indexBuckets) { const isFullyMigrated = considerAllInstancesMigrated || diff --git a/x-pack/plugins/monitoring/server/lib/setup/collection/index.js b/x-pack/plugins/monitoring/server/lib/setup/collection/index.ts similarity index 100% rename from x-pack/plugins/monitoring/server/lib/setup/collection/index.js rename to x-pack/plugins/monitoring/server/lib/setup/collection/index.ts diff --git a/x-pack/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.js b/x-pack/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.ts similarity index 84% rename from x-pack/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.js rename to x-pack/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.ts index ccbc6ccaa78aa..7529b5020d1ff 100644 --- a/x-pack/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.js +++ b/x-pack/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.ts @@ -6,8 +6,9 @@ */ import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; +import { Cluster } from '../../types'; -export const getStandaloneClusterDefinition = () => { +export const getStandaloneClusterDefinition: () => Cluster = () => { return { cluster_uuid: STANDALONE_CLUSTER_CLUSTER_UUID, license: {}, @@ -28,5 +29,5 @@ export const getStandaloneClusterDefinition = () => { }, }, }, - }; + } as Cluster; }; diff --git a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.js b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts similarity index 87% rename from x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.js rename to x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts index 938610e51693e..42ac8b89eaf37 100644 --- a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.js +++ b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts @@ -7,15 +7,16 @@ import moment from 'moment'; import { get } from 'lodash'; +import { LegacyRequest } from '../../types'; import { standaloneClusterFilter } from './'; -export async function hasStandaloneClusters(req, indexPatterns) { +export async function hasStandaloneClusters(req: LegacyRequest, indexPatterns: string[]) { const indexPatternList = indexPatterns.reduce((list, patterns) => { list.push(...patterns.split(',')); return list; - }, []); + }, [] as string[]); - const filters = [ + const filters: any[] = [ standaloneClusterFilter, { bool: { @@ -39,7 +40,7 @@ export async function hasStandaloneClusters(req, indexPatterns) { const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; - const timeRangeFilter = { + const timeRangeFilter: { range: { timestamp: Record } } = { range: { timestamp: { format: 'epoch_millis', diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index 3b939e7361652..18eb8fd4d4ddb 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -207,7 +207,7 @@ export class MonitoringPlugin } } - async start(coreStart: CoreStart, { licensing }: PluginsStart) { + start(coreStart: CoreStart, { licensing }: PluginsStart) { const config = this.config!; this.cluster = instantiateClient( config.ui.elasticsearch, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js index 4884b8151f61f..a0b00167101fe 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { metricSet } from './metric_set_instance'; import { handleError } from '../../../../lib/errors'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js index 53afa4c3f01b4..95f378ff5b98d 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getStats, getApms } from '../../../../lib/apm'; import { handleError } from '../../../../lib/errors'; import { INDEX_PATTERN_BEATS } from '../../../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js index 7a772594b4bc2..ea7f3f41b842e 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { metricSet } from './metric_set_overview'; import { handleError } from '../../../../lib/errors'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js index 919efe98f3df3..851380fede77d 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getBeatSummary } from '../../../../lib/beats'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js index 57b24e59e66ab..fa35ccb9371c2 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getStats, getBeats } from '../../../../lib/beats'; import { handleError } from '../../../../lib/errors'; import { INDEX_PATTERN_BEATS } from '../../../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js index 5f1bb1778bc9a..4abf46b3ad1ce 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { getLatestStats, getStats } from '../../../../lib/beats'; import { handleError } from '../../../../lib/errors'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts index 73b646126ce98..898cfc82463d9 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts @@ -11,7 +11,7 @@ import { get, groupBy } from 'lodash'; // @ts-ignore import { handleError } from '../../../../lib/errors/handle_error'; // @ts-ignore -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { ElasticsearchResponse, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts index 5ecb84d97618b..d07a660222407 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts @@ -10,7 +10,7 @@ import { schema } from '@kbn/config-schema'; // @ts-ignore import { handleError } from '../../../../lib/errors/handle_error'; // @ts-ignore -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; // @ts-ignore import { getMetrics } from '../../../../lib/details/get_metrics'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js index 89ca911f44268..e99ae04ab282c 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js @@ -12,7 +12,7 @@ import { getIndexSummary } from '../../../../lib/elasticsearch/indices'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { getShardAllocation, getShardStats } from '../../../../lib/elasticsearch/shards'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSet } from './metric_set_index_detail'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getLogs } from '../../../../lib/logs/get_logs'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js index 8099ecf3462cc..76e769ac030ba 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js @@ -10,7 +10,7 @@ import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getIndices } from '../../../../lib/elasticsearch/indices'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getIndicesUnassignedShardStats } from '../../../../lib/elasticsearch/shards/get_indices_unassigned_shard_stats'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js index e23c23f7a819d..5853cc3d6ee9d 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js @@ -10,7 +10,7 @@ import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getMlJobs } from '../../../../lib/elasticsearch/get_ml_jobs'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getIndicesUnassignedShardStats } from '../../../../lib/elasticsearch/shards/get_indices_unassigned_shard_stats'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js index 2122f8ceb2215..5f77d0394a4f1 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js @@ -12,7 +12,7 @@ import { getNodeSummary } from '../../../../lib/elasticsearch/nodes'; import { getShardStats, getShardAllocation } from '../../../../lib/elasticsearch/shards'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSets } from './metric_set_node_detail'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getLogs } from '../../../../lib/logs/get_logs'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js index db12e28916b65..7ea2e6e1e1440 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js @@ -11,7 +11,7 @@ import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getNodes } from '../../../../lib/elasticsearch/nodes'; import { getNodesShardCount } from '../../../../lib/elasticsearch/shards/get_nodes_shard_count'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getPaginatedNodes } from '../../../../lib/elasticsearch/nodes/get_nodes/get_paginated_nodes'; import { LISTING_METRICS_NAMES } from '../../../../lib/elasticsearch/nodes/get_nodes/nodes_listing_metrics'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js index c76513df721ba..a0fc524768eb9 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js @@ -11,7 +11,7 @@ import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getLastRecovery } from '../../../../lib/elasticsearch/get_last_recovery'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSet } from './metric_set_overview'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getLogs } from '../../../../lib/logs'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts index d05d60866d119..3cd2b8b73b315 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts @@ -14,7 +14,7 @@ import { INDEX_PATTERN_LOGSTASH, } from '../../../../../../common/constants'; // @ts-ignore -import { prefixIndexPattern } from '../../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../../common/ccs_utils'; // @ts-ignore import { handleError } from '../../../../../lib/errors'; import { RouteDependencies, LegacyServer } from '../../../../../types'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.ts b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.ts index d16f568b475b4..613ca39275c2d 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.ts @@ -12,7 +12,7 @@ import { handleError } from '../../../../lib/errors'; // @ts-ignore import { getMetrics } from '../../../../lib/details/get_metrics'; // @ts-ignore -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; // @ts-ignore import { metricSet } from './metric_set_instance'; import { INDEX_PATTERN_KIBANA } from '../../../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js index 59618f0a217b5..f9b3498cd684e 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getKibanaClusterStatus } from './_get_kibana_cluster_status'; import { getKibanas } from '../../../../lib/kibana/get_kibanas'; import { handleError } from '../../../../lib/errors'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js index cca36d2aad1a7..f9a9443c3533b 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getKibanaClusterStatus } from './_get_kibana_cluster_status'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { metricSet } from './metric_set_overview'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js index b81b4ea796c63..d3ecea95430ca 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { getNodeInfo } from '../../../../lib/logstash/get_node_info'; import { handleError } from '../../../../lib/errors'; import { getMetrics } from '../../../../lib/details/get_metrics'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSets } from './metric_set_node'; import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js index 74b89ab41be92..051fb7d38fd41 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { getClusterStatus } from '../../../../lib/logstash/get_cluster_status'; import { getNodes } from '../../../../lib/logstash/get_nodes'; import { handleError } from '../../../../lib/errors'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants'; /* diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js index 23dd64a1afb74..89a6a93fb207d 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { getClusterStatus } from '../../../../lib/logstash/get_cluster_status'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSet } from './metric_set_overview'; import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js index 4243b2d6c3a5c..6b81059f0c256 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js @@ -10,7 +10,7 @@ import { handleError } from '../../../../lib/errors'; import { getPipelineVersions } from '../../../../lib/logstash/get_pipeline_versions'; import { getPipeline } from '../../../../lib/logstash/get_pipeline'; import { getPipelineVertex } from '../../../../lib/logstash/get_pipeline_vertex'; -import { prefixIndexPattern } from '../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants'; function getPipelineVersion(versions, pipelineHash) { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js index c881ff7b3d23c..7f14b74da207d 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { handleError } from '../../../../../lib/errors'; -import { prefixIndexPattern } from '../../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../../common/ccs_utils'; import { INDEX_PATTERN_LOGSTASH } from '../../../../../../common/constants'; import { getLogstashPipelineIds } from '../../../../../lib/logstash/get_pipeline_ids'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js index 1f7a5e1d436b1..b7d86e86e7a07 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js @@ -8,7 +8,7 @@ import { schema } from '@kbn/config-schema'; import { getClusterStatus } from '../../../../../lib/logstash/get_cluster_status'; import { handleError } from '../../../../../lib/errors'; -import { prefixIndexPattern } from '../../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../../common/ccs_utils'; import { INDEX_PATTERN_LOGSTASH } from '../../../../../../common/constants'; import { getPaginatedPipelines } from '../../../../../lib/logstash/get_paginated_pipelines'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js index 47b8fd81a4d44..f31e88b5b8b08 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js @@ -8,7 +8,7 @@ import { schema } from '@kbn/config-schema'; import { getNodeInfo } from '../../../../../lib/logstash/get_node_info'; import { handleError } from '../../../../../lib/errors'; -import { prefixIndexPattern } from '../../../../../lib/ccs_utils'; +import { prefixIndexPattern } from '../../../../../../common/ccs_utils'; import { INDEX_PATTERN_LOGSTASH } from '../../../../../../common/constants'; import { getPaginatedPipelines } from '../../../../../lib/logstash/get_paginated_pipelines'; diff --git a/x-pack/plugins/observability/kibana.json b/x-pack/plugins/observability/kibana.json index 45fe0258dd142..07299f2e6ff1c 100644 --- a/x-pack/plugins/observability/kibana.json +++ b/x-pack/plugins/observability/kibana.json @@ -15,6 +15,7 @@ "home", "lens", "licensing", + "spaces", "usageCollection" ], "requiredPlugins": [ diff --git a/x-pack/plugins/observability/server/index.ts b/x-pack/plugins/observability/server/index.ts index 9a62602859c54..97a17b0d11153 100644 --- a/x-pack/plugins/observability/server/index.ts +++ b/x-pack/plugins/observability/server/index.ts @@ -9,7 +9,7 @@ /* eslint-disable @kbn/eslint/no_export_all */ import { schema, TypeOf } from '@kbn/config-schema'; -import { PluginInitializerContext } from 'src/core/server'; +import { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; import { ObservabilityPlugin, ObservabilityPluginSetup } from './plugin'; import { createOrUpdateIndex, Mappings } from './utils/create_or_update_index'; import { ScopedAnnotationsClient } from './lib/annotations/bootstrap_annotations'; @@ -18,9 +18,9 @@ export { rangeQuery, kqlQuery } from './utils/queries'; export * from './types'; -export const config = { +export const config: PluginConfigDescriptor = { exposeToBrowser: { - unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } }, + unsafe: true, }, schema: schema.object({ enabled: schema.boolean({ defaultValue: true }), @@ -33,6 +33,7 @@ export const config = { cases: schema.object({ enabled: schema.boolean({ defaultValue: false }) }), }), }), + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], }; export type ObservabilityConfig = TypeOf; diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json index 4e912ee4535b8..dc935f3f77787 100644 --- a/x-pack/plugins/observability/tsconfig.json +++ b/x-pack/plugins/observability/tsconfig.json @@ -26,6 +26,7 @@ { "path": "../cases/tsconfig.json" }, { "path": "../lens/tsconfig.json" }, { "path": "../rule_registry/tsconfig.json" }, + { "path": "../spaces/tsconfig.json" }, { "path": "../timelines/tsconfig.json"}, { "path": "../translations/tsconfig.json" } ] diff --git a/x-pack/plugins/osquery/server/index.ts b/x-pack/plugins/osquery/server/index.ts index 30bc5ed5bd835..385515c285093 100644 --- a/x-pack/plugins/osquery/server/index.ts +++ b/x-pack/plugins/osquery/server/index.ts @@ -5,11 +5,12 @@ * 2.0. */ -import { PluginInitializerContext } from '../../../../src/core/server'; +import { PluginConfigDescriptor, PluginInitializerContext } from '../../../../src/core/server'; import { OsqueryPlugin } from './plugin'; -import { ConfigSchema } from './config'; +import { ConfigSchema, ConfigType } from './config'; -export const config = { +export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: ConfigSchema, exposeToBrowser: { enabled: true, diff --git a/x-pack/plugins/remote_clusters/server/config.ts b/x-pack/plugins/remote_clusters/server/config.ts index e0fadea5d41f7..8f379ec5613c8 100644 --- a/x-pack/plugins/remote_clusters/server/config.ts +++ b/x-pack/plugins/remote_clusters/server/config.ts @@ -18,6 +18,7 @@ export const configSchema = schema.object({ export type ConfigType = TypeOf; export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: configSchema, exposeToBrowser: { ui: true, diff --git a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts index ceb3ed180cd3b..bedf310725ae2 100644 --- a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts +++ b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts @@ -11,8 +11,10 @@ import { CoreStart } from 'src/core/public'; import type { SearchSource } from 'src/plugins/data/common'; import type { SavedSearch } from 'src/plugins/discover/public'; import { coreMock } from '../../../../../src/core/public/mocks'; +import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; import type { ILicense, LicensingPluginSetup } from '../../../licensing/public'; import { ReportingAPIClient } from '../lib/reporting_api_client'; +import type { ReportingPublicPluginStartDendencies } from '../plugin'; import type { ActionContext } from './get_csv_panel_action'; import { ReportingCsvPanelAction } from './get_csv_panel_action'; @@ -25,8 +27,8 @@ describe('GetCsvReportPanelAction', () => { let context: ActionContext; let mockLicense$: (state?: LicenseResults) => Rx.Observable; let mockSearchSource: SearchSource; - let mockStartServicesPayload: [CoreStart, object, unknown]; - let mockStartServices$: Rx.Subject; + let mockStartServicesPayload: [CoreStart, ReportingPublicPluginStartDendencies, unknown]; + let mockStartServices$: Rx.Observable; beforeAll(() => { if (typeof window.URL.revokeObjectURL === 'undefined') { @@ -48,14 +50,17 @@ describe('GetCsvReportPanelAction', () => { }) as unknown as LicensingPluginSetup['license$']; }; - mockStartServices$ = new Rx.Subject<[CoreStart, object, unknown]>(); mockStartServicesPayload = [ { + ...core, application: { capabilities: { dashboard: { downloadCsv: true } } }, } as unknown as CoreStart, - {}, + { + data: dataPluginMock.createStartContract(), + } as ReportingPublicPluginStartDendencies, null, ]; + mockStartServices$ = Rx.from(Promise.resolve(mockStartServicesPayload)); mockSearchSource = { createCopy: () => mockSearchSource, @@ -93,7 +98,7 @@ describe('GetCsvReportPanelAction', () => { usesUiCapabilities: true, }); - mockStartServices$.next(mockStartServicesPayload); + await mockStartServices$.pipe(first()).toPromise(); await panel.execute(context); @@ -130,7 +135,7 @@ describe('GetCsvReportPanelAction', () => { usesUiCapabilities: true, }); - mockStartServices$.next(mockStartServicesPayload); + await mockStartServices$.pipe(first()).toPromise(); await panel.execute(context); @@ -153,7 +158,7 @@ describe('GetCsvReportPanelAction', () => { usesUiCapabilities: true, }); - mockStartServices$.next(mockStartServicesPayload); + await mockStartServices$.pipe(first()).toPromise(); await panel.execute(context); @@ -169,7 +174,7 @@ describe('GetCsvReportPanelAction', () => { usesUiCapabilities: true, }); - mockStartServices$.next(mockStartServicesPayload); + await mockStartServices$.pipe(first()).toPromise(); await panel.execute(context); @@ -187,7 +192,7 @@ describe('GetCsvReportPanelAction', () => { usesUiCapabilities: true, }); - mockStartServices$.next(mockStartServicesPayload); + await mockStartServices$.pipe(first()).toPromise(); await panel.execute(context); @@ -204,14 +209,13 @@ describe('GetCsvReportPanelAction', () => { usesUiCapabilities: true, }); - mockStartServices$.next(mockStartServicesPayload); - + await mockStartServices$.pipe(first()).toPromise(); await licenseMock$.pipe(first()).toPromise(); expect(await plugin.isCompatible(context)).toEqual(false); }); - it('sets a display and icon type', () => { + it('sets a display and icon type', async () => { const panel = new ReportingCsvPanelAction({ core, apiClient, @@ -220,7 +224,7 @@ describe('GetCsvReportPanelAction', () => { usesUiCapabilities: true, }); - mockStartServices$.next(mockStartServicesPayload); + await mockStartServices$.pipe(first()).toPromise(); expect(panel.getIconType()).toMatchInlineSnapshot(`"document"`); expect(panel.getDisplayName()).toMatchInlineSnapshot(`"Download CSV"`); @@ -228,25 +232,28 @@ describe('GetCsvReportPanelAction', () => { describe('Application UI Capabilities', () => { it(`doesn't allow downloads when UI capability is not enabled`, async () => { + mockStartServicesPayload = [ + { application: { capabilities: {} } } as unknown as CoreStart, + { + data: dataPluginMock.createStartContract(), + } as ReportingPublicPluginStartDendencies, + null, + ]; + const startServices$ = Rx.from(Promise.resolve(mockStartServicesPayload)); const plugin = new ReportingCsvPanelAction({ core, apiClient, license$: mockLicense$(), - startServices$: mockStartServices$, + startServices$, usesUiCapabilities: true, }); - mockStartServices$.next([ - { application: { capabilities: {} } } as unknown as CoreStart, - {}, - null, - ]); + await startServices$.pipe(first()).toPromise(); expect(await plugin.isCompatible(context)).toEqual(false); }); it(`allows downloads when license is valid and UI capability is enabled`, async () => { - mockStartServices$ = new Rx.Subject(); const plugin = new ReportingCsvPanelAction({ core, apiClient, @@ -255,7 +262,7 @@ describe('GetCsvReportPanelAction', () => { usesUiCapabilities: true, }); - mockStartServices$.next(mockStartServicesPayload); + await mockStartServices$.pipe(first()).toPromise(); expect(await plugin.isCompatible(context)).toEqual(true); }); diff --git a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx index eb14e32160869..ef32e64741765 100644 --- a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx +++ b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx @@ -7,7 +7,8 @@ import { i18n } from '@kbn/i18n'; import * as Rx from 'rxjs'; -import type { CoreSetup, IUiSettingsClient, NotificationsSetup } from 'src/core/public'; +import { first } from 'rxjs/operators'; +import type { CoreSetup, NotificationsSetup } from 'src/core/public'; import { CoreStart } from 'src/core/public'; import type { ISearchEmbeddable, SavedSearch } from '../../../../../src/plugins/discover/public'; import { @@ -22,6 +23,7 @@ import type { LicensingPluginSetup } from '../../../licensing/public'; import { CSV_REPORTING_ACTION } from '../../common/constants'; import { checkLicense } from '../lib/license_check'; import { ReportingAPIClient } from '../lib/reporting_api_client'; +import type { ReportingPublicPluginStartDendencies } from '../plugin'; function isSavedSearchEmbeddable( embeddable: IEmbeddable | ISearchEmbeddable @@ -36,7 +38,7 @@ export interface ActionContext { interface Params { apiClient: ReportingAPIClient; core: CoreSetup; - startServices$: Rx.Observable<[CoreStart, object, unknown]>; + startServices$: Rx.Observable<[CoreStart, ReportingPublicPluginStartDendencies, unknown]>; license$: LicensingPluginSetup['license$']; usesUiCapabilities: boolean; } @@ -47,16 +49,16 @@ export class ReportingCsvPanelAction implements ActionDefinition public readonly id = CSV_REPORTING_ACTION; private licenseHasDownloadCsv: boolean = false; private capabilityHasDownloadCsv: boolean = false; - private uiSettings: IUiSettingsClient; private notifications: NotificationsSetup; private apiClient: ReportingAPIClient; + private startServices$: Params['startServices$']; constructor({ core, startServices$, license$, usesUiCapabilities, apiClient }: Params) { this.isDownloading = false; - this.uiSettings = core.uiSettings; this.notifications = core.notifications; this.apiClient = apiClient; + this.startServices$ = startServices$; license$.subscribe((license) => { const results = license.check('reporting', 'basic'); @@ -65,7 +67,7 @@ export class ReportingCsvPanelAction implements ActionDefinition }); if (usesUiCapabilities) { - startServices$.subscribe(([{ application }]) => { + this.startServices$.subscribe(([{ application }]) => { this.capabilityHasDownloadCsv = application.capabilities.dashboard?.downloadCsv === true; }); } else { @@ -84,11 +86,12 @@ export class ReportingCsvPanelAction implements ActionDefinition } public async getSearchSource(savedSearch: SavedSearch, embeddable: ISearchEmbeddable) { + const [{ uiSettings }, { data }] = await this.startServices$.pipe(first()).toPromise(); const { getSharingData } = await loadSharingDataHelpers(); return await getSharingData( savedSearch.searchSource, - savedSearch, // TODO: get unsaved state (using embeddale.searchScope): https://github.com/elastic/kibana/issues/43977 - this.uiSettings + savedSearch, // TODO: get unsaved state (using embeddable.searchScope): https://github.com/elastic/kibana/issues/43977 + { uiSettings, data } ); } diff --git a/x-pack/plugins/reporting/public/plugin.ts b/x-pack/plugins/reporting/public/plugin.ts index 28226751975a9..7fd6047470a0e 100644 --- a/x-pack/plugins/reporting/public/plugin.ts +++ b/x-pack/plugins/reporting/public/plugin.ts @@ -8,6 +8,7 @@ import { i18n } from '@kbn/i18n'; import * as Rx from 'rxjs'; import { catchError, filter, map, mergeMap, takeUntil } from 'rxjs/operators'; +import type { DataPublicPluginStart } from 'src/plugins/data/public'; import { CoreSetup, CoreStart, @@ -77,6 +78,7 @@ export interface ReportingPublicPluginSetupDendencies { export interface ReportingPublicPluginStartDendencies { home: HomePublicPluginStart; + data: DataPublicPluginStart; management: ManagementStart; licensing: LicensingPluginStart; uiActions: UiActionsStart; @@ -134,7 +136,10 @@ export class ReportingPublicPlugin return this.contract; } - public setup(core: CoreSetup, setupDeps: ReportingPublicPluginSetupDendencies) { + public setup( + core: CoreSetup, + setupDeps: ReportingPublicPluginSetupDendencies + ) { const { getStartServices, uiSettings } = core; const { home, diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index dc5c560d29546..c269677ae930d 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -345,6 +345,15 @@ export class CsvGenerator { break; } + // TODO check for shard failures, log them and add a warning if found + { + const { + hits: { hits, ...hitsMeta }, + ...header + } = results; + this.logger.debug('Results metadata: ' + JSON.stringify({ header, hitsMeta })); + } + let table: Datatable | undefined; try { table = tabifyDocs(results, index, { shallow: true, meta: true }); @@ -405,6 +414,14 @@ export class CsvGenerator { this.logger.debug(`Finished generating. Row count: ${this.csvRowCount}.`); + // FIXME: https://github.com/elastic/kibana/issues/112186 -- find root cause + if (!this.maxSizeReached && this.csvRowCount !== totalRecords) { + this.logger.warning( + `ES scroll returned fewer total hits than expected! ` + + `Search result total hits: ${totalRecords}. Row count: ${this.csvRowCount}.` + ); + } + return { content_type: CONTENT_TYPE_CSV, csv_contains_formulas: this.csvContainsFormulas && !escapeFormulaValues, diff --git a/x-pack/plugins/reporting/server/lib/content_stream.ts b/x-pack/plugins/reporting/server/lib/content_stream.ts index 79ff9a6812137..23cc8a302dbef 100644 --- a/x-pack/plugins/reporting/server/lib/content_stream.ts +++ b/x-pack/plugins/reporting/server/lib/content_stream.ts @@ -93,11 +93,11 @@ export class ContentStream extends Duplex { this.parameters = { encoding }; } - private async decode(content: string) { + private decode(content: string) { return Buffer.from(content, this.parameters.encoding === 'base64' ? 'base64' : undefined); } - private async encode(buffer: Buffer) { + private encode(buffer: Buffer) { return buffer.toString(this.parameters.encoding === 'base64' ? 'base64' : undefined); } @@ -188,7 +188,7 @@ export class ContentStream extends Duplex { return; } - const buffer = await this.decode(content); + const buffer = this.decode(content); this.push(buffer); this.chunksRead++; @@ -252,7 +252,7 @@ export class ContentStream extends Duplex { private async flush(size = this.buffer.byteLength) { const chunk = this.buffer.slice(0, size); - const content = await this.encode(chunk); + const content = this.encode(chunk); if (!this.chunksWritten) { await this.removeChunks(); @@ -269,32 +269,29 @@ export class ContentStream extends Duplex { this.buffer = this.buffer.slice(size); } - async _write(chunk: Buffer | string, encoding: BufferEncoding, callback: Callback) { + private async flushAllFullChunks() { + const maxChunkSize = await this.getMaxChunkSize(); + + while (this.buffer.byteLength >= maxChunkSize) { + await this.flush(maxChunkSize); + } + } + + _write(chunk: Buffer | string, encoding: BufferEncoding, callback: Callback) { this.buffer = Buffer.concat([ this.buffer, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding), ]); - try { - const maxChunkSize = await this.getMaxChunkSize(); - - while (this.buffer.byteLength >= maxChunkSize) { - await this.flush(maxChunkSize); - } - - callback(); - } catch (error) { - callback(error); - } + this.flushAllFullChunks() + .then(() => callback()) + .catch(callback); } - async _final(callback: Callback) { - try { - await this.flush(); - callback(); - } catch (error) { - callback(error); - } + _final(callback: Callback) { + this.flush() + .then(() => callback()) + .catch(callback); } getSeqNo(): number | undefined { diff --git a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap index 12debe5c85d5e..2017ae0be59c7 100644 --- a/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap +++ b/x-pack/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap @@ -37,6 +37,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -73,6 +96,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -118,6 +164,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -154,6 +223,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -190,6 +282,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -230,6 +345,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -266,6 +404,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -305,6 +466,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -341,6 +525,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -377,10 +584,56 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, }, + "output_size": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "printable_pdf": Object { "app": Object { "canvas workpad": Object { @@ -413,6 +666,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -449,6 +725,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -973,6 +1272,29 @@ Object { }, }, }, + "output_size": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "printable_pdf": Object { "app": Object { "canvas workpad": Object { @@ -1005,6 +1327,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -1041,6 +1386,29 @@ Object { "type": "long", }, }, + "sizes": Object { + "1.0": Object { + "type": "long", + }, + "25.0": Object { + "type": "long", + }, + "5.0": Object { + "type": "long", + }, + "50.0": Object { + "type": "long", + }, + "75.0": Object { + "type": "long", + }, + "95.0": Object { + "type": "long", + }, + "99.0": Object { + "type": "long", + }, + }, "total": Object { "type": "long", }, @@ -1620,6 +1988,7 @@ Object { "preserve_layout": 0, "print": 0, }, + "output_size": undefined, "total": 4, }, "csv_searchsource": Object { @@ -1636,6 +2005,7 @@ Object { "preserve_layout": 0, "print": 0, }, + "output_size": undefined, "total": 5, }, "csv_searchsource_immediate": Object { @@ -1703,6 +2073,7 @@ Object { "preserve_layout": 0, "print": 0, }, + "output_size": undefined, "total": 4, }, "csv_searchsource": Object { @@ -1719,6 +2090,7 @@ Object { "preserve_layout": 0, "print": 0, }, + "output_size": undefined, "total": 5, }, "csv_searchsource_immediate": Object { @@ -1737,6 +2109,7 @@ Object { }, "total": 0, }, + "output_size": undefined, "printable_pdf": Object { "app": Object { "canvas workpad": 0, @@ -1784,6 +2157,7 @@ Object { }, }, }, + "output_size": undefined, "printable_pdf": Object { "app": Object { "canvas workpad": 0, @@ -2001,6 +2375,7 @@ Object { }, "total": 0, }, + "output_size": undefined, "printable_pdf": Object { "app": Object { "canvas workpad": 0, @@ -2039,6 +2414,7 @@ Object { }, "statuses": Object {}, }, + "output_size": undefined, "printable_pdf": Object { "app": Object { "canvas workpad": 0, @@ -2079,7 +2455,7 @@ Object { } `; -exports[`data modeling with normal looking usage data 1`] = ` +exports[`data modeling with sparse data 1`] = ` Object { "PNG": Object { "app": Object { @@ -2095,7 +2471,8 @@ Object { "preserve_layout": 0, "print": 0, }, - "total": 3, + "output_size": undefined, + "total": 1, }, "PNGV2": Object { "app": Object { @@ -2113,7 +2490,7 @@ Object { }, "total": 0, }, - "_all": 12, + "_all": 4, "available": true, "browser_type": undefined, "csv": Object { @@ -2124,13 +2501,14 @@ Object { "visualization": 0, }, "available": true, - "deprecated": 0, + "deprecated": 1, "layout": Object { "canvas": 0, "preserve_layout": 0, "print": 0, }, - "total": 0, + "output_size": undefined, + "total": 1, }, "csv_searchsource": Object { "app": Object { @@ -2180,6 +2558,7 @@ Object { "preserve_layout": 0, "print": 0, }, + "output_size": undefined, "total": 1, }, "PNGV2": Object { @@ -2198,7 +2577,7 @@ Object { }, "total": 0, }, - "_all": 1, + "_all": 4, "csv": Object { "app": Object { "canvas workpad": 0, @@ -2207,13 +2586,14 @@ Object { "visualization": 0, }, "available": true, - "deprecated": 0, + "deprecated": 1, "layout": Object { "canvas": 0, "preserve_layout": 0, "print": 0, }, - "total": 0, + "output_size": undefined, + "total": 1, }, "csv_searchsource": Object { "app": Object { @@ -2247,10 +2627,11 @@ Object { }, "total": 0, }, + "output_size": undefined, "printable_pdf": Object { "app": Object { - "canvas workpad": 0, - "dashboard": 0, + "canvas workpad": 1, + "dashboard": 1, "search": 0, "visualization": 0, }, @@ -2258,10 +2639,11 @@ Object { "deprecated": 0, "layout": Object { "canvas": 0, - "preserve_layout": 0, + "preserve_layout": 2, "print": 0, }, - "total": 0, + "output_size": undefined, + "total": 2, }, "printable_pdf_v2": Object { "app": Object { @@ -2280,33 +2662,39 @@ Object { "total": 0, }, "status": Object { - "completed": 0, - "completed_with_warnings": 1, + "completed": 4, "failed": 0, }, "statuses": Object { - "completed_with_warnings": Object { + "completed": Object { "PNG": Object { "dashboard": 1, }, + "csv": Object {}, + "printable_pdf": Object { + "canvas workpad": 1, + "dashboard": 1, + }, }, }, }, + "output_size": undefined, "printable_pdf": Object { "app": Object { - "canvas workpad": 6, - "dashboard": 0, + "canvas workpad": 1, + "dashboard": 1, "search": 0, - "visualization": 3, + "visualization": 0, }, "available": true, "deprecated": 0, "layout": Object { "canvas": 0, - "preserve_layout": 9, + "preserve_layout": 2, "print": 0, }, - "total": 9, + "output_size": undefined, + "total": 2, }, "printable_pdf_v2": Object { "app": Object { @@ -2325,27 +2713,17 @@ Object { "total": 0, }, "status": Object { - "completed": 10, - "completed_with_warnings": 1, - "failed": 1, + "completed": 4, + "failed": 0, }, "statuses": Object { "completed": Object { - "PNG": Object { - "visualization": 1, - }, - "printable_pdf": Object { - "canvas workpad": 6, - "visualization": 3, - }, - }, - "completed_with_warnings": Object { "PNG": Object { "dashboard": 1, }, - }, - "failed": Object { - "PNG": Object { + "csv": Object {}, + "printable_pdf": Object { + "canvas workpad": 1, "dashboard": 1, }, }, @@ -2353,7 +2731,7 @@ Object { } `; -exports[`data modeling with sparse data 1`] = ` +exports[`data modeling with usage data from the reporting/archived_reports es archive 1`] = ` Object { "PNG": Object { "app": Object { @@ -2369,6 +2747,7 @@ Object { "preserve_layout": 0, "print": 0, }, + "output_size": undefined, "total": 1, }, "PNGV2": Object { @@ -2387,7 +2766,7 @@ Object { }, "total": 0, }, - "_all": 4, + "_all": 11, "available": true, "browser_type": undefined, "csv": Object { @@ -2404,6 +2783,7 @@ Object { "preserve_layout": 0, "print": 0, }, + "output_size": undefined, "total": 1, }, "csv_searchsource": Object { @@ -2420,7 +2800,8 @@ Object { "preserve_layout": 0, "print": 0, }, - "total": 0, + "output_size": undefined, + "total": 3, }, "csv_searchsource_immediate": Object { "app": Object { @@ -2454,7 +2835,7 @@ Object { "preserve_layout": 0, "print": 0, }, - "total": 1, + "total": 0, }, "PNGV2": Object { "app": Object { @@ -2472,7 +2853,7 @@ Object { }, "total": 0, }, - "_all": 4, + "_all": 0, "csv": Object { "app": Object { "canvas workpad": 0, @@ -2481,13 +2862,13 @@ Object { "visualization": 0, }, "available": true, - "deprecated": 1, + "deprecated": 0, "layout": Object { "canvas": 0, "preserve_layout": 0, "print": 0, }, - "total": 1, + "total": 0, }, "csv_searchsource": Object { "app": Object { @@ -2521,10 +2902,11 @@ Object { }, "total": 0, }, + "output_size": undefined, "printable_pdf": Object { "app": Object { - "canvas workpad": 1, - "dashboard": 1, + "canvas workpad": 0, + "dashboard": 0, "search": 0, "visualization": 0, }, @@ -2532,10 +2914,10 @@ Object { "deprecated": 0, "layout": Object { "canvas": 0, - "preserve_layout": 2, + "preserve_layout": 0, "print": 0, }, - "total": 2, + "total": 0, }, "printable_pdf_v2": Object { "app": Object { @@ -2554,26 +2936,16 @@ Object { "total": 0, }, "status": Object { - "completed": 4, + "completed": 0, "failed": 0, }, - "statuses": Object { - "completed": Object { - "PNG": Object { - "dashboard": 1, - }, - "csv": Object {}, - "printable_pdf": Object { - "canvas workpad": 1, - "dashboard": 1, - }, - }, - }, + "statuses": Object {}, }, + "output_size": undefined, "printable_pdf": Object { "app": Object { - "canvas workpad": 1, - "dashboard": 1, + "canvas workpad": 0, + "dashboard": 6, "search": 0, "visualization": 0, }, @@ -2581,10 +2953,11 @@ Object { "deprecated": 0, "layout": Object { "canvas": 0, - "preserve_layout": 2, - "print": 0, + "preserve_layout": 5, + "print": 1, }, - "total": 2, + "output_size": undefined, + "total": 6, }, "printable_pdf_v2": Object { "app": Object { @@ -2603,17 +2976,38 @@ Object { "total": 0, }, "status": Object { - "completed": 4, - "failed": 0, + "completed": 6, + "completed_with_warnings": 2, + "failed": 2, + "pending": 1, }, "statuses": Object { "completed": Object { + "csv": Object { + "search": 1, + }, + "csv_searchsource": Object { + "search": 3, + }, + "printable_pdf": Object { + "dashboard": 2, + }, + }, + "completed_with_warnings": Object { "PNG": Object { "dashboard": 1, }, - "csv": Object {}, "printable_pdf": Object { - "canvas workpad": 1, + "dashboard": 1, + }, + }, + "failed": Object { + "printable_pdf": Object { + "dashboard": 2, + }, + }, + "pending": Object { + "printable_pdf": Object { "dashboard": 1, }, }, diff --git a/x-pack/plugins/reporting/server/usage/get_export_stats.test.ts b/x-pack/plugins/reporting/server/usage/get_export_stats.test.ts index 782f2e910038e..f74e176e6f21d 100644 --- a/x-pack/plugins/reporting/server/usage/get_export_stats.test.ts +++ b/x-pack/plugins/reporting/server/usage/get_export_stats.test.ts @@ -11,6 +11,15 @@ import { getExportTypesHandler } from './get_export_type_handler'; import { FeatureAvailabilityMap } from './types'; let featureMap: FeatureAvailabilityMap; +const sizesAggResponse = { + '1.0': 5093470.0, + '5.0': 5093470.0, + '25.0': 5093470.0, + '50.0': 8514532.0, + '75.0': 1.1935594e7, + '95.0': 1.1935594e7, + '99.0': 1.1935594e7, +}; beforeEach(() => { featureMap = { PNG: true, csv: true, csv_searchsource: true, printable_pdf: true }; @@ -67,14 +76,19 @@ test('Model of job status and status-by-pdf-app', () => { test('Model of jobTypes', () => { const result = getExportStats( { - PNG: { available: true, total: 3 }, + PNG: { available: true, total: 3, sizes: sizesAggResponse }, printable_pdf: { available: true, total: 3, + sizes: sizesAggResponse, app: { dashboard: 0, visualization: 0, 'canvas workpad': 3 }, layout: { preserve_layout: 3, print: 0 }, }, - csv_searchsource: { available: true, total: 3 }, + csv_searchsource: { + available: true, + total: 3, + sizes: sizesAggResponse, + }, }, featureMap, exportTypesHandler @@ -95,6 +109,15 @@ test('Model of jobTypes', () => { "preserve_layout": 0, "print": 0, }, + "output_size": Object { + "1.0": 5093470, + "25.0": 5093470, + "5.0": 5093470, + "50.0": 8514532, + "75.0": 11935594, + "95.0": 11935594, + "99.0": 11935594, + }, "total": 3, } `); @@ -131,6 +154,15 @@ test('Model of jobTypes', () => { "preserve_layout": 0, "print": 0, }, + "output_size": Object { + "1.0": 5093470, + "25.0": 5093470, + "5.0": 5093470, + "50.0": 8514532, + "75.0": 11935594, + "95.0": 11935594, + "99.0": 11935594, + }, "total": 3, } `); @@ -149,6 +181,15 @@ test('Model of jobTypes', () => { "preserve_layout": 3, "print": 0, }, + "output_size": Object { + "1.0": 5093470, + "25.0": 5093470, + "5.0": 5093470, + "50.0": 8514532, + "75.0": 11935594, + "95.0": 11935594, + "99.0": 11935594, + }, "total": 3, } `); @@ -156,7 +197,14 @@ test('Model of jobTypes', () => { test('PNG counts, provided count of deprecated jobs explicitly', () => { const result = getExportStats( - { PNG: { available: true, total: 15, deprecated: 5 } }, + { + PNG: { + available: true, + total: 15, + deprecated: 5, + sizes: sizesAggResponse, + }, + }, featureMap, exportTypesHandler ); @@ -175,6 +223,15 @@ test('PNG counts, provided count of deprecated jobs explicitly', () => { "preserve_layout": 0, "print": 0, }, + "output_size": Object { + "1.0": 5093470, + "25.0": 5093470, + "5.0": 5093470, + "50.0": 8514532, + "75.0": 11935594, + "95.0": 11935594, + "99.0": 11935594, + }, "total": 15, } `); @@ -182,7 +239,14 @@ test('PNG counts, provided count of deprecated jobs explicitly', () => { test('CSV counts, provides all jobs implicitly deprecated due to jobtype', () => { const result = getExportStats( - { csv: { available: true, total: 15, deprecated: 0 } }, + { + csv: { + available: true, + total: 15, + deprecated: 0, + sizes: sizesAggResponse, + }, + }, featureMap, exportTypesHandler ); @@ -201,6 +265,15 @@ test('CSV counts, provides all jobs implicitly deprecated due to jobtype', () => "preserve_layout": 0, "print": 0, }, + "output_size": Object { + "1.0": 5093470, + "25.0": 5093470, + "5.0": 5093470, + "50.0": 8514532, + "75.0": 11935594, + "95.0": 11935594, + "99.0": 11935594, + }, "total": 15, } `); diff --git a/x-pack/plugins/reporting/server/usage/get_export_stats.ts b/x-pack/plugins/reporting/server/usage/get_export_stats.ts index ffdb6cdc290d7..72c09f08017a1 100644 --- a/x-pack/plugins/reporting/server/usage/get_export_stats.ts +++ b/x-pack/plugins/reporting/server/usage/get_export_stats.ts @@ -33,6 +33,7 @@ function getAvailableTotalForFeature( available: isAvailable(featureAvailability, typeKey), total: jobType.total, deprecated, + output_size: jobType.sizes, app: { ...defaultTotalsForFeature.app, ...jobType.app }, layout: { ...defaultTotalsForFeature.layout, ...jobType.layout }, }; @@ -56,6 +57,7 @@ export const getExportStats = ( _all: rangeAll, status: rangeStatus, statuses: rangeStatusByApp, + output_size: outputSize, ...rangeStats } = rangeStatsInput; @@ -84,6 +86,7 @@ export const getExportStats = ( _all: rangeAll || 0, status: { completed: 0, failed: 0, ...rangeStatus }, statuses: rangeStatusByApp, + output_size: outputSize, } as RangeStats; return resultStats; diff --git a/x-pack/plugins/reporting/server/usage/get_reporting_usage.ts b/x-pack/plugins/reporting/server/usage/get_reporting_usage.ts index 9aba7841162c2..9a452943ff699 100644 --- a/x-pack/plugins/reporting/server/usage/get_reporting_usage.ts +++ b/x-pack/plugins/reporting/server/usage/get_reporting_usage.ts @@ -13,6 +13,7 @@ import type { GetLicense } from './'; import { getExportStats } from './get_export_stats'; import { getExportTypesHandler } from './get_export_type_handler'; import type { + AggregationBuckets, AggregationResultBuckets, AvailableTotal, FeatureAvailabilityMap, @@ -33,6 +34,8 @@ const OBJECT_TYPES_FIELD = 'meta.objectType.keyword'; const STATUS_TYPES_KEY = 'statusTypes'; const STATUS_BY_APP_KEY = 'statusByApp'; const STATUS_TYPES_FIELD = 'status'; +const OUTPUT_SIZES_KEY = 'sizes'; +const OUTPUT_SIZES_FIELD = 'output.size'; const DEFAULT_TERMS_SIZE = 10; const PRINTABLE_PDF_JOBTYPE = 'printable_pdf'; @@ -64,13 +67,14 @@ const getAppStatuses = (buckets: StatusByAppBucket[]) => }, {}); function getAggStats(aggs: AggregationResultBuckets): Partial { - const { buckets: jobBuckets } = aggs[JOB_TYPES_KEY]; + const { buckets: jobBuckets } = aggs[JOB_TYPES_KEY] as AggregationBuckets; const jobTypes = jobBuckets.reduce((accum: JobTypes, bucket) => { - const { key, doc_count: count, isDeprecated } = bucket; + const { key, doc_count: count, isDeprecated, sizes } = bucket; const deprecatedCount = isDeprecated?.doc_count; const total: Omit = { total: count, deprecated: deprecatedCount, + sizes: sizes?.values, }; return { ...accum, [key]: total }; }, {} as JobTypes); @@ -97,7 +101,13 @@ function getAggStats(aggs: AggregationResultBuckets): Partial { statusByApp = getAppStatuses(statusAppBuckets); } - return { _all: all, status: statusTypes, statuses: statusByApp, ...jobTypes }; + return { + _all: all, + status: statusTypes, + statuses: statusByApp, + output_size: get(aggs[OUTPUT_SIZES_KEY], 'values') ?? undefined, + ...jobTypes, + }; } type RangeStatSets = Partial & { @@ -135,7 +145,6 @@ export async function getReportingUsage( exportTypesRegistry: ExportTypesRegistry ): Promise { const reportingIndex = config.get('index'); - const params = { index: `${reportingIndex}-*`, filterPath: 'aggregations.*.buckets', @@ -152,8 +161,14 @@ export async function getReportingUsage( aggs: { [JOB_TYPES_KEY]: { terms: { field: JOB_TYPES_FIELD, size: DEFAULT_TERMS_SIZE }, - aggs: { isDeprecated: { filter: { term: { [OBJECT_TYPE_DEPRECATED_KEY]: true } } } }, + aggs: { + isDeprecated: { filter: { term: { [OBJECT_TYPE_DEPRECATED_KEY]: true } } }, + [OUTPUT_SIZES_KEY]: { + percentiles: { field: OUTPUT_SIZES_FIELD }, + }, + }, }, + [STATUS_TYPES_KEY]: { terms: { field: STATUS_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, [STATUS_BY_APP_KEY]: { terms: { field: 'status', size: DEFAULT_TERMS_SIZE }, @@ -161,19 +176,24 @@ export async function getReportingUsage( jobTypes: { terms: { field: JOB_TYPES_FIELD, size: DEFAULT_TERMS_SIZE }, aggs: { - appNames: { terms: { field: OBJECT_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, // NOTE Discover/CSV export is missing the 'meta.objectType' field, so Discover/CSV results are missing for this agg + appNames: { terms: { field: OBJECT_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, }, }, }, }, [OBJECT_TYPES_KEY]: { filter: { term: { jobtype: PRINTABLE_PDF_JOBTYPE } }, - aggs: { pdf: { terms: { field: OBJECT_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } } }, + aggs: { + pdf: { terms: { field: OBJECT_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, + }, }, [LAYOUT_TYPES_KEY]: { filter: { term: { jobtype: PRINTABLE_PDF_JOBTYPE } }, aggs: { pdf: { terms: { field: LAYOUT_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } } }, }, + [OUTPUT_SIZES_KEY]: { + percentiles: { field: OUTPUT_SIZES_FIELD }, + }, }, }, }, diff --git a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts index e69e56d6272d5..447085810cfd0 100644 --- a/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts +++ b/x-pack/plugins/reporting/server/usage/reporting_usage_collector.test.ts @@ -18,7 +18,6 @@ import { getReportingUsageCollector, registerReportingUsageCollector, } from './reporting_usage_collector'; -import { SearchResponse } from './types'; const exportTypesRegistry = getExportTypesRegistry(); @@ -190,7 +189,7 @@ describe('data modeling', () => { beforeAll(async () => { mockCore = await createMockReportingCore(createMockConfigSchema()); }); - test('with normal looking usage data', async () => { + test('with usage data from the reporting/archived_reports es archive', async () => { const plugins = getPluginsMock(); const collector = getReportingUsageCollector( mockCore, @@ -202,39 +201,37 @@ describe('data modeling', () => { } ); collectorFetchContext = getMockFetchClients( - getResponseMock( - { + getResponseMock({ aggregations: { ranges: { + meta: {}, buckets: { all: { - doc_count: 12, - jobTypes: { buckets: [ { doc_count: 9, key: 'printable_pdf' }, { doc_count: 3, key: 'PNG' }, ], }, - layoutTypes: { doc_count: 9, pdf: { buckets: [{ doc_count: 9, key: 'preserve_layout' }] }, }, - objectTypes: { doc_count: 9, pdf: { buckets: [ { doc_count: 6, key: 'canvas workpad' }, { doc_count: 3, key: 'visualization' }, ], }, }, - statusByApp: { buckets: [ { doc_count: 10, jobTypes: { buckets: [ { appNames: { buckets: [ { doc_count: 6, key: 'canvas workpad' }, { doc_count: 3, key: 'visualization' }, ], }, doc_count: 9, key: 'printable_pdf', }, { appNames: { buckets: [{ doc_count: 1, key: 'visualization' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed', }, { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'failed', }, ], }, - statusTypes: { buckets: [ { doc_count: 10, key: 'completed' }, { doc_count: 1, key: 'completed_with_warnings' }, { doc_count: 1, key: 'failed' }, ], }, + doc_count: 11, + layoutTypes: { doc_count: 6, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'preserve_layout', doc_count: 5 }, { key: 'print', doc_count: 1 }, ] } }, + statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 6, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 3, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'search', doc_count: 3 }, ] } }, { key: 'printable_pdf', doc_count: 2, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 2 }, ] } }, { key: 'csv', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'search', doc_count: 1 }, ] } }, ] } }, { key: 'completed_with_warnings', doc_count: 2, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'PNG', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'printable_pdf', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, ] } }, { key: 'failed', doc_count: 2, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 2 }, ] } }, ] } }, { key: 'pending', doc_count: 1, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 1, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 1 }, ] } }, ] } }, ] }, + objectTypes: { doc_count: 6, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'dashboard', doc_count: 6 }, ] } }, + statusTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 6 }, { key: 'completed_with_warnings', doc_count: 2 }, { key: 'failed', doc_count: 2 }, { key: 'pending', doc_count: 1 }, ] }, + jobTypes: { meta: {}, doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'printable_pdf', doc_count: 6, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 1713303.0 }, sizeAvg: { value: 957215.0 }, sizeMin: { value: 43226.0 } }, { key: 'csv_searchsource', doc_count: 3, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 7557.0 }, sizeAvg: { value: 3684.6666666666665 }, sizeMin: { value: 204.0 } }, { key: 'PNG', doc_count: 1, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 37748.0 }, sizeAvg: { value: 37748.0 }, sizeMin: { value: 37748.0 } }, { key: 'csv', doc_count: 1, isDeprecated: { meta: {}, doc_count: 0 }, sizeMax: { value: 231.0 }, sizeAvg: { value: 231.0 }, sizeMin: { value: 231.0 } }, ] }, + sizeMax: { value: 1713303.0 }, + sizeMin: { value: 204.0 }, + sizeAvg: { value: 365084.75 }, }, last7Days: { - doc_count: 1, - jobTypes: { buckets: [{ doc_count: 1, key: 'PNG' }] }, - layoutTypes: { doc_count: 0, pdf: { buckets: [] } }, - objectTypes: { doc_count: 0, pdf: { buckets: [] } }, - statusByApp: { buckets: [ { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, ], }, - statusTypes: { buckets: [{ doc_count: 1, key: 'completed_with_warnings' }] }, - }, - lastDay: { - doc_count: 1, - jobTypes: { buckets: [{ doc_count: 1, key: 'PNG' }] }, - layoutTypes: { doc_count: 0, pdf: { buckets: [] } }, - objectTypes: { doc_count: 0, pdf: { buckets: [] } }, - statusByApp: { buckets: [ { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, ], }, - statusTypes: { buckets: [{ doc_count: 1, key: 'completed_with_warnings' }] }, + doc_count: 0, + layoutTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, + statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + objectTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, + statusTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + jobTypes: { meta: {}, doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + sizeMax: { value: null }, + sizeMin: { value: null }, + sizeAvg: { value: null }, }, }, - }, + }, // prettier-ignore }, - } as SearchResponse) // prettier-ignore + }) ); const usageStats = await collector.fetch(collectorFetchContext); expect(usageStats).toMatchSnapshot(); @@ -258,121 +255,21 @@ describe('data modeling', () => { buckets: { all: { doc_count: 9, - layoutTypes: { - doc_count: 0, - pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, - }, - statusByApp: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'completed', - doc_count: 9, - jobTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'csv_searchsource', - doc_count: 5, - appNames: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'search', doc_count: 5 }], - }, - }, - { - key: 'csv', - doc_count: 4, - appNames: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'search', doc_count: 4 }], - }, - }, - ], - }, - }, - ], - }, - objectTypes: { - doc_count: 0, - pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, - }, - statusTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'completed', doc_count: 9 }], - }, - jobTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, - { key: 'csv', doc_count: 4, isDeprecated: { doc_count: 4 } }, - ], - }, + layoutTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, + statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 9, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 5 }] } }, { key: 'csv', doc_count: 4, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 4 }] } }, ] } }, ] }, + objectTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, + statusTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'completed', doc_count: 9 }] }, + jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, { key: 'csv', doc_count: 4, isDeprecated: { doc_count: 4 } }, ] }, }, last7Days: { doc_count: 9, - layoutTypes: { - doc_count: 0, - pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, - }, - statusByApp: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'completed', - doc_count: 9, - jobTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'csv_searchsource', - doc_count: 5, - appNames: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'search', doc_count: 5 }], - }, - }, - { - key: 'csv', - doc_count: 4, - appNames: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'search', doc_count: 4 }], - }, - }, - ], - }, - }, - ], - }, - objectTypes: { - doc_count: 0, - pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, - }, - statusTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'completed', doc_count: 9 }], - }, - jobTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, - { key: 'csv', doc_count: 4, isDeprecated: { doc_count: 4 } }, - ], - }, + layoutTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, + statusByApp: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'completed', doc_count: 9, jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 5 }] } }, { key: 'csv', doc_count: 4, appNames: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'search', doc_count: 4 }] } }, ] } }, ] }, + objectTypes: { doc_count: 0, pdf: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] } }, + statusTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [{ key: 'completed', doc_count: 9 }] }, + jobTypes: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [ { key: 'csv_searchsource', doc_count: 5, isDeprecated: { doc_count: 0 } }, { key: 'csv', doc_count: 4, isDeprecated: { doc_count: 4 } }, ] }, }, - }, + }, // prettier-ignore }, }, }) @@ -393,39 +290,30 @@ describe('data modeling', () => { } ); collectorFetchContext = getMockFetchClients( - getResponseMock( - { + getResponseMock({ aggregations: { ranges: { buckets: { all: { doc_count: 4, - layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, }, - statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], }, - objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, + layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] } }, + statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] } }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ] } }, ] }, + objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] }, - jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], }, + jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ] }, }, last7Days: { doc_count: 4, - layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, }, - statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], }, - objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, + layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] } }, + statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] } }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ] } }, ] }, + objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ] } }, statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] }, - jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], }, + jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ] }, }, - lastDay: { - doc_count: 4, - layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, }, - statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], }, - objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, - statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] }, - jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], }, - }, - }, + }, // prettier-ignore }, }, - } as SearchResponse) // prettier-ignore + }) ); const usageStats = await collector.fetch(collectorFetchContext); expect(usageStats).toMatchSnapshot(); @@ -445,9 +333,9 @@ describe('data modeling', () => { collectorFetchContext = getMockFetchClients( getResponseMock({ - aggregations: { - ranges: { - buckets: { + aggregations: { + ranges: { + buckets: { all: { doc_count: 0, jobTypes: { buckets: [] }, @@ -455,6 +343,9 @@ describe('data modeling', () => { objectTypes: { doc_count: 0, pdf: { buckets: [] } }, statusByApp: { buckets: [] }, statusTypes: { buckets: [] }, + sizeMax: { value: null}, + sizeMin: { value: null }, + sizeAvg: { value: null}, }, last7Days: { doc_count: 0, @@ -463,19 +354,15 @@ describe('data modeling', () => { objectTypes: { doc_count: 0, pdf: { buckets: [] } }, statusByApp: { buckets: [] }, statusTypes: { buckets: [] }, + sizeMax: { value: null}, + sizeMin: { value: null }, + sizeAvg: { value: null}, + }, - lastDay: { - doc_count: 0, - jobTypes: { buckets: [] }, - layoutTypes: { doc_count: 0, pdf: { buckets: [] } }, - objectTypes: { doc_count: 0, pdf: { buckets: [] } }, - statusByApp: { buckets: [] }, - statusTypes: { buckets: [] }, - }, + }, // prettier-ignore }, }, - }, - } as SearchResponse) // prettier-ignore + }) ); const usageStats = await collector.fetch(collectorFetchContext); expect(usageStats).toMatchSnapshot(); diff --git a/x-pack/plugins/reporting/server/usage/schema.ts b/x-pack/plugins/reporting/server/usage/schema.ts index 02bf65e7c5e4d..9580ddb935dfb 100644 --- a/x-pack/plugins/reporting/server/usage/schema.ts +++ b/x-pack/plugins/reporting/server/usage/schema.ts @@ -14,6 +14,7 @@ import { LayoutCounts, RangeStats, ReportingUsageType, + SizePercentiles, } from './types'; const appCountsSchema: MakeSchemaFrom = { @@ -39,10 +40,21 @@ const byAppCountsSchema: MakeSchemaFrom = { printable_pdf_v2: appCountsSchema, }; +const sizesSchema: MakeSchemaFrom = { + '1.0': { type: 'long' }, + '5.0': { type: 'long' }, + '25.0': { type: 'long' }, + '50.0': { type: 'long' }, + '75.0': { type: 'long' }, + '95.0': { type: 'long' }, + '99.0': { type: 'long' }, +}; + const availableTotalSchema: MakeSchemaFrom = { available: { type: 'boolean' }, total: { type: 'long' }, deprecated: { type: 'long' }, + sizes: sizesSchema, app: appCountsSchema, layout: layoutCountsSchema, }; @@ -74,6 +86,7 @@ const rangeStatsSchema: MakeSchemaFrom = { pending: byAppCountsSchema, processing: byAppCountsSchema, }, + output_size: sizesSchema, }; export const reportingSchema: MakeSchemaFrom = { diff --git a/x-pack/plugins/reporting/server/usage/types.ts b/x-pack/plugins/reporting/server/usage/types.ts index 7bd79de090b37..856d3ad10cb26 100644 --- a/x-pack/plugins/reporting/server/usage/types.ts +++ b/x-pack/plugins/reporting/server/usage/types.ts @@ -5,45 +5,57 @@ * 2.0. */ -export interface KeyCountBucket { - key: string; +export interface SizePercentiles { + '1.0': number | null; + '5.0': number | null; + '25.0': number | null; + '50.0': number | null; + '75.0': number | null; + '95.0': number | null; + '99.0': number | null; +} + +interface DocCount { doc_count: number; - isDeprecated?: { - doc_count: number; - }; +} + +interface SizeStats { + sizes?: { values: SizePercentiles }; +} + +export interface KeyCountBucket extends DocCount, SizeStats { + key: string; + isDeprecated?: DocCount; } export interface AggregationBuckets { buckets: KeyCountBucket[]; } -export interface StatusByAppBucket { +export interface StatusByAppBucket extends DocCount { key: string; - doc_count: number; jobTypes: { - buckets: Array<{ - doc_count: number; - key: string; - appNames: AggregationBuckets; - }>; + buckets: Array< + { + key: string; + appNames: AggregationBuckets; + } & DocCount + >; }; } -export interface AggregationResultBuckets { - jobTypes: AggregationBuckets; +export interface AggregationResultBuckets extends DocCount, SizeStats { + jobTypes?: AggregationBuckets; layoutTypes: { - doc_count: number; - pdf: AggregationBuckets; - }; + pdf?: AggregationBuckets; + } & DocCount; objectTypes: { - doc_count: number; - pdf: AggregationBuckets; - }; + pdf?: AggregationBuckets; + } & DocCount; statusTypes: AggregationBuckets; statusByApp: { buckets: StatusByAppBucket[]; }; - doc_count: number; } export interface SearchResponse { @@ -61,6 +73,7 @@ export interface AvailableTotal { available: boolean; total: number; deprecated?: number; + sizes?: SizePercentiles; app?: { search?: number; dashboard?: number; @@ -110,7 +123,8 @@ type StatusByAppCounts = { export type RangeStats = JobTypes & { _all: number; status: StatusCounts; - statuses: StatusByAppCounts; + statuses?: StatusByAppCounts; + output_size?: SizePercentiles; }; export type ReportingUsageType = RangeStats & { diff --git a/x-pack/plugins/rollup/server/index.ts b/x-pack/plugins/rollup/server/index.ts index aa96f3ae0aac3..e77e0e6f15d72 100644 --- a/x-pack/plugins/rollup/server/index.ts +++ b/x-pack/plugins/rollup/server/index.ts @@ -13,5 +13,6 @@ export const plugin = (pluginInitializerContext: PluginInitializerContext) => new RollupPlugin(pluginInitializerContext); export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: configSchema, }; diff --git a/x-pack/plugins/rollup/server/types.ts b/x-pack/plugins/rollup/server/types.ts index c774644da46ce..a3e826fefa0bf 100644 --- a/x-pack/plugins/rollup/server/types.ts +++ b/x-pack/plugins/rollup/server/types.ts @@ -7,7 +7,7 @@ import { IRouter } from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { VisTypeTimeseriesSetup } from 'src/plugins/vis_type_timeseries/server'; +import { VisTypeTimeseriesSetup } from 'src/plugins/vis_types/timeseries/server'; import { getCapabilitiesForRollupIndices } from 'src/plugins/data/server'; import { IndexManagementPluginSetup } from '../../index_management/server'; diff --git a/x-pack/plugins/rollup/tsconfig.json b/x-pack/plugins/rollup/tsconfig.json index fbe323b2549ea..252c27a66fba2 100644 --- a/x-pack/plugins/rollup/tsconfig.json +++ b/x-pack/plugins/rollup/tsconfig.json @@ -22,7 +22,7 @@ { "path": "../../../src/plugins/home/tsconfig.json" }, { "path": "../index_management/tsconfig.json" }, { "path": "../../../src/plugins/usage_collection/tsconfig.json" }, - { "path": "../../../src/plugins/vis_type_timeseries/tsconfig.json" }, + { "path": "../../../src/plugins/vis_types/timeseries/tsconfig.json" }, // required bundles { "path": "../../../src/plugins/kibana_utils/tsconfig.json" }, { "path": "../../../src/plugins/kibana_react/tsconfig.json" }, diff --git a/x-pack/plugins/rule_registry/server/config.ts b/x-pack/plugins/rule_registry/server/config.ts index 481c5fe3cce8b..62f29a9e06294 100644 --- a/x-pack/plugins/rule_registry/server/config.ts +++ b/x-pack/plugins/rule_registry/server/config.ts @@ -6,8 +6,10 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { PluginConfigDescriptor } from 'src/core/server'; -export const config = { +export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: schema.object({ enabled: schema.boolean({ defaultValue: true }), write: schema.object({ diff --git a/x-pack/plugins/saved_objects_tagging/server/config.ts b/x-pack/plugins/saved_objects_tagging/server/config.ts index f4f0bd1cf1aa0..183779aa6f229 100644 --- a/x-pack/plugins/saved_objects_tagging/server/config.ts +++ b/x-pack/plugins/saved_objects_tagging/server/config.ts @@ -16,6 +16,7 @@ const configSchema = schema.object({ export type SavedObjectsTaggingConfigType = TypeOf; export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: configSchema, exposeToBrowser: { cache_refresh_interval: true, diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index a93439b29069b..18c029ce2300e 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -64,6 +64,7 @@ export const DEFAULT_INDICATOR_SOURCE_PATH = 'threatintel.indicator'; export const ENRICHMENT_DESTINATION_PATH = 'threat.enrichments'; export const DEFAULT_THREAT_INDEX_KEY = 'securitySolution:defaultThreatIndex'; export const DEFAULT_THREAT_INDEX_VALUE = ['filebeat-*']; +export const DEFAULT_THREAT_MATCH_QUERY = '@timestamp >= "now-30d"'; export enum SecurityPageName { administration = 'administration', @@ -311,3 +312,5 @@ export const showAllOthersBucket: string[] = [ export const ELASTIC_NAME = 'estc'; export const TRANSFORM_STATS_URL = `/api/transform/transforms/${metadataTransformPattern}-*/_stats`; + +export const RISKY_HOSTS_INDEX = 'ml_host_risk_score_latest'; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 51211705db573..148390324c13f 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -20,6 +20,7 @@ export const allowedExperimentalValues = Object.freeze({ excludePoliciesInFilterEnabled: false, uebaEnabled: false, disableIsolationUIPendingStatuses: false, + riskyHostsEnabled: false, }); type ExperimentalConfigKeys = Array; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts index bae99649c2e01..8e65666e921fa 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts @@ -11,6 +11,7 @@ export * from './common'; export * from './details'; export * from './first_last_seen'; export * from './kpi'; +export * from './risky_hosts'; export * from './overview'; export * from './uncommon_processes'; @@ -22,5 +23,6 @@ export enum HostsQueries { hosts = 'hosts', hostsEntities = 'hostsEntities', overview = 'overviewHost', + riskyHosts = 'riskyHosts', uncommonProcesses = 'uncommonProcesses', } diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risky_hosts/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risky_hosts/index.ts new file mode 100644 index 0000000000000..f6290e5321a3c --- /dev/null +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risky_hosts/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Inspect, Maybe, RequestBasicOptions } from '../../..'; +import { IEsSearchResponse } from '../../../../../../../../src/plugins/data/common'; + +export type HostsRiskyHostsRequestOptions = RequestBasicOptions; + +export interface HostsRiskyHostsStrategyResponse extends IEsSearchResponse { + inspect?: Maybe; +} diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts index 208579ffacabe..47a96d8a5fe69 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts @@ -28,6 +28,8 @@ import { HostsKpiUniqueIpsStrategyResponse, HostsKpiUniqueIpsRequestOptions, HostFirstLastSeenRequestOptions, + HostsRiskyHostsStrategyResponse, + HostsRiskyHostsRequestOptions, } from './hosts'; import { NetworkQueries, @@ -124,6 +126,8 @@ export type StrategyResponseType = T extends HostsQ ? HostDetailsStrategyResponse : T extends UebaQueries.riskScore ? RiskScoreStrategyResponse + : T extends HostsQueries.riskyHosts + ? HostsRiskyHostsStrategyResponse : T extends UebaQueries.hostRules ? HostRulesStrategyResponse : T extends UebaQueries.userRules @@ -178,6 +182,8 @@ export type StrategyResponseType = T extends HostsQ export type StrategyRequestType = T extends HostsQueries.hosts ? HostsRequestOptions + : T extends HostsQueries.riskyHosts + ? HostsRiskyHostsRequestOptions : T extends HostsQueries.details ? HostDetailsRequestOptions : T extends HostsQueries.overview diff --git a/x-pack/plugins/security_solution/common/types/timeline/pinned_event/index.ts b/x-pack/plugins/security_solution/common/types/timeline/pinned_event/index.ts index dbb19df7a6b05..df230615818ac 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/pinned_event/index.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/pinned_event/index.ts @@ -30,6 +30,12 @@ export const SavedPinnedEventRuntimeType = runtimeTypes.intersection([ export interface SavedPinnedEvent extends runtimeTypes.TypeOf {} +/** + * This type represents a pinned event type stored in a saved object that does not include any fields that reference + * other saved objects. + */ +export type PinnedEventWithoutExternalRefs = Omit; + /** * Note Saved object type with metadata */ diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts index f8b3b426580b2..871e50821b58c 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts @@ -108,6 +108,7 @@ import { loginAndWaitForPageWithoutDateRange } from '../../tasks/login'; import { goBackToAllRulesTable } from '../../tasks/rule_details'; import { ALERTS_URL, RULE_CREATION } from '../../urls/navigation'; +import { DEFAULT_THREAT_MATCH_QUERY } from '../../../common/constants'; describe('indicator match', () => { describe('Detection rules, Indicator Match', () => { @@ -180,8 +181,8 @@ describe('indicator match', () => { }); describe('custom indicator query input', () => { - it('Has a default set of *:*', () => { - getCustomIndicatorQueryInput().should('have.text', '*:*'); + it(`Has a default set of ${DEFAULT_THREAT_MATCH_QUERY}`, () => { + getCustomIndicatorQueryInput().should('have.text', DEFAULT_THREAT_MATCH_QUERY); }); it('Shows invalidation text if text is removed', () => { diff --git a/x-pack/plugins/security_solution/cypress/integration/overview/risky_hosts_panel.spec.ts b/x-pack/plugins/security_solution/cypress/integration/overview/risky_hosts_panel.spec.ts new file mode 100644 index 0000000000000..df57f7cc8d050 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/overview/risky_hosts_panel.spec.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + OVERVIEW_RISKY_HOSTS_ENABLE_MODULE_BUTTON, + OVERVIEW_RISKY_HOSTS_LINKS, + OVERVIEW_RISKY_HOSTS_LINKS_ERROR_INNER_PANEL, + OVERVIEW_RISKY_HOSTS_LINKS_WARNING_INNER_PANEL, + OVERVIEW_RISKY_HOSTS_TOTAL_EVENT_COUNT, + OVERVIEW_RISKY_HOSTS_VIEW_DASHBOARD_BUTTON, +} from '../../screens/overview'; + +import { loginAndWaitForPage } from '../../tasks/login'; +import { OVERVIEW_URL } from '../../urls/navigation'; +import { cleanKibana } from '../../tasks/common'; +import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver'; + +describe('Risky Hosts Link Panel', () => { + before(() => { + cleanKibana(); + }); + + it('renders disabled panel view as expected', () => { + loginAndWaitForPage(OVERVIEW_URL); + cy.get(`${OVERVIEW_RISKY_HOSTS_LINKS} ${OVERVIEW_RISKY_HOSTS_LINKS_ERROR_INNER_PANEL}`).should( + 'exist' + ); + cy.get(`${OVERVIEW_RISKY_HOSTS_VIEW_DASHBOARD_BUTTON}`).should('be.disabled'); + cy.get(`${OVERVIEW_RISKY_HOSTS_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 0 hosts'); + cy.get(`${OVERVIEW_RISKY_HOSTS_ENABLE_MODULE_BUTTON}`).should('exist'); + cy.get(`${OVERVIEW_RISKY_HOSTS_ENABLE_MODULE_BUTTON}`) + .should('have.attr', 'href') + .and('match', /host-risk-score.md/); + }); + + describe('enabled module', () => { + before(() => { + esArchiverLoad('risky_hosts'); + }); + + after(() => { + esArchiverUnload('risky_hosts'); + }); + + it('renders disabled dashboard module as expected when there are no hosts in the selected time period', () => { + loginAndWaitForPage( + `${OVERVIEW_URL}?sourcerer=(timerange:(from:%272021-07-08T04:00:00.000Z%27,kind:absolute,to:%272021-07-09T03:59:59.999Z%27))` + ); + cy.get( + `${OVERVIEW_RISKY_HOSTS_LINKS} ${OVERVIEW_RISKY_HOSTS_LINKS_WARNING_INNER_PANEL}` + ).should('exist'); + cy.get(`${OVERVIEW_RISKY_HOSTS_VIEW_DASHBOARD_BUTTON}`).should('be.disabled'); + cy.get(`${OVERVIEW_RISKY_HOSTS_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 0 hosts'); + }); + + it('renders dashboard module as expected when there are hosts in the selected time period', () => { + loginAndWaitForPage(OVERVIEW_URL); + cy.get( + `${OVERVIEW_RISKY_HOSTS_LINKS} ${OVERVIEW_RISKY_HOSTS_LINKS_WARNING_INNER_PANEL}` + ).should('not.exist'); + cy.get(`${OVERVIEW_RISKY_HOSTS_VIEW_DASHBOARD_BUTTON}`).should('be.disabled'); + cy.get(`${OVERVIEW_RISKY_HOSTS_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 1 host'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/screens/overview.ts b/x-pack/plugins/security_solution/cypress/screens/overview.ts index b505bc3b01848..b617b6261d297 100644 --- a/x-pack/plugins/security_solution/cypress/screens/overview.ts +++ b/x-pack/plugins/security_solution/cypress/screens/overview.ts @@ -155,3 +155,14 @@ export const OVERVIEW_CTI_LINKS_INFO_INNER_PANEL = '[data-test-subj="cti-inner-p export const OVERVIEW_CTI_VIEW_DASHBOARD_BUTTON = '[data-test-subj="cti-view-dashboard-button"]'; export const OVERVIEW_CTI_TOTAL_EVENT_COUNT = `${OVERVIEW_CTI_LINKS} [data-test-subj="header-panel-subtitle"]`; export const OVERVIEW_CTI_ENABLE_MODULE_BUTTON = '[data-test-subj="cti-enable-module-button"]'; + +export const OVERVIEW_RISKY_HOSTS_LINKS = '[data-test-subj="risky-hosts-dashboard-links"]'; +export const OVERVIEW_RISKY_HOSTS_LINKS_ERROR_INNER_PANEL = + '[data-test-subj="risky-hosts-inner-panel-danger"]'; +export const OVERVIEW_RISKY_HOSTS_LINKS_WARNING_INNER_PANEL = + '[data-test-subj="risky-hosts-inner-panel-warning"]'; +export const OVERVIEW_RISKY_HOSTS_VIEW_DASHBOARD_BUTTON = + '[data-test-subj="risky-hosts-view-dashboard-button"]'; +export const OVERVIEW_RISKY_HOSTS_TOTAL_EVENT_COUNT = `${OVERVIEW_RISKY_HOSTS_LINKS} [data-test-subj="header-panel-subtitle"]`; +export const OVERVIEW_RISKY_HOSTS_ENABLE_MODULE_BUTTON = + '[data-test-subj="risky-hosts-enable-module-button"]'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts index c1210bf457b69..b7fb0785736f6 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts @@ -473,6 +473,7 @@ export const fillDefineIndicatorMatchRuleAndContinue = (rule: ThreatIndicatorRul indexField: rule.indicatorMappingField, indicatorIndexField: rule.indicatorIndexField, }); + getCustomIndicatorQueryInput().type('{selectall}{enter}*:*'); getDefineContinueButton().should('exist').click({ force: true }); cy.get(CUSTOM_QUERY_INPUT).should('not.exist'); }; diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx index c62337b2426d3..768137c9d731d 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -32,6 +32,7 @@ import { defaultControlColumn } from '../../../timelines/components/timeline/bod import { EventsViewer } from './events_viewer'; import * as i18n from './translations'; import { GraphOverlay } from '../../../timelines/components/graph_overlay'; + const EMPTY_CONTROL_COLUMNS: ControlColumnProps[] = []; const leadingControlColumns: ControlColumnProps[] = [ { @@ -177,8 +178,7 @@ const StatefulEventsViewerComponent: React.FC = ({ {tGridEnabled ? ( timelinesUi.getTGrid<'embedded'>({ - id, - type: 'embedded', + additionalFilters, browserFields, bulkActions, columns, @@ -189,9 +189,12 @@ const StatefulEventsViewerComponent: React.FC = ({ end, entityType, filters: globalFilters, + filterStatus: currentFilter, globalFullScreen, + graphEventId, graphOverlay, hasAlertsCrud, + id, indexNames: selectedPatterns, indexPattern, isLive, @@ -199,19 +202,17 @@ const StatefulEventsViewerComponent: React.FC = ({ itemsPerPage, itemsPerPageOptions: itemsPerPageOptions!, kqlMode, - query, + leadingControlColumns, onRuleChange, + query, renderCellValue, rowRenderers, setQuery, - start, sort, - additionalFilters, - graphEventId, - filterStatus: currentFilter, - leadingControlColumns, - trailingControlColumns, + start, tGridEventRenderedViewEnabled, + trailingControlColumns, + type: 'embedded', unit, }) ) : ( diff --git a/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.tsx b/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.tsx index 0d6e59483fbc4..e1546c5220e22 100644 --- a/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.tsx +++ b/x-pack/plugins/security_solution/public/common/components/hover_actions/actions/show_top_n.tsx @@ -21,6 +21,7 @@ import { useSourcererScope } from '../../../containers/sourcerer'; import { TooltipWithKeyboardShortcut } from '../../accessibility'; import { getAdditionalScreenReaderOnlyContext } from '../utils'; import { SHOW_TOP_N_KEYBOARD_SHORTCUT } from '../keyboard_shortcut_constants'; +import { Filter } from '../../../../../../../../src/plugins/data/public'; const SHOW_TOP = (fieldName: string) => i18n.translate('xpack.securitySolution.hoverActions.showTopTooltip', { @@ -35,11 +36,12 @@ interface Props { Component?: typeof EuiButtonEmpty | typeof EuiButtonIcon | typeof EuiContextMenuItem; enablePopOver?: boolean; field: string; + globalFilters?: Filter[]; onClick: () => void; onFilterAdded?: () => void; ownFocus: boolean; - showTopN: boolean; showTooltip?: boolean; + showTopN: boolean; timelineId?: string | null; value?: string[] | string | null; } @@ -56,6 +58,7 @@ export const ShowTopNButton: React.FC = React.memo( showTopN, timelineId, value, + globalFilters, }) => { const activeScope: SourcererScopeName = timelineId === TimelineId.active @@ -128,9 +131,10 @@ export const ShowTopNButton: React.FC = React.memo( timelineId={timelineId ?? undefined} toggleTopN={onClick} value={value} + globalFilters={globalFilters} /> ), - [browserFields, field, indexPattern, onClick, onFilterAdded, timelineId, value] + [browserFields, field, indexPattern, onClick, onFilterAdded, timelineId, value, globalFilters] ); return showTopN ? ( diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx index 787b7e8f88703..6962ed03e81d4 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx @@ -160,6 +160,60 @@ let testProps = { }; describe('StatefulTopN', () => { + describe('rendering globalFilter', () => { + let wrapper: ReactWrapper; + const globalFilters = [ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'signal.rule.id', + params: { + query: 'd62249f0-1632-11ec-b035-19607969bc20', + }, + }, + query: { + match_phrase: { + 'signal.rule.id': 'd62249f0-1632-11ec-b035-19607969bc20', + }, + }, + }, + ]; + beforeEach(() => { + wrapper = mount( + + + + ); + }); + + test(`provides filters from non Redux state when rendering in alerts table`, () => { + const props = wrapper.find('[data-test-subj="top-n"]').first().props() as Props; + + expect(props.filters).toEqual([ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'signal.rule.id', + params: { + query: 'd62249f0-1632-11ec-b035-19607969bc20', + }, + }, + query: { + match_phrase: { + 'signal.rule.id': 'd62249f0-1632-11ec-b035-19607969bc20', + }, + }, + }, + ]); + }); + }); + describe('rendering in a global NON-timeline context', () => { let wrapper: ReactWrapper; diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx index 2286a53030784..1556f2d0f3d13 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx @@ -41,11 +41,11 @@ const makeMapStateToProps = () => { // The mapped Redux state provided to this component includes the global // filters that appear at the top of most views in the app, and all the // filters in the active timeline: - const mapStateToProps = (state: State) => { + const mapStateToProps = (state: State, ownProps: { globalFilters?: Filter[] }) => { const activeTimeline: TimelineModel = getTimeline(state, TimelineId.active) ?? timelineDefaults; const activeTimelineFilters = activeTimeline.filters ?? EMPTY_FILTERS; const activeTimelineInput: inputsModel.InputsRange = getInputsTimeline(state); - + const { globalFilters } = ownProps; return { activeTimelineEventType: activeTimeline.eventType, activeTimelineFilters: @@ -59,7 +59,7 @@ const makeMapStateToProps = () => { dataProviders: activeTimeline.activeTab === TimelineTabs.query ? activeTimeline.dataProviders : [], globalQuery: getGlobalQuerySelector(state), - globalFilters: getGlobalFiltersQuerySelector(state), + globalFilters: globalFilters ?? getGlobalFiltersQuerySelector(state), kqlMode: activeTimeline.kqlMode, }; }; @@ -82,6 +82,7 @@ export interface OwnProps { toggleTopN: () => void; onFilterAdded?: () => void; value?: string[] | string | null; + globalFilters?: Filter[]; } type PropsFromRedux = ConnectedProps; type Props = OwnProps & PropsFromRedux; diff --git a/x-pack/plugins/security_solution/public/common/experimental_features_service.ts b/x-pack/plugins/security_solution/public/common/experimental_features_service.ts new file mode 100644 index 0000000000000..813341f175408 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/experimental_features_service.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ExperimentalFeatures } from '../../common/experimental_features'; + +export class ExperimentalFeaturesService { + private static experimentalFeatures?: ExperimentalFeatures; + + public static init({ experimentalFeatures }: { experimentalFeatures: ExperimentalFeatures }) { + this.experimentalFeatures = experimentalFeatures; + } + + public static get(): ExperimentalFeatures { + if (!this.experimentalFeatures) { + this.throwUninitializedError(); + } + + return this.experimentalFeatures; + } + + private static throwUninitializedError(): never { + throw new Error( + 'Experimental features services not initialized - are you trying to import this module from outside of the Security Solution app?' + ); + } +} diff --git a/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx b/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx index 8279613e67db7..149a0c62b8b6a 100644 --- a/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx +++ b/x-pack/plugins/security_solution/public/common/lib/cell_actions/default_cell_actions.tsx @@ -6,6 +6,7 @@ */ import React, { useCallback, useState, useMemo } from 'react'; +import { Filter } from '../../../../../../../src/plugins/data/public'; import type { BrowserFields, @@ -167,11 +168,13 @@ export const defaultCellActions: TGridCellAction[] = [ ({ browserFields, data, + globalFilters, timelineId, pageSize, }: { browserFields: BrowserFields; data: TimelineNonEcsData[][]; + globalFilters?: Filter[]; timelineId: string; pageSize: number; }) => @@ -205,6 +208,7 @@ export const defaultCellActions: TGridCellAction[] = [ enablePopOver data-test-subj="hover-actions-show-top-n" field={columnId} + globalFilters={globalFilters} onClick={onClick} onFilterAdded={onFilterAdded} ownFocus={false} diff --git a/x-pack/plugins/security_solution/public/common/utils/exceptions/index.ts b/x-pack/plugins/security_solution/public/common/utils/exceptions/index.ts new file mode 100644 index 0000000000000..bc4b93112963f --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/utils/exceptions/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const isIndexNotFoundError = (error: unknown): boolean => + ( + error as { + attributes?: { caused_by?: { type?: string } }; + } + ).attributes?.caused_by?.type === 'index_not_found_exception'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx index 3dfcc62e26a66..785afa49c9791 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx @@ -11,7 +11,11 @@ import styled from 'styled-components'; import { isEqual } from 'lodash'; import { IndexPattern } from 'src/plugins/data/public'; -import { DEFAULT_INDEX_KEY, DEFAULT_THREAT_INDEX_KEY } from '../../../../../common/constants'; +import { + DEFAULT_INDEX_KEY, + DEFAULT_THREAT_INDEX_KEY, + DEFAULT_THREAT_MATCH_QUERY, +} from '../../../../../common/constants'; import { DEFAULT_TIMELINE_TITLE } from '../../../../timelines/components/timeline/translations'; import { isMlRule } from '../../../../../common/machine_learning/helpers'; import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions'; @@ -72,7 +76,7 @@ const stepDefineDefaultValue: DefineStepRule = { saved_id: undefined, }, threatQueryBar: { - query: { query: '*:*', language: 'kuery' }, + query: { query: DEFAULT_THREAT_MATCH_QUERY, language: 'kuery' }, filters: [], saved_id: undefined, }, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index 8de3f0065f5f9..70d7faa47b9ee 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -391,7 +391,6 @@ const RuleDetailsPageComponent: React.FC = ({ const alertsTableDefaultFilters = useMemo( () => [ ...buildAlertsRuleIdFilter(ruleId), - ...filters, ...(ruleRegistryEnabled ? [ // TODO: Once we are past experimental phase this code should be removed @@ -400,7 +399,7 @@ const RuleDetailsPageComponent: React.FC = ({ : [...buildShowBuildingBlockFilter(showBuildingBlockAlerts)]), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ], - [ruleId, filters, ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] + [ruleId, ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] ); const alertMergedFilters = useMemo( diff --git a/x-pack/plugins/security_solution/public/management/common/routing.ts b/x-pack/plugins/security_solution/public/management/common/routing.ts index b4776f328cf15..58fbd64faf8a6 100644 --- a/x-pack/plugins/security_solution/public/management/common/routing.ts +++ b/x-pack/plugins/security_solution/public/management/common/routing.ts @@ -26,6 +26,7 @@ import { appendSearch } from '../../common/components/link_to/helpers'; import { EndpointIndexUIQueryParams } from '../pages/endpoint_hosts/types'; import { TrustedAppsListPageLocation } from '../pages/trusted_apps/state'; import { EventFiltersPageLocation } from '../pages/event_filters/types'; +import { PolicyDetailsArtifactsPageLocation } from '../pages/policy/types'; // Taken from: https://github.com/microsoft/TypeScript/issues/12936#issuecomment-559034150 type ExactKeys = Exclude extends never ? T1 : never; @@ -160,6 +161,25 @@ const normalizeTrustedAppsPageLocation = ( } }; +const normalizePolicyDetailsArtifactsListPageLocation = ( + location?: Partial +): Partial => { + if (location) { + return { + ...(!isDefaultOrMissing(location.page_index, MANAGEMENT_DEFAULT_PAGE) + ? { page_index: location.page_index } + : {}), + ...(!isDefaultOrMissing(location.page_size, MANAGEMENT_DEFAULT_PAGE_SIZE) + ? { page_size: location.page_size } + : {}), + ...(!isDefaultOrMissing(location.show, undefined) ? { show: location.show } : {}), + ...(!isDefaultOrMissing(location.filter, '') ? { filter: location.filter } : ''), + }; + } else { + return {}; + } +}; + const normalizeEventFiltersPageLocation = ( location?: Partial ): Partial => { @@ -257,6 +277,34 @@ export const getTrustedAppsListPath = (location?: Partial { + const showParamValue = extractFirstParamValue( + query, + 'show' + ) as PolicyDetailsArtifactsPageLocation['show']; + + return { + ...extractListPaginationParams(query), + show: showParamValue && 'list' === showParamValue ? showParamValue : undefined, + }; +}; + +export const getPolicyDetailsArtifactsListPath = ( + policyId: string, + location?: Partial +): string => { + const path = generatePath(MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH, { + tabName: AdministrationSubTab.policies, + policyId, + }); + + return `${path}${appendSearch( + querystring.stringify(normalizePolicyDetailsArtifactsListPageLocation(location)) + )}`; +}; + export const extractEventFiltetrsPageLocation = ( query: querystring.ParsedUrlQuery ): EventFiltersPageLocation => { diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.test.tsx index 624a3c265c4c0..1cb21c7da1703 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.test.tsx @@ -92,7 +92,7 @@ describe('when rendering the endpoint list `AdminSearchBar`', () => { ])( 'should update the url and exclude the `admin_query` param when %s was entered', async (_, value) => { - await render(); + await render({ admin_query: "(language:kuery,query:'foo')" }); await submitQuery(value); expect(getQueryParamsFromStore().admin_query).toBe(undefined); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.tsx index 2f2a1666b6f52..18d22e0cd1b15 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.tsx @@ -24,7 +24,7 @@ const AdminQueryBar = styled.div` export const AdminSearchBar = memo(() => { const history = useHistory(); - const queryParams = useEndpointSelector(selectors.uiQueryParams); + const { admin_query: _, ...queryParams } = useEndpointSelector(selectors.uiQueryParams); const searchBarIndexPatterns = useEndpointSelector(selectors.patterns); const searchBarQuery = useEndpointSelector(selectors.searchBarQuery); const clonedIndexPatterns = useMemo( diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/policy_response_friendly_names.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/policy_response_friendly_names.ts index a9c2676396e83..3551d00c50c73 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/policy_response_friendly_names.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/policy_response_friendly_names.ts @@ -243,6 +243,18 @@ responseMap.set( defaultMessage: 'Events', }) ); +responseMap.set( + 'memory_protection', + i18n.translate('xpack.securitySolution.endpoint.details.policyResponse.memory_protection', { + defaultMessage: 'Memory Threat', + }) +); +responseMap.set( + 'behavior_protection', + i18n.translate('xpack.securitySolution.endpoint.details.policyResponse.behavior_protection', { + defaultMessage: 'Malicious Behavior', + }) +); /** * Maps a server provided value to corresponding i18n'd string. diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/index.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/index.ts new file mode 100644 index 0000000000000..ab84bb4f253ea --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PolicySettingsAction } from './policy_settings_action'; +import { PolicyTrustedAppsAction } from './policy_trusted_apps_action'; + +export type PolicyDetailsAction = PolicySettingsAction | PolicyTrustedAppsAction; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/policy_settings_action.ts similarity index 83% rename from x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action.ts rename to x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/policy_settings_action.ts index 6bd39e9c24f96..eec0ab1c6445c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/policy_settings_action.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { ILicense } from '../../../../../../../licensing/common/types'; -import { GetAgentStatusResponse } from '../../../../../../../fleet/common/types/rest_spec'; -import { PolicyData, UIPolicyConfig } from '../../../../../../common/endpoint/types'; -import { ServerApiError } from '../../../../../common/types'; -import { PolicyDetailsState } from '../../types'; +import { ILicense } from '../../../../../../../../licensing/common/types'; +import { GetAgentStatusResponse } from '../../../../../../../../fleet/common/types/rest_spec'; +import { PolicyData, UIPolicyConfig } from '../../../../../../../common/endpoint/types'; +import { ServerApiError } from '../../../../../../common/types'; +import { PolicyDetailsState } from '../../../types'; export interface ServerReturnedPolicyDetailsData { type: 'serverReturnedPolicyDetailsData'; @@ -69,7 +69,7 @@ export interface LicenseChanged { payload: ILicense; } -export type PolicyDetailsAction = +export type PolicySettingsAction = | ServerReturnedPolicyDetailsData | UserClickedPolicyDetailsSaveButton | ServerReturnedPolicyDetailsAgentSummaryData diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/policy_trusted_apps_action.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/policy_trusted_apps_action.ts new file mode 100644 index 0000000000000..46e0f8293cc33 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/action/policy_trusted_apps_action.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// TODO: defined trusted apps actions (code below only here to silence TS) +export type PolicyTrustedAppsAction = + | { + type: 'a'; + } + | { type: 'b' }; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.ts index bc83c7438eba8..bc9e42ddf7f52 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.ts @@ -11,8 +11,7 @@ import { AppAction } from '../../../../../common/store/actions'; import { Immutable } from '../../../../../../common/endpoint/types'; export { policyDetailsMiddlewareFactory } from './middleware'; -export { PolicyDetailsAction } from './action'; -export { policyDetailsReducer } from './reducer'; +export { policyDetailsReducer, initialPolicyDetailsState } from './reducer'; export interface EndpointPolicyDetailsStatePluginState { policyDetails: Immutable; @@ -21,3 +20,4 @@ export interface EndpointPolicyDetailsStatePluginState { export interface EndpointPolicyDetailsStatePluginReducer { policyDetails: ImmutableReducer; } +export { PolicyDetailsAction } from './action'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware.ts deleted file mode 100644 index 3d90b8d640ac8..0000000000000 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware.ts +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IHttpFetchError } from 'kibana/public'; -import { - DefaultPolicyNotificationMessage, - DefaultPolicyRuleNotificationMessage, -} from '../../../../../../common/endpoint/models/policy_config'; -import { PolicyDetailsState, UpdatePolicyResponse } from '../../types'; -import { - policyIdFromParams, - isOnPolicyDetailsPage, - policyDetails, - policyDetailsForUpdate, - needsToRefresh, -} from './selectors'; -import { - sendGetPackagePolicy, - sendGetFleetAgentStatusForPolicy, - sendPutPackagePolicy, -} from '../services/ingest'; -import { NewPolicyData, PolicyData } from '../../../../../../common/endpoint/types'; -import { ImmutableMiddlewareFactory } from '../../../../../common/store'; -import { getPolicyDataForUpdate } from '../../../../../../common/endpoint/service/policy/get_policy_data_for_update'; - -export const policyDetailsMiddlewareFactory: ImmutableMiddlewareFactory = ( - coreStart -) => { - const http = coreStart.http; - return ({ getState, dispatch }) => - (next) => - async (action) => { - next(action); - const state = getState(); - - if ( - action.type === 'userChangedUrl' && - needsToRefresh(state) && - isOnPolicyDetailsPage(state) - ) { - const id = policyIdFromParams(state); - let policyItem: PolicyData; - - try { - policyItem = (await sendGetPackagePolicy(http, id)).item; - // sets default user notification message if policy config message is empty - if (policyItem.inputs[0].config.policy.value.windows.popup.malware.message === '') { - policyItem.inputs[0].config.policy.value.windows.popup.malware.message = - DefaultPolicyNotificationMessage; - policyItem.inputs[0].config.policy.value.mac.popup.malware.message = - DefaultPolicyNotificationMessage; - policyItem.inputs[0].config.policy.value.linux.popup.malware.message = - DefaultPolicyNotificationMessage; - } - if (policyItem.inputs[0].config.policy.value.windows.popup.ransomware.message === '') { - policyItem.inputs[0].config.policy.value.windows.popup.ransomware.message = - DefaultPolicyNotificationMessage; - } - if ( - policyItem.inputs[0].config.policy.value.windows.popup.memory_protection.message === '' - ) { - policyItem.inputs[0].config.policy.value.windows.popup.memory_protection.message = - DefaultPolicyRuleNotificationMessage; - } - if ( - policyItem.inputs[0].config.policy.value.windows.popup.behavior_protection.message === - '' - ) { - policyItem.inputs[0].config.policy.value.windows.popup.behavior_protection.message = - DefaultPolicyRuleNotificationMessage; - } - if ( - policyItem.inputs[0].config.policy.value.mac.popup.behavior_protection.message === '' - ) { - policyItem.inputs[0].config.policy.value.mac.popup.behavior_protection.message = - DefaultPolicyRuleNotificationMessage; - } - if ( - policyItem.inputs[0].config.policy.value.linux.popup.behavior_protection.message === '' - ) { - policyItem.inputs[0].config.policy.value.linux.popup.behavior_protection.message = - DefaultPolicyRuleNotificationMessage; - } - } catch (error) { - dispatch({ - type: 'serverFailedToReturnPolicyDetailsData', - payload: error.body || error, - }); - return; - } - - dispatch({ - type: 'serverReturnedPolicyDetailsData', - payload: { - policyItem, - }, - }); - - // Agent summary is secondary data, so its ok for it to come after the details - // page is populated with the main content - if (policyItem.policy_id) { - const { results } = await sendGetFleetAgentStatusForPolicy(http, policyItem.policy_id); - dispatch({ - type: 'serverReturnedPolicyDetailsAgentSummaryData', - payload: { - agentStatusSummary: results, - }, - }); - } - } else if (action.type === 'userClickedPolicyDetailsSaveButton') { - const { id } = policyDetails(state) as PolicyData; - const updatedPolicyItem = policyDetailsForUpdate(state) as NewPolicyData; - - let apiResponse: UpdatePolicyResponse; - try { - apiResponse = await sendPutPackagePolicy(http, id, updatedPolicyItem).catch( - (error: IHttpFetchError) => { - if (!error.response || error.response.status !== 409) { - return Promise.reject(error); - } - // Handle 409 error (version conflict) here, by using the latest document - // for the package policy and adding the updated policy to it, ensuring that - // any recent updates to `manifest_artifacts` are retained. - return sendGetPackagePolicy(http, id).then((packagePolicy) => { - const latestUpdatedPolicyItem = packagePolicy.item; - latestUpdatedPolicyItem.inputs[0].config.policy = - updatedPolicyItem.inputs[0].config.policy; - - return sendPutPackagePolicy( - http, - id, - getPolicyDataForUpdate(latestUpdatedPolicyItem) - ); - }); - } - ); - } catch (error) { - dispatch({ - type: 'serverReturnedPolicyDetailsUpdateFailure', - payload: { - success: false, - error: error.body || error, - }, - }); - return; - } - - dispatch({ - type: 'serverReturnedUpdatedPolicyDetailsData', - payload: { - policyItem: apiResponse.item, - updateStatus: { - success: true, - }, - }, - }); - } - }; -}; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/index.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/index.ts new file mode 100644 index 0000000000000..6b7e4e7d541c8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ImmutableMiddlewareFactory } from '../../../../../../common/store'; +import { PolicyDetailsState } from '../../../types'; +import { policyTrustedAppsMiddlewareRunner } from './policy_trusted_apps_middleware'; +import { policySettingsMiddlewareRunner } from './policy_settings_middleware'; + +export const policyDetailsMiddlewareFactory: ImmutableMiddlewareFactory = ( + coreStart +) => { + return (store) => (next) => async (action) => { + next(action); + + policySettingsMiddlewareRunner(coreStart, store, action); + policyTrustedAppsMiddlewareRunner(coreStart, store, action); + }; +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts new file mode 100644 index 0000000000000..73b244944e502 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts @@ -0,0 +1,144 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IHttpFetchError } from 'kibana/public'; +import { + DefaultPolicyNotificationMessage, + DefaultPolicyRuleNotificationMessage, +} from '../../../../../../../common/endpoint/models/policy_config'; +import { MiddlewareRunner, UpdatePolicyResponse } from '../../../types'; +import { + policyIdFromParams, + isOnPolicyDetailsPage, + policyDetails, + policyDetailsForUpdate, + needsToRefresh, +} from '../selectors/policy_settings_selectors'; +import { + sendGetPackagePolicy, + sendGetFleetAgentStatusForPolicy, + sendPutPackagePolicy, +} from '../../services/ingest'; +import { NewPolicyData, PolicyData } from '../../../../../../../common/endpoint/types'; +import { getPolicyDataForUpdate } from '../../../../../../../common/endpoint/service/policy'; + +export const policySettingsMiddlewareRunner: MiddlewareRunner = async ( + coreStart, + { dispatch, getState }, + action +) => { + const http = coreStart.http; + const state = getState(); + + if (action.type === 'userChangedUrl' && needsToRefresh(state) && isOnPolicyDetailsPage(state)) { + const id = policyIdFromParams(state); + let policyItem: PolicyData; + + try { + policyItem = (await sendGetPackagePolicy(http, id)).item; + // sets default user notification message if policy config message is empty + if (policyItem.inputs[0].config.policy.value.windows.popup.malware.message === '') { + policyItem.inputs[0].config.policy.value.windows.popup.malware.message = + DefaultPolicyNotificationMessage; + policyItem.inputs[0].config.policy.value.mac.popup.malware.message = + DefaultPolicyNotificationMessage; + policyItem.inputs[0].config.policy.value.linux.popup.malware.message = + DefaultPolicyNotificationMessage; + } + if (policyItem.inputs[0].config.policy.value.windows.popup.ransomware.message === '') { + policyItem.inputs[0].config.policy.value.windows.popup.ransomware.message = + DefaultPolicyNotificationMessage; + } + if (policyItem.inputs[0].config.policy.value.windows.popup.memory_protection.message === '') { + policyItem.inputs[0].config.policy.value.windows.popup.memory_protection.message = + DefaultPolicyRuleNotificationMessage; + } + if ( + policyItem.inputs[0].config.policy.value.windows.popup.behavior_protection.message === '' + ) { + policyItem.inputs[0].config.policy.value.windows.popup.behavior_protection.message = + DefaultPolicyRuleNotificationMessage; + } + if (policyItem.inputs[0].config.policy.value.mac.popup.behavior_protection.message === '') { + policyItem.inputs[0].config.policy.value.mac.popup.behavior_protection.message = + DefaultPolicyRuleNotificationMessage; + } + if (policyItem.inputs[0].config.policy.value.linux.popup.behavior_protection.message === '') { + policyItem.inputs[0].config.policy.value.linux.popup.behavior_protection.message = + DefaultPolicyRuleNotificationMessage; + } + } catch (error) { + dispatch({ + type: 'serverFailedToReturnPolicyDetailsData', + payload: error.body || error, + }); + return; + } + + dispatch({ + type: 'serverReturnedPolicyDetailsData', + payload: { + policyItem, + }, + }); + + // Agent summary is secondary data, so its ok for it to come after the details + // page is populated with the main content + if (policyItem.policy_id) { + const { results } = await sendGetFleetAgentStatusForPolicy(http, policyItem.policy_id); + dispatch({ + type: 'serverReturnedPolicyDetailsAgentSummaryData', + payload: { + agentStatusSummary: results, + }, + }); + } + } else if (action.type === 'userClickedPolicyDetailsSaveButton') { + const { id } = policyDetails(state) as PolicyData; + const updatedPolicyItem = policyDetailsForUpdate(state) as NewPolicyData; + + let apiResponse: UpdatePolicyResponse; + try { + apiResponse = await sendPutPackagePolicy(http, id, updatedPolicyItem).catch( + (error: IHttpFetchError) => { + if (!error.response || error.response.status !== 409) { + return Promise.reject(error); + } + // Handle 409 error (version conflict) here, by using the latest document + // for the package policy and adding the updated policy to it, ensuring that + // any recent updates to `manifest_artifacts` are retained. + return sendGetPackagePolicy(http, id).then((packagePolicy) => { + const latestUpdatedPolicyItem = packagePolicy.item; + latestUpdatedPolicyItem.inputs[0].config.policy = + updatedPolicyItem.inputs[0].config.policy; + + return sendPutPackagePolicy(http, id, getPolicyDataForUpdate(latestUpdatedPolicyItem)); + }); + } + ); + } catch (error) { + dispatch({ + type: 'serverReturnedPolicyDetailsUpdateFailure', + payload: { + success: false, + error: error.body || error, + }, + }); + return; + } + + dispatch({ + type: 'serverReturnedUpdatedPolicyDetailsData', + payload: { + policyItem: apiResponse.item, + updateStatus: { + success: true, + }, + }, + }); + } +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_trusted_apps_middleware.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_trusted_apps_middleware.ts new file mode 100644 index 0000000000000..171bbd881302e --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_trusted_apps_middleware.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MiddlewareRunner } from '../../../types'; + +export const policyTrustedAppsMiddlewareRunner: MiddlewareRunner = async ( + coreStart, + store, + action +) => { + // FIXME: implement middlware for trusted apps +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/index.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/index.ts new file mode 100644 index 0000000000000..a577c1ca85ef0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ImmutableReducer } from '../../../../../../common/store'; +import { PolicyDetailsState } from '../../../types'; +import { AppAction } from '../../../../../../common/store/actions'; +import { policySettingsReducer } from './policy_settings_reducer'; +import { initialPolicyDetailsState } from './initial_policy_details_state'; +import { policyTrustedAppsReducer } from './trusted_apps_reducer'; + +export * from './initial_policy_details_state'; + +export const policyDetailsReducer: ImmutableReducer = ( + state = initialPolicyDetailsState(), + action +) => { + return [policySettingsReducer, policyTrustedAppsReducer].reduce( + (updatedState, runReducer) => runReducer(updatedState, action), + state + ); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/initial_policy_details_state.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/initial_policy_details_state.ts new file mode 100644 index 0000000000000..723f8fe31bd2a --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/initial_policy_details_state.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Immutable } from '../../../../../../../common/endpoint/types'; +import { PolicyDetailsState } from '../../../types'; +import { + MANAGEMENT_DEFAULT_PAGE, + MANAGEMENT_DEFAULT_PAGE_SIZE, +} from '../../../../../common/constants'; +import { createUninitialisedResourceState } from '../../../../../state'; + +/** + * Return a fresh copy of initial state, since we mutate state in the reducer. + */ +export const initialPolicyDetailsState: () => Immutable = () => ({ + policyItem: undefined, + isLoading: false, + agentStatusSummary: { + error: 0, + events: 0, + offline: 0, + online: 0, + total: 0, + other: 0, + }, + artifacts: { + location: { + page_index: MANAGEMENT_DEFAULT_PAGE, + page_size: MANAGEMENT_DEFAULT_PAGE_SIZE, + show: undefined, + filter: '', + }, + availableList: createUninitialisedResourceState(), + }, +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/policy_settings_reducer.ts similarity index 81% rename from x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer.ts rename to x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/policy_settings_reducer.ts index 512059e9c3aab..9997e547e8148 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/policy_settings_reducer.ts @@ -5,16 +5,20 @@ * 2.0. */ -import { fullPolicy, isOnPolicyDetailsPage, license } from './selectors'; +// eslint-disable-next-line import/no-nodejs-modules +import { parse } from 'querystring'; +import { fullPolicy, isOnPolicyDetailsPage, license } from '../selectors/policy_settings_selectors'; import { Immutable, PolicyConfig, - UIPolicyConfig, PolicyData, -} from '../../../../../../common/endpoint/types'; -import { ImmutableReducer } from '../../../../../common/store'; -import { AppAction } from '../../../../../common/store/actions'; -import { PolicyDetailsState } from '../../types'; + UIPolicyConfig, +} from '../../../../../../../common/endpoint/types'; +import { ImmutableReducer } from '../../../../../../common/store'; +import { AppAction } from '../../../../../../common/store/actions'; +import { PolicyDetailsState } from '../../../types'; +import { extractPolicyDetailsArtifactsListPageLocation } from '../../../../../common/routing'; +import { initialPolicyDetailsState } from './initial_policy_details_state'; const updatePolicyConfigInPolicyData = ( policyData: Immutable, @@ -33,23 +37,7 @@ const updatePolicyConfigInPolicyData = ( })), }); -/** - * Return a fresh copy of initial state, since we mutate state in the reducer. - */ -export const initialPolicyDetailsState: () => Immutable = () => ({ - policyItem: undefined, - isLoading: false, - agentStatusSummary: { - error: 0, - events: 0, - offline: 0, - online: 0, - total: 0, - other: 0, - }, -}); - -export const policyDetailsReducer: ImmutableReducer = ( +export const policySettingsReducer: ImmutableReducer = ( state = initialPolicyDetailsState(), action ) => { @@ -106,6 +94,12 @@ export const policyDetailsReducer: ImmutableReducer = { ...state, location: action.payload, + artifacts: { + ...state.artifacts, + location: extractPolicyDetailsArtifactsListPageLocation( + parse(action.payload.search.slice(1)) + ), + }, }; const isCurrentlyOnDetailsPage = isOnPolicyDetailsPage(newState); const wasPreviouslyOnDetailsPage = isOnPolicyDetailsPage(state); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/trusted_apps_reducer.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/trusted_apps_reducer.ts new file mode 100644 index 0000000000000..7f2f9e437ca06 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/reducer/trusted_apps_reducer.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ImmutableReducer } from '../../../../../../common/store'; +import { PolicyDetailsState } from '../../../types'; +import { AppAction } from '../../../../../../common/store/actions'; +import { initialPolicyDetailsState } from './initial_policy_details_state'; + +export const policyTrustedAppsReducer: ImmutableReducer = ( + state = initialPolicyDetailsState(), + action +) => { + // FIXME: implement trusted apps reducer + return state; +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/index.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/index.ts new file mode 100644 index 0000000000000..af5be5c39480e --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './policy_settings_selectors'; +export * from './trusted_apps_selectors'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_settings_selectors.ts similarity index 92% rename from x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts rename to x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_settings_selectors.ts index 017111da8d884..23ab0fd73c9e1 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_settings_selectors.ts @@ -7,23 +7,23 @@ import { createSelector } from 'reselect'; import { matchPath } from 'react-router-dom'; -import { ILicense } from '../../../../../../../licensing/common/types'; -import { unsetPolicyFeaturesAccordingToLicenseLevel } from '../../../../../../common/license/policy_config'; -import { PolicyDetailsState } from '../../types'; +import { ILicense } from '../../../../../../../../licensing/common/types'; +import { unsetPolicyFeaturesAccordingToLicenseLevel } from '../../../../../../../common/license/policy_config'; +import { PolicyDetailsArtifactsPageLocation, PolicyDetailsState } from '../../../types'; import { Immutable, NewPolicyData, PolicyConfig, PolicyData, UIPolicyConfig, -} from '../../../../../../common/endpoint/types'; -import { policyFactory as policyConfigFactory } from '../../../../../../common/endpoint/models/policy_config'; +} from '../../../../../../../common/endpoint/types'; +import { policyFactory as policyConfigFactory } from '../../../../../../../common/endpoint/models/policy_config'; import { MANAGEMENT_ROUTING_POLICY_DETAILS_FORM_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH, -} from '../../../../common/constants'; -import { ManagementRoutePolicyDetailsParams } from '../../../../types'; -import { getPolicyDataForUpdate } from '../../../../../../common/endpoint/service/policy/get_policy_data_for_update'; +} from '../../../../../common/constants'; +import { ManagementRoutePolicyDetailsParams } from '../../../../../types'; +import { getPolicyDataForUpdate } from '../../../../../../../common/endpoint/service/policy/get_policy_data_for_update'; /** Returns the policy details */ export const policyDetails = (state: Immutable) => state.policyItem; @@ -80,6 +80,13 @@ export const needsToRefresh = (state: Immutable): boolean => return !state.policyItem && !state.apiError; }; +/** + * Returns current artifacts location + */ +export const getCurrentArtifactsLocation = ( + state: Immutable +): Immutable => state.artifacts.location; + /** Returns a boolean of whether the user is on the policy form page or not */ export const isOnPolicyFormPage = (state: Immutable) => { return ( diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.ts new file mode 100644 index 0000000000000..f7a568b5ade0e --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/trusted_apps_selectors.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const isOnTrustedAppsView = () => { + return true; +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/types.ts b/x-pack/plugins/security_solution/public/management/pages/policy/types.ts index 6d767df73cd1c..9000fb469afd3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/types.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { CoreStart } from 'kibana/public'; import { ILicense } from '../../../../../licensing/common/types'; import { AppLocation, @@ -12,6 +13,7 @@ import { ProtectionFields, PolicyData, UIPolicyConfig, + MaybeImmutable, } from '../../../../common/endpoint/types'; import { ServerApiError } from '../../../common/types'; import { @@ -21,6 +23,19 @@ import { GetPackagesResponse, UpdatePackagePolicyResponse, } from '../../../../../fleet/common'; +import { AsyncResourceState } from '../../state'; +import { TrustedAppsListData } from '../trusted_apps/state'; +import { ImmutableMiddlewareAPI } from '../../../common/store'; +import { AppAction } from '../../../common/store/actions'; + +/** + * Function that runs Policy Details middleware + */ +export type MiddlewareRunner = ( + coreStart: CoreStart, + store: ImmutableMiddlewareAPI, + action: MaybeImmutable +) => Promise; /** * Policy list store state @@ -61,6 +76,8 @@ export interface PolicyDetailsState { isLoading: boolean; /** current location of the application */ location?: Immutable; + /** artifacts namespace inside policy details page */ + artifacts: PolicyArtifactsState; /** A summary of stats for the agents associated with a given Fleet Agent Policy */ agentStatusSummary?: Omit; /** Status of an update to the policy */ @@ -72,12 +89,29 @@ export interface PolicyDetailsState { license?: ILicense; } +/** + * Policy artifacts store state + */ +export interface PolicyArtifactsState { + /** artifacts location params */ + location: PolicyDetailsArtifactsPageLocation; + /** A list of artifacts can be linked to the policy */ + availableList: AsyncResourceState; +} + export enum OS { windows = 'windows', mac = 'mac', linux = 'linux', } +export interface PolicyDetailsArtifactsPageLocation { + page_index: number; + page_size: number; + show?: 'list'; + filter: string; +} + /** * Returns the keys of an object whose values meet a criteria. * Ex) interface largeNestedObject = { diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/components/antivirus_registration_form/index.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/components/antivirus_registration_form/index.tsx index 51edf1a200c53..45aad6c3d1432 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/components/antivirus_registration_form/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/components/antivirus_registration_form/index.tsx @@ -13,7 +13,7 @@ import { EuiSpacer, EuiSwitch, EuiText } from '@elastic/eui'; import { OperatingSystem } from '../../../../../../../common/endpoint/types'; import { isAntivirusRegistrationEnabled } from '../../../store/policy_details/selectors'; import { usePolicyDetailsSelector } from '../../policy_hooks'; -import { ConfigForm } from '../../components/config_form'; +import { ConfigForm } from '../config_form'; const TRANSLATIONS: Readonly<{ [K in 'title' | 'description' | 'label']: string }> = { title: i18n.translate( diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx index ed3d9967f318e..5f0c5cca0ad2c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx @@ -5,9 +5,10 @@ * 2.0. */ +import React, { FC, memo, useCallback } from 'react'; import { EuiBadge, EuiBadgeProps, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; -import React, { FC, memo } from 'react'; import { i18n } from '@kbn/i18n'; +import styled from 'styled-components'; import { GetExceptionSummaryResponse } from '../../../../../../../../common/endpoint/types'; const SUMMARY_KEYS: Readonly> = [ @@ -36,46 +37,76 @@ const SUMMARY_LABELS: Readonly<{ [key in keyof GetExceptionSummaryResponse]: str ), }; +export const StyledEuiFlexGridGroup = styled(EuiFlexGroup)` + display: grid; + min-width: 240px; + grid-template-columns: 50% 50%; +`; + +const StyledEuiFlexGroup = styled(EuiFlexGroup)<{ + isSmall: boolean; +}>` + font-size: ${({ isSmall, theme }) => (isSmall ? theme.eui.euiFontSizeXS : 'innherit')}; + font-weight: ${({ isSmall }) => (isSmall ? '1px' : 'innherit')}; +`; + const CSS_BOLD: Readonly = { fontWeight: 'bold' }; interface ExceptionItemsSummaryProps { stats: GetExceptionSummaryResponse | undefined; + isSmall?: boolean; } -export const ExceptionItemsSummary = memo(({ stats }) => { - return ( - - {SUMMARY_KEYS.map((stat) => { - return ( - - - {SUMMARY_LABELS[stat]} - - - ); - })} - - ); -}); +export const ExceptionItemsSummary = memo( + ({ stats, isSmall = false }) => { + const getItem = useCallback( + (stat: keyof GetExceptionSummaryResponse) => ( + + + {SUMMARY_LABELS[stat]} + + + ), + [stats, isSmall] + ); + + return ( + + {SUMMARY_KEYS.map((stat) => getItem(stat))} + + ); + } +); ExceptionItemsSummary.displayName = 'ExceptionItemsSummary'; -const SummaryStat: FC<{ value: number; color?: EuiBadgeProps['color'] }> = memo( - ({ children, value, color, ...commonProps }) => { +const SummaryStat: FC<{ value: number; color?: EuiBadgeProps['color']; isSmall?: boolean }> = memo( + ({ children, value, color, isSmall = false, ...commonProps }) => { return ( - - + + {children} {value} - + ); } diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx index 22e1c3a612eb7..41768f4be7d2e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx @@ -46,15 +46,17 @@ export const FleetEventFiltersCard = memo( setStats(summary); } } catch (error) { - toasts.addDanger( - i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.eventFiltersSummaryError', - { - defaultMessage: 'There was an error trying to fetch event filters stats: "{error}"', - values: { error }, - } - ) - ); + if (isMounted.current) { + toasts.addDanger( + i18n.translate( + 'xpack.securitySolution.endpoint.fleetCustomExtension.eventFiltersSummaryError', + { + defaultMessage: 'There was an error trying to fetch event filters stats: "{error}"', + values: { error }, + } + ) + ); + } } }; fetchStats(); @@ -78,12 +80,15 @@ export const FleetEventFiltersCard = memo( path: fleetPackageCustomUrlPath, }, ], - backButtonUrl: getAppUrl({ appId: INTEGRATIONS_PLUGIN_ID, path: fleetPackageCustomUrlPath }), + backButtonUrl: getAppUrl({ + appId: INTEGRATIONS_PLUGIN_ID, + path: fleetPackageCustomUrlPath, + }), }; }, [getAppUrl, pkgkey]); return ( - + diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.test.tsx index 22a7072caea02..aa4b36d548604 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { I18nProvider } from '@kbn/i18n/react'; -import { FleetTrustedAppsCard } from './fleet_trusted_apps_card'; +import { FleetTrustedAppsCardWrapper } from './fleet_trusted_apps_card_wrapper'; import * as reactTestingLibrary from '@testing-library/react'; import { TrustedAppsHttpService } from '../../../../../trusted_apps/service'; import { useToasts } from '../../../../../../../common/lib/kibana'; @@ -67,7 +67,9 @@ describe('Fleet trusted apps card', () => { ); // @ts-ignore - const component = reactTestingLibrary.render(, { wrapper: Wrapper }); + const component = reactTestingLibrary.render(, { + wrapper: Wrapper, + }); try { // @ts-ignore await reactTestingLibrary.act(() => promise); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx index 4f10eceb6781c..08e8ec39dbaa8 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx @@ -9,116 +9,87 @@ import React, { memo, useMemo, useState, useEffect, useRef } from 'react'; import { EuiPanel, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { - PackageCustomExtensionComponentProps, - pagePathGetters, -} from '../../../../../../../../../fleet/public'; -import { getTrustedAppsListPath } from '../../../../../../common/routing'; -import { - ListPageRouteState, - GetExceptionSummaryResponse, -} from '../../../../../../../../common/endpoint/types'; -import { INTEGRATIONS_PLUGIN_ID } from '../../../../../../../../../fleet/common'; +import { GetExceptionSummaryResponse } from '../../../../../../../../common/endpoint/types'; -import { useAppUrl } from '../../../../../../../common/lib/kibana/hooks'; import { useKibana, useToasts } from '../../../../../../../common/lib/kibana'; -import { LinkWithIcon } from './link_with_icon'; import { ExceptionItemsSummary } from './exception_items_summary'; import { TrustedAppsHttpService } from '../../../../../trusted_apps/service'; import { StyledEuiFlexGridGroup, StyledEuiFlexGridItem } from './styled_components'; -export const FleetTrustedAppsCard = memo(({ pkgkey }) => { - const { getAppUrl } = useAppUrl(); - const { - services: { http }, - } = useKibana(); - const toasts = useToasts(); - const [stats, setStats] = useState(); - const trustedAppsApi = useMemo(() => new TrustedAppsHttpService(http), [http]); - const isMounted = useRef(); +interface FleetTrustedAppsCardProps { + customLink: React.ReactNode; + policyId?: string; + cardSize?: 'm' | 'l'; +} - useEffect(() => { - isMounted.current = true; - const fetchStats = async () => { - try { - const response = await trustedAppsApi.getTrustedAppsSummary(); - if (isMounted) { - setStats(response); +export const FleetTrustedAppsCard = memo( + ({ customLink, policyId, cardSize = 'l' }) => { + const { + services: { http }, + } = useKibana(); + const toasts = useToasts(); + const [stats, setStats] = useState(); + const trustedAppsApi = useMemo(() => new TrustedAppsHttpService(http), [http]); + const isMounted = useRef(); + + useEffect(() => { + isMounted.current = true; + const fetchStats = async () => { + try { + const response = await trustedAppsApi.getTrustedAppsSummary({ + kuery: policyId + ? `exception-list-agnostic.attributes.tags:"policy:${policyId}" OR exception-list-agnostic.attributes.tags:"policy:all"` + : undefined, + }); + if (isMounted) { + setStats(response); + } + } catch (error) { + if (isMounted.current) { + toasts.addDanger( + i18n.translate( + 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppsSummaryError', + { + defaultMessage: + 'There was an error trying to fetch trusted apps stats: "{error}"', + values: { error }, + } + ) + ); + } } - } catch (error) { - toasts.addDanger( - i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppsSummaryError', - { - defaultMessage: 'There was an error trying to fetch trusted apps stats: "{error}"', - values: { error }, - } - ) - ); - } - }; - fetchStats(); - return () => { - isMounted.current = false; - }; - }, [toasts, trustedAppsApi]); - const trustedAppsListUrlPath = getTrustedAppsListPath(); + }; + fetchStats(); + return () => { + isMounted.current = false; + }; + }, [toasts, trustedAppsApi, policyId]); - const trustedAppRouteState = useMemo(() => { - const fleetPackageCustomUrlPath = `#${ - pagePathGetters.integration_details_custom({ pkgkey })[1] - }`; + const getTitleMessage = () => ( + + ); - return { - backButtonLabel: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.backButtonLabel', - { defaultMessage: 'Back to Endpoint Integration' } - ), - onBackButtonNavigateTo: [ - INTEGRATIONS_PLUGIN_ID, - { - path: fleetPackageCustomUrlPath, - }, - ], - backButtonUrl: getAppUrl({ appId: INTEGRATIONS_PLUGIN_ID, path: fleetPackageCustomUrlPath }), - }; - }, [getAppUrl, pkgkey]); - return ( - - - - -

    - -

    -
    -
    - - - - - <> - - - - - -
    -
    - ); -}); + return ( + + + + + {cardSize === 'l' ?

    {getTitleMessage()}

    :
    {getTitleMessage()}
    } +
    +
    + + + + + {customLink} + +
    +
    + ); + } +); FleetTrustedAppsCard.displayName = 'FleetTrustedAppsCard'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card_wrapper.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card_wrapper.tsx new file mode 100644 index 0000000000000..5ac79a5dd5d5a --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card_wrapper.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + PackageCustomExtensionComponentProps, + pagePathGetters, +} from '../../../../../../../../../fleet/public'; +import { getTrustedAppsListPath } from '../../../../../../common/routing'; +import { ListPageRouteState } from '../../../../../../../../common/endpoint/types'; +import { INTEGRATIONS_PLUGIN_ID } from '../../../../../../../../../fleet/common'; + +import { useAppUrl } from '../../../../../../../common/lib/kibana/hooks'; +import { LinkWithIcon } from './link_with_icon'; +import { FleetTrustedAppsCard } from './fleet_trusted_apps_card'; + +export const FleetTrustedAppsCardWrapper = memo( + ({ pkgkey }) => { + const { getAppUrl } = useAppUrl(); + const trustedAppsListUrlPath = getTrustedAppsListPath(); + + const trustedAppRouteState = useMemo(() => { + const fleetPackageCustomUrlPath = `#${ + pagePathGetters.integration_details_custom({ pkgkey })[1] + }`; + + return { + backButtonLabel: i18n.translate( + 'xpack.securitySolution.endpoint.fleetCustomExtension.backButtonLabel', + { defaultMessage: 'Back to Endpoint Integration' } + ), + onBackButtonNavigateTo: [ + INTEGRATIONS_PLUGIN_ID, + { + path: fleetPackageCustomUrlPath, + }, + ], + backButtonUrl: getAppUrl({ + appId: INTEGRATIONS_PLUGIN_ID, + path: fleetPackageCustomUrlPath, + }), + }; + }, [getAppUrl, pkgkey]); + + const customLink = useMemo( + () => ( + + + + ), + [getAppUrl, trustedAppRouteState, trustedAppsListUrlPath] + ); + return ; + } +); + +FleetTrustedAppsCardWrapper.displayName = 'FleetTrustedAppsCardWrapper'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/link_with_icon.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/link_with_icon.tsx index 6600fcfddde0c..6aebb130eb896 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/link_with_icon.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/link_with_icon.tsx @@ -13,16 +13,23 @@ import { LinkToAppProps, } from '../../../../../../../common/components/endpoint/link_to_app'; -const LinkLabel = styled.span` +const LinkLabel = styled.span<{ + size?: 'm' | 'l'; +}>` display: inline-block; padding-right: ${(props) => props.theme.eui.paddingSizes.s}; + font-size: ${({ size, theme }) => (size === 'm' ? theme.eui.euiFontSizeXS : 'innherit')}; `; -export const LinkWithIcon: FC = memo(({ children, ...props }) => { +type ComponentProps = LinkToAppProps & { + size?: 'm' | 'l'; +}; + +export const LinkWithIcon: FC = memo(({ children, size = 'l', ...props }) => { return ( - {children} - + {children} + ); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx index cb128946d8efa..d2d5de5d43a3f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx @@ -7,9 +7,12 @@ import styled from 'styled-components'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -export const StyledEuiFlexGridGroup = styled(EuiFlexGroup)` +export const StyledEuiFlexGridGroup = styled(EuiFlexGroup)<{ + cardSize?: 'm' | 'l'; +}>` display: grid; - grid-template-columns: 25% 45% 30%; + grid-template-columns: ${({ cardSize = 'l' }) => + cardSize === 'l' ? '25% 45% 30%' : '30% 35% 35%'}; grid-template-areas: 'title summary link'; `; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx index 094f1131d7034..0748a95f63c9f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx @@ -8,14 +8,14 @@ import { EuiSpacer } from '@elastic/eui'; import React, { memo } from 'react'; import { PackageCustomExtensionComponentProps } from '../../../../../../../../fleet/public'; -import { FleetTrustedAppsCard } from './components/fleet_trusted_apps_card'; +import { FleetTrustedAppsCardWrapper } from './components/fleet_trusted_apps_card_wrapper'; import { FleetEventFiltersCard } from './components/fleet_event_filters_card'; export const EndpointPackageCustomExtension = memo( (props) => { return (
    - +
    diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_policy_edit_extension.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_policy_edit_extension.tsx index fe321e6a321c2..0a912598c5722 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_policy_edit_extension.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_policy_edit_extension.tsx @@ -5,19 +5,27 @@ * 2.0. */ -import React, { memo, useEffect, useState } from 'react'; -import { EuiSpacer } from '@elastic/eui'; +import React, { memo, useEffect, useState, useMemo } from 'react'; +import { EuiSpacer, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { useDispatch } from 'react-redux'; import { PackagePolicyEditExtensionComponentProps, NewPackagePolicy, + pagePathGetters, } from '../../../../../../../fleet/public'; -import { getPolicyDetailPath } from '../../../../common/routing'; +import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; +import { INTEGRATIONS_PLUGIN_ID } from '../../../../../../../fleet/common'; +import { useAppUrl } from '../../../../../common/lib/kibana/hooks'; +import { PolicyDetailsRouteState } from '../../../../../../common/endpoint/types'; +import { getPolicyDetailPath, getPolicyTrustedAppsPath } from '../../../../common/routing'; import { PolicyDetailsForm } from '../policy_details_form'; import { AppAction } from '../../../../../common/store/actions'; import { usePolicyDetailsSelector } from '../policy_hooks'; import { policyDetailsForUpdate } from '../../store/policy_details/selectors'; - +import { FleetTrustedAppsCard } from './endpoint_package_custom_extension/components/fleet_trusted_apps_card'; +import { LinkWithIcon } from './endpoint_package_custom_extension/components/link_with_icon'; /** * Exports Endpoint-specific package policy instructions * for use in the Ingest app create / edit package policy @@ -40,7 +48,12 @@ const WrappedPolicyDetailsForm = memo<{ }>(({ policyId, onChange }) => { const dispatch = useDispatch<(a: AppAction) => void>(); const updatedPolicy = usePolicyDetailsSelector(policyDetailsForUpdate); + const { getAppUrl } = useAppUrl(); const [, setLastUpdatedPolicy] = useState(updatedPolicy); + // TODO: Remove this and related code when removing FF + const isTrustedAppsByPolicyEnabled = useIsExperimentalFeatureEnabled( + 'trustedAppsByPolicyEnabled' + ); // When the form is initially displayed, trigger the Redux middleware which is based on // the location information stored via the `userChangedUrl` action. @@ -93,9 +106,91 @@ const WrappedPolicyDetailsForm = memo<{ }); }, [onChange, updatedPolicy]); + const policyTrustedAppsPath = useMemo(() => getPolicyTrustedAppsPath(policyId), [policyId]); + const policyTrustedAppRouteState = useMemo(() => { + const fleetPackageIntegrationCustomUrlPath = `#${ + pagePathGetters.integration_policy_edit({ packagePolicyId: policyId })[1] + }`; + + return { + backLink: { + label: i18n.translate( + 'xpack.securitySolution.endpoint.fleetCustomExtension.artifacts.backButtonLabel', + { + defaultMessage: `Back to Fleet integration policy`, + } + ), + navigateTo: [ + INTEGRATIONS_PLUGIN_ID, + { + path: fleetPackageIntegrationCustomUrlPath, + }, + ], + href: getAppUrl({ + appId: INTEGRATIONS_PLUGIN_ID, + path: fleetPackageIntegrationCustomUrlPath, + }), + }, + }; + }, [getAppUrl, policyId]); + + const policyTrustedAppsLink = useMemo( + () => ( + + + + ), + [getAppUrl, policyTrustedAppsPath, policyTrustedAppRouteState] + ); + return (
    - + {isTrustedAppsByPolicyEnabled ? ( + <> +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    +
    + + +
    + + ) : ( + + )}
    ); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/with_security_context.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/with_security_context.tsx index b657dfc74bdbc..1135a29759315 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/with_security_context.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/with_security_context.tsx @@ -13,6 +13,8 @@ import { CurrentLicense } from '../../../../../common/components/current_license import { StartPlugins } from '../../../../../types'; import { managementReducer } from '../../../../store/reducer'; import { managementMiddlewareFactory } from '../../../../store/middleware'; +import { appReducer } from '../../../../../common/store/app'; +import { ExperimentalFeaturesService } from '../../../../../common/experimental_features_service'; type ComposeType = typeof compose; declare global { @@ -51,8 +53,15 @@ export const withSecurityContext =

    ({ store = createStore( combineReducers({ management: managementReducer, + app: appReducer, }), - { management: undefined }, + { + management: undefined, + // @ts-ignore ignore this error as we just need the enableExperimental and it's temporary + app: { + enableExperimental: ExperimentalFeaturesService.get(), + }, + }, composeEnhancers(applyMiddleware(...managementMiddlewareFactory(coreStart, depsStart))) ); } diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details_form.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details_form.tsx index c9d1b3b7882a0..ed6a33166ff59 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details_form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details_form.tsx @@ -29,14 +29,14 @@ const LOCKED_CARD_RAMSOMWARE_TITLE = i18n.translate( const LOCKED_CARD_MEMORY_TITLE = i18n.translate( 'xpack.securitySolution.endpoint.policy.details.memory', { - defaultMessage: 'Memory', + defaultMessage: 'Memory Threat', } ); const LOCKED_CARD_BEHAVIOR_TITLE = i18n.translate( 'xpack.securitySolution.endpoint.policy.details.behavior', { - defaultMessage: 'Behavior', + defaultMessage: 'Malicious Behavior', } ); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts index 9d39ecd05ad8a..c643094e61126 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts @@ -28,6 +28,7 @@ import { PutTrustedAppsRequestParams, GetOneTrustedAppRequestParams, GetOneTrustedAppResponse, + GetTrustedAppsSummaryRequest, } from '../../../../../common/endpoint/types/trusted_apps'; import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; @@ -82,8 +83,10 @@ export class TrustedAppsHttpService implements TrustedAppsService { ); } - async getTrustedAppsSummary() { - return this.http.get(TRUSTED_APPS_SUMMARY_API); + async getTrustedAppsSummary(request: GetTrustedAppsSummaryRequest) { + return this.http.get(TRUSTED_APPS_SUMMARY_API, { + query: request, + }); } getPolicyList(options?: Parameters[1]) { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_flyout.tsx index 62bdc446ddb9e..049ab5884b179 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_flyout.tsx @@ -171,11 +171,21 @@ export const CreateTrustedAppFlyout = memo( + +

    + {i18n.translate('xpack.securitySolution.trustedApps.detailsSectionTitle', { + defaultMessage: 'Details', + })} +

    +
    + {!isEditMode && ( - -

    {ABOUT_TRUSTED_APPS}

    + <> + +

    {ABOUT_TRUSTED_APPS}

    +
    -
    + )} { const getOsField = (dataTestSub: string = dataTestSubjForForm): HTMLButtonElement => { return renderResult.getByTestId(`${dataTestSub}-osSelectField`) as HTMLButtonElement; }; - const getGlobalSwitchField = (dataTestSub: string = dataTestSubjForForm): HTMLButtonElement => { - return renderResult.getByTestId( - `${dataTestSub}-effectedPolicies-globalSwitch` - ) as HTMLButtonElement; - }; const getDescriptionField = (dataTestSub: string = dataTestSubjForForm): HTMLTextAreaElement => { return renderResult.getByTestId(`${dataTestSub}-descriptionField`) as HTMLTextAreaElement; }; @@ -252,55 +247,50 @@ describe('When using the Trusted App Form', () => { }); describe('the Policy Selection area', () => { - it('should show loader when setting `policies.isLoading` to true', () => { + beforeEach(() => { + const policy = generator.generatePolicyPackagePolicy(); + policy.name = 'test policy A'; + policy.id = '123'; + + formProps.policies.options = [policy]; + }); + + it('should have `global` switch on if effective scope is global and policy options hidden', () => { + render(); + const globalButton = renderResult.getByTestId( + `${dataTestSubjForForm}-effectedPolicies-global` + ) as HTMLButtonElement; + + expect(globalButton.classList.contains('euiButtonGroupButton-isSelected')).toEqual(true); + expect(renderResult.queryByTestId('policy-123')).toBeNull(); + }); + + it('should have policy options visible and specific policies checked if scope is per-policy', () => { + (formProps.trustedApp as NewTrustedApp).effectScope = { + type: 'policy', + policies: ['123'], + }; + render(); + const perPolicyButton = renderResult.getByTestId( + `${dataTestSubjForForm}-effectedPolicies-perPolicy` + ) as HTMLButtonElement; + + expect(perPolicyButton.classList.contains('euiButtonGroupButton-isSelected')).toEqual(true); + expect(renderResult.getByTestId('policy-123').getAttribute('aria-disabled')).toEqual('false'); + expect(renderResult.getByTestId('policy-123').getAttribute('aria-selected')).toEqual('true'); + }); + it('should show loader when setting `policies.isLoading` to true and scope is per-policy', () => { formProps.policies.isLoading = true; + (formProps.trustedApp as NewTrustedApp).effectScope = { + type: 'policy', + policies: ['123'], + }; render(); expect( renderResult.getByTestId(`${dataTestSubjForForm}-effectedPolicies-policiesSelectable`) .textContent ).toEqual('Loading options'); }); - - describe('and policies exist', () => { - beforeEach(() => { - const policy = generator.generatePolicyPackagePolicy(); - policy.name = 'test policy A'; - policy.id = '123'; - - formProps.policies.options = [policy]; - }); - - it('should display the policies available, but disabled if ', () => { - render(); - expect(renderResult.getByTestId('policy-123')); - }); - - it('should have `global` switch on if effective scope is global and policy options disabled', () => { - render(); - expect(getGlobalSwitchField().getAttribute('aria-checked')).toEqual('true'); - expect(renderResult.getByTestId('policy-123').getAttribute('aria-disabled')).toEqual( - 'true' - ); - expect(renderResult.getByTestId('policy-123').getAttribute('aria-selected')).toEqual( - 'false' - ); - }); - - it('should have specific policies checked if scope is per-policy', () => { - (formProps.trustedApp as NewTrustedApp).effectScope = { - type: 'policy', - policies: ['123'], - }; - render(); - expect(getGlobalSwitchField().getAttribute('aria-checked')).toEqual('false'); - expect(renderResult.getByTestId('policy-123').getAttribute('aria-disabled')).toEqual( - 'false' - ); - expect(renderResult.getByTestId('policy-123').getAttribute('aria-selected')).toEqual( - 'true' - ); - }); - }); }); describe('the Policy Selection area under feature flag', () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx index f9b83fd69a75e..5db9a8557fa10 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx @@ -14,6 +14,8 @@ import { EuiSuperSelect, EuiSuperSelectOption, EuiTextArea, + EuiText, + EuiSpacer, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { EuiFormProps } from '@elastic/eui/src/components/form/form'; @@ -458,6 +460,41 @@ export const CreateTrustedAppForm = memo( data-test-subj={getTestId('nameTextField')} /> + + + + + +

    + {i18n.translate('xpack.securitySolution.trustedApps.conditionsSectionTitle', { + defaultMessage: 'Conditions', + })} +

    +
    + + +

    + {i18n.translate('xpack.securitySolution.trustedApps.conditionsSectionDescription', { + defaultMessage: + 'Select an operating system and add conditions. Availability of conditions may depend on your chosen OS.', + })} +

    +
    + ( data-test-subj={getTestId('conditionsBuilder')} /> - - - - {isTrustedAppsByPolicyEnabled ? ( <> diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.test.tsx index 427d880444d39..4837a816d0ed8 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.test.tsx @@ -56,7 +56,7 @@ describe('when using EffectedPolicySelect component', () => { describe('and no policy entries exist', () => { it('should display no options available message', () => { - const { getByTestId } = render(); + const { getByTestId } = render({ isGlobal: false }); expect(getByTestId('test-policiesSelectable').textContent).toEqual('No options available'); }); }); @@ -65,9 +65,15 @@ describe('when using EffectedPolicySelect component', () => { const policyId = 'abc123'; const policyTestSubj = `policy-${policyId}`; - const toggleGlobalSwitch = () => { + const selectGlobalPolicy = () => { act(() => { - fireEvent.click(renderResult.getByTestId('test-globalSwitch')); + fireEvent.click(renderResult.getByTestId('globalPolicy')); + }); + }; + + const selectPerPolicy = () => { + act(() => { + fireEvent.click(renderResult.getByTestId('perPolicy')); }); }; @@ -97,59 +103,41 @@ describe('when using EffectedPolicySelect component', () => { }); it('should display policies', () => { - const { getByTestId } = render(); + const { getByTestId } = render({ isGlobal: false }); expect(getByTestId(policyTestSubj)); }); - it('should disable policy items if global is checked', () => { - const { getByTestId } = render(); - expect(getByTestId(policyTestSubj).getAttribute('aria-disabled')).toEqual('true'); + it('should hide policy items if global is checked', () => { + const { queryByTestId } = render({ isGlobal: true }); + expect(queryByTestId(policyTestSubj)).toBeNull(); }); it('should enable policy items if global is unchecked', async () => { - const { getByTestId } = render(); - toggleGlobalSwitch(); + const { getByTestId } = render({ isGlobal: false }); + selectPerPolicy(); expect(getByTestId(policyTestSubj).getAttribute('aria-disabled')).toEqual('false'); }); it('should call onChange with selection when global is toggled', () => { render(); - toggleGlobalSwitch(); + selectPerPolicy(); expect(handleOnChange.mock.calls[0][0]).toEqual({ isGlobal: false, selected: [], }); - toggleGlobalSwitch(); + selectGlobalPolicy(); expect(handleOnChange.mock.calls[1][0]).toEqual({ isGlobal: true, selected: [], }); }); - it('should not allow clicking on policies when global is true', () => { - render(); - - clickOnPolicy(); - expect(handleOnChange.mock.calls.length).toBe(0); - - // Select a Policy, then switch back to global and try to click the policy again (should be disabled and trigger onChange()) - toggleGlobalSwitch(); - clickOnPolicy(); - toggleGlobalSwitch(); - clickOnPolicy(); - expect(handleOnChange.mock.calls.length).toBe(3); - expect(handleOnChange.mock.calls[2][0]).toEqual({ - isGlobal: true, - selected: [componentProps.options[0]], - }); - }); - - it('should maintain policies selection even if global was checked', () => { + it('should maintain policies selection even if global was checked, and user switched back to per policy', () => { render(); - toggleGlobalSwitch(); + selectPerPolicy(); clickOnPolicy(); expect(handleOnChange.mock.calls[1][0]).toEqual({ isGlobal: false, @@ -157,7 +145,7 @@ describe('when using EffectedPolicySelect component', () => { }); // Toggle isGlobal back to True - toggleGlobalSwitch(); + selectGlobalPolicy(); expect(handleOnChange.mock.calls[2][0]).toEqual({ isGlobal: true, selected: [componentProps.options[0]], diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx index 99db45c0e4b84..bb620ee5e7c01 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx @@ -7,12 +7,15 @@ import React, { memo, useCallback, useMemo } from 'react'; import { + EuiButtonGroup, + EuiButtonGroupOptionProps, EuiCheckbox, + EuiFlexGroup, + EuiFlexItem, EuiFormRow, EuiSelectable, EuiSelectableProps, - EuiSwitch, - EuiSwitchProps, + EuiSpacer, EuiText, htmlIdGenerator, } from '@elastic/eui'; @@ -70,6 +73,28 @@ export const EffectedPolicySelect = memo( const getTestId = useTestIdGenerator(dataTestSubj); + const toggleGlobal: EuiButtonGroupOptionProps[] = useMemo( + () => [ + { + id: 'globalPolicy', + label: i18n.translate('xpack.securitySolution.endpoint.trustedAppsByPolicy.global', { + defaultMessage: 'Global', + }), + iconType: isGlobal ? 'checkInCircleFilled' : '', + 'data-test-subj': getTestId('global'), + }, + { + id: 'perPolicy', + label: i18n.translate('xpack.securitySolution.endpoint.trustedAppsByPolicy.perPolicy', { + defaultMessage: 'Per Policy', + }), + iconType: !isGlobal ? 'checkInCircleFilled' : '', + 'data-test-subj': getTestId('perPolicy'), + }, + ], + [getTestId, isGlobal] + ); + const selectableOptions: EffectedPolicyOption[] = useMemo(() => { const isPolicySelected = new Set(selected.map((policy) => policy.id)); @@ -117,10 +142,10 @@ export const EffectedPolicySelect = memo( [isGlobal, onChange] )!; - const handleGlobalSwitchChange: EuiSwitchProps['onChange'] = useCallback( - ({ target: { checked } }) => { + const handleGlobalButtonChange = useCallback( + (selectedId) => { onChange({ - isGlobal: checked, + isGlobal: selectedId === 'globalPolicy', selected, }); }, @@ -138,48 +163,54 @@ export const EffectedPolicySelect = memo( return ( - +

    + +

    + + + + -

    - -

    +

    + {i18n.translate('xpack.securitySolution.trustedApps.assignmentSectionDescription', { + defaultMessage: + 'You can assign this trusted application globally across all policies or assign it to specific policies.', + })} +

    - } - > - -
    - - - {...otherSelectableProps} - options={selectableOptions} - listProps={listProps || DEFAULT_LIST_PROPS} - onChange={handleOnPolicySelectChange} - searchable={true} - data-test-subj={getTestId('policiesSelectable')} - > - {listBuilderCallback} - - + + + + + + + + + {!isGlobal && ( + + + {...otherSelectableProps} + options={selectableOptions} + listProps={listProps || DEFAULT_LIST_PROPS} + onChange={handleOnPolicySelectChange} + searchable={true} + data-test-subj={getTestId('policiesSelectable')} + > + {listBuilderCallback} + + + )}
    ); } diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx index c696c4705912e..b9609fb43ada5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx @@ -430,8 +430,11 @@ describe('When on the Trusted Apps Page', () => { it('should have list of policies populated', async () => { useIsExperimentalFeatureEnabledMock.mockReturnValue(true); const resetEnv = forceHTMLElementOffsetWidth(); - const { getByTestId } = await renderAndClickAddButton(); - expect(getByTestId('policy-abc123')); + const renderResult = await renderAndClickAddButton(); + act(() => { + fireEvent.click(renderResult.getByTestId('perPolicy')); + }); + expect(renderResult.getByTestId('policy-abc123')); resetEnv(); }); diff --git a/x-pack/plugins/security_solution/public/management/store/reducer.ts b/x-pack/plugins/security_solution/public/management/store/reducer.ts index 25c7c87c6f5c9..662d2b4322bcb 100644 --- a/x-pack/plugins/security_solution/public/management/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/store/reducer.ts @@ -9,7 +9,7 @@ import { combineReducers } from 'redux'; import { policyDetailsReducer, initialPolicyDetailsState, -} from '../pages/policy/store/policy_details/reducer'; +} from '../pages/policy/store/policy_details'; import { MANAGEMENT_STORE_ENDPOINTS_NAMESPACE, MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE, diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/disabled_link_panel.test.tsx b/x-pack/plugins/security_solution/public/overview/components/link_panel/disabled_link_panel.test.tsx new file mode 100644 index 0000000000000..fc68807f5eb83 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/disabled_link_panel.test.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { TestProviders } from '../../../common/mock'; +import { DisabledLinkPanel } from './disabled_link_panel'; +import { ThreatIntelPanelView as TestView } from '../overview_cti_links/threat_intel_panel_view'; + +jest.mock('../../../common/lib/kibana'); + +describe('DisabledLinkPanel', () => { + const defaultProps = { + bodyCopy: 'body', + buttonCopy: 'button', + dataTestSubjPrefix: '_test_prefix_', + docLink: '/doclink', + LinkPanelViewComponent: TestView, + listItems: [], + titleCopy: 'title', + }; + + it('renders expected children', () => { + render( + + + + ); + + expect(screen.getByTestId('_test_prefix_-inner-panel-danger')).toBeInTheDocument(); + expect(screen.getByTestId('_test_prefix_-enable-module-button')).toHaveTextContent( + defaultProps.buttonCopy + ); + expect(screen.getByRole('link')).toHaveAttribute('href', defaultProps.docLink); + }); +}); diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/disabled_link_panel.tsx b/x-pack/plugins/security_solution/public/overview/components/link_panel/disabled_link_panel.tsx new file mode 100644 index 0000000000000..67d6d5608fe39 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/disabled_link_panel.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo } from 'react'; +import { EuiButton } from '@elastic/eui'; + +import { InnerLinkPanel } from './inner_link_panel'; +import { LinkPanelListItem, LinkPanelViewProps } from './types'; + +interface DisabledLinkPanelProps { + bodyCopy: string; + buttonCopy: string; + dataTestSubjPrefix: string; + docLink: string; + LinkPanelViewComponent: React.ComponentType; + listItems: LinkPanelListItem[]; + titleCopy: string; +} + +const DisabledLinkPanelComponent: React.FC = ({ + bodyCopy, + buttonCopy, + dataTestSubjPrefix, + docLink, + LinkPanelViewComponent, + listItems, + titleCopy, +}) => ( + + {buttonCopy} + + } + color="warning" + dataTestSubj={`${dataTestSubjPrefix}-inner-panel-danger`} + title={titleCopy} + /> + } + /> +); + +export const DisabledLinkPanel = memo(DisabledLinkPanelComponent); +DisabledLinkPanel.displayName = 'DisabledLinkPanel'; diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/helpers.ts b/x-pack/plugins/security_solution/public/overview/components/link_panel/helpers.ts new file mode 100644 index 0000000000000..45d26d9269f6e --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/helpers.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LinkPanelListItem } from '.'; + +export const isLinkPanelListItem = ( + item: LinkPanelListItem | Partial +): item is LinkPanelListItem => + typeof item.title === 'string' && typeof item.path === 'string' && typeof item.count === 'number'; + +export interface EventCounts { + [key: string]: number; +} diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/index.ts b/x-pack/plugins/security_solution/public/overview/components/link_panel/index.ts new file mode 100644 index 0000000000000..64c8d6a38efe7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { InnerLinkPanel } from './inner_link_panel'; +export { isLinkPanelListItem } from './helpers'; +export { LinkPanel } from './link_panel'; +export { LinkPanelListItem } from './types'; diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/inner_link_panel.test.tsx b/x-pack/plugins/security_solution/public/overview/components/link_panel/inner_link_panel.test.tsx new file mode 100644 index 0000000000000..819f3d285b1ad --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/inner_link_panel.test.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { EuiButton } from '@elastic/eui'; +import { TestProviders } from '../../../common/mock'; +import { InnerLinkPanel } from './inner_link_panel'; + +describe('InnerLinkPanel', () => { + const defaultProps = { + body: 'test_body', + button: , + dataTestSubj: 'custom_test_subj', + title: 'test_title', + }; + + it('renders expected children', () => { + render( + + + + ); + + expect(screen.getByTestId('custom_test_subj')).toBeInTheDocument(); + expect(screen.getByRole('button')).toBeInTheDocument(); + expect(screen.getByTestId('inner-link-panel-title')).toHaveTextContent(defaultProps.title); + }); +}); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_inner_panel.tsx b/x-pack/plugins/security_solution/public/overview/components/link_panel/inner_link_panel.tsx similarity index 62% rename from x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_inner_panel.tsx rename to x-pack/plugins/security_solution/public/overview/components/link_panel/inner_link_panel.tsx index dbdd9ed5526a8..07ecce00a1c57 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_inner_panel.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/inner_link_panel.tsx @@ -9,20 +9,10 @@ import React from 'react'; import styled from 'styled-components'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSplitPanel, EuiText } from '@elastic/eui'; -const PanelContainer = styled(EuiSplitPanel.Inner)` - margin-bottom: ${({ theme }) => theme.eui.paddingSizes.m}; -`; - const ButtonContainer = styled(EuiFlexGroup)` padding: ${({ theme }) => theme.eui.paddingSizes.s}; `; -const Title = styled(EuiText)<{ textcolor: 'primary' | 'warning' }>` - color: ${({ theme, textcolor }) => - textcolor === 'primary' ? theme.eui.euiColorPrimary : theme.eui.euiColorWarningText}; - margin-bottom: ${({ theme }) => theme.eui.paddingSizes.m}; -`; - const Icon = styled(EuiIcon)` padding: 0; margin-top: ${({ theme }) => theme.eui.paddingSizes.m}; @@ -30,38 +20,49 @@ const Icon = styled(EuiIcon)` transform: scale(${({ color }) => (color === 'primary' ? 1.4 : 1)}); `; -export const CtiInnerPanel = ({ - color, - title, +const PanelContainer = styled(EuiSplitPanel.Inner)` + margin-bottom: ${({ theme }) => theme.eui.paddingSizes.m}; +`; + +const Title = styled(EuiText)<{ textcolor: 'primary' | 'warning' }>` + color: ${({ theme, textcolor }) => + textcolor === 'primary' ? theme.eui.euiColorPrimary : theme.eui.euiColorWarningText}; + margin-bottom: ${({ theme }) => theme.eui.paddingSizes.m}; +`; + +export const InnerLinkPanel = ({ body, button, + color, dataTestSubj, + title, }: { - color: 'primary' | 'warning'; - title: string; body: string; button?: JSX.Element; + color: 'primary' | 'warning'; dataTestSubj: string; -}) => { - const iconType = color === 'primary' ? 'iInCircle' : 'help'; - return ( - - - - - - - {title} - - - {body} - - {button && ( - - {button} - - )} - - - ); -}; + title: string; +}) => ( + + + + + + + + {title} + + + + {body} + + {button && ( + + {button} + + )} + + +); + +InnerLinkPanel.displayName = 'InnerLinkPanel'; diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/link.test.tsx b/x-pack/plugins/security_solution/public/overview/components/link_panel/link.test.tsx new file mode 100644 index 0000000000000..3353e31616467 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/link.test.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { Link } from './link'; + +describe('Link', () => { + it('renders tag when there is a path', () => { + render(); + + expect(screen.getByRole('link')).toBeInTheDocument(); + expect(screen.getByRole('link')).toHaveAttribute('href', '/test-path'); + expect(screen.getByRole('link')).toHaveTextContent('test_copy'); + }); + + it('does not render tag when there is no path', () => { + render(); + + expect(screen.getByText('test_copy')).toBeInTheDocument(); + expect(screen.queryByRole('link')).toBeNull(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/link.tsx b/x-pack/plugins/security_solution/public/overview/components/link_panel/link.tsx new file mode 100644 index 0000000000000..e6a3efbc1aed4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/link.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiLink, EuiText } from '@elastic/eui'; + +export const Link: React.FC<{ path?: string; copy: string }> = ({ path, copy }) => + path ? ( + + {copy} + + ) : ( + + {copy} + + ); + +Link.displayName = 'Link'; diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/link_panel.test.tsx b/x-pack/plugins/security_solution/public/overview/components/link_panel/link_panel.test.tsx new file mode 100644 index 0000000000000..70eb8aa0d9129 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/link_panel.test.tsx @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { EuiButton, EuiPanel } from '@elastic/eui'; +import { TestProviders } from '../../../common/mock'; +import { LinkPanel } from './link_panel'; + +describe('LinkPanel', () => { + const defaultProps = { + button: , + columns: [ + { name: 'title', field: 'title', sortable: true }, + { + name: 'count', + field: 'count', + }, + ], + dataTestSubj: '_custom_test_subj_', + infoPanel:
    , + listItems: [ + { title: 'a', count: 2, path: '' }, + { title: 'b', count: 1, path: '/test' }, + ], + panelTitle: 'test-panel-title', + splitPanel: , + subtitle: , + }; + + it('renders expected children', () => { + render( + + + + ); + + expect(screen.getByTestId('_custom_test_subj_')).toBeInTheDocument(); + expect(screen.getByRole('table')).toBeInTheDocument(); + expect(screen.getByTestId('_test_button_')).toBeInTheDocument(); + expect(screen.getByTestId('_split_panel_')).toBeInTheDocument(); + expect(screen.getByTestId('_subtitle_')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/link_panel.tsx b/x-pack/plugins/security_solution/public/overview/components/link_panel/link_panel.tsx new file mode 100644 index 0000000000000..4cc2d62d88791 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/link_panel.tsx @@ -0,0 +1,155 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useMemo, useState } from 'react'; +import styled from 'styled-components'; +import { chunk } from 'lodash'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiTableFieldDataColumnType, + EuiBasicTable, + CriteriaWithPagination, + EuiPanel, + EuiSpacer, +} from '@elastic/eui'; +import { InspectButtonContainer } from '../../../common/components/inspect'; +import { HeaderSection } from '../../../common/components/header_section'; +import { LinkPanelListItem } from './types'; + +// @ts-ignore-next-line +const StyledTable = styled(EuiBasicTable)` + [data-test-subj='panel-link'], + [data-test-subj='panel-no-link'] { + opacity: 0; + } + tr:hover { + [data-test-subj='panel-link'], + [data-test-subj='panel-no-link'] { + opacity: 1; + } + } +`; + +const PAGE_SIZE = 5; + +const sortAndChunkItems = ( + listItems: LinkPanelListItem[], + sortField: string | number, + sortDirection: 'asc' | 'desc' +) => { + const sortedItems = [...listItems].sort((a, b) => { + const aSortValue = a[sortField]; + const bSortValue = b[sortField]; + if (typeof aSortValue !== 'undefined' && typeof bSortValue !== 'undefined') { + if (aSortValue === bSortValue) { + return a.title > b.title ? 1 : a.title < b.title ? -1 : 0; + } + return aSortValue > bSortValue ? 1 : aSortValue < bSortValue ? -1 : 0; + } + return 0; + }); + if (sortDirection === 'desc') { + sortedItems.reverse(); + } + return chunk(sortedItems, PAGE_SIZE); +}; + +const LinkPanelComponent = ({ + button, + columns, + dataTestSubj, + defaultSortField, + defaultSortOrder, + infoPanel, + inspectQueryId, + listItems, + panelTitle, + splitPanel, + subtitle, +}: { + button: React.ReactNode; + columns: Array>; + dataTestSubj: string; + defaultSortField?: string; + defaultSortOrder?: 'asc' | 'desc'; + infoPanel?: React.ReactNode; + inspectQueryId?: string; + listItems: LinkPanelListItem[]; + panelTitle: string; + splitPanel: React.ReactNode; + subtitle: React.ReactNode; +}) => { + const [pageIndex, setPageIndex] = useState(0); + const [sortField, setSortField] = useState(defaultSortField ?? 'title'); + const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>(defaultSortOrder ?? 'asc'); + + const onTableChange = ({ page, sort }: CriteriaWithPagination) => { + const { index } = page; + setPageIndex(index); + if (sort) { + const { field, direction } = sort; + setSortField(field); + setSortDirection(direction); + } + }; + + const chunkedItems = useMemo( + () => sortAndChunkItems(listItems, sortField, sortDirection), + [listItems, sortDirection, sortField] + ); + + const pagination = useMemo( + () => ({ + hidePerPageOptions: true, + pageIndex, + pageSize: PAGE_SIZE, + totalItemCount: listItems.length, + }), + [pageIndex, listItems.length] + ); + + const sorting = useMemo( + () => ({ + sort: { + direction: sortDirection, + field: sortField, + }, + }), + [sortField, sortDirection] + ); + + return ( + <> + + + + + + + <>{button} + + {splitPanel} + {infoPanel} + + + + + + + ); +}; + +export const LinkPanel = React.memo(LinkPanelComponent); + +LinkPanel.displayName = 'LinkPanel'; diff --git a/x-pack/plugins/security_solution/public/overview/components/link_panel/types.ts b/x-pack/plugins/security_solution/public/overview/components/link_panel/types.ts new file mode 100644 index 0000000000000..f6c0fb6f3837f --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/link_panel/types.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface LinkPanelListItem { + [key: string]: string | number | undefined; + copy?: string; + count: number; + path: string; + title: string; + hostPath?: string; +} + +export interface LinkPanelViewProps { + buttonHref?: string; + isInspectEnabled?: boolean; + isPluginDisabled?: boolean; + listItems: LinkPanelListItem[]; + splitPanel?: JSX.Element; + totalCount?: number; +} diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.test.tsx index a9f48d2103bd4..1ad7975572f46 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { cloneDeep } from 'lodash/fp'; -import { mount } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { I18nProvider } from '@kbn/i18n/react'; import { CtiDisabledModule } from './cti_disabled_module'; import { ThemeProvider } from 'styled-components'; @@ -35,7 +35,7 @@ describe('CtiDisabledModule', () => { }); it('renders splitPanel with "danger" variant', () => { - const wrapper = mount( + render( @@ -45,10 +45,7 @@ describe('CtiDisabledModule', () => { ); - expect( - wrapper - .find('[data-test-subj="cti-dashboard-links"] [data-test-subj="cti-inner-panel-danger"]') - .hostNodes().length - ).toEqual(1); + expect(screen.getByTestId('cti-dashboard-links')).toBeInTheDocument(); + expect(screen.getByTestId('cti-inner-panel-danger')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.tsx index 38c352c43b0d4..2697e4a571ad8 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.tsx @@ -5,51 +5,30 @@ * 2.0. */ -import React, { useMemo } from 'react'; -import { EuiButton } from '@elastic/eui'; -import { ThreatIntelPanelView } from './threat_intel_panel_view'; +import React from 'react'; import { EMPTY_LIST_ITEMS } from '../../containers/overview_cti_links/helpers'; import { useKibana } from '../../../common/lib/kibana'; -import { CtiInnerPanel } from './cti_inner_panel'; import * as i18n from './translations'; +import { DisabledLinkPanel } from '../link_panel/disabled_link_panel'; +import { ThreatIntelPanelView } from './threat_intel_panel_view'; export const CtiDisabledModuleComponent = () => { const threatIntelDocLink = `${ useKibana().services.docLinks.links.filebeat.base }/filebeat-module-threatintel.html`; - const danger = useMemo( - () => ( - - {i18n.DANGER_BUTTON} - - } - dataTestSubj="cti-inner-panel-danger" - /> - ), - [threatIntelDocLink] - ); - return ( - ); }; -CtiDisabledModuleComponent.displayName = 'CtiDisabledModule'; - export const CtiDisabledModule = React.memo(CtiDisabledModuleComponent); +CtiDisabledModule.displayName = 'CtiDisabledModule'; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_enabled_module.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_enabled_module.test.tsx index a30e752cc3afc..310b03959746e 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_enabled_module.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_enabled_module.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { cloneDeep } from 'lodash/fp'; -import { mount } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { I18nProvider } from '@kbn/i18n/react'; import { CtiEnabledModule } from './cti_enabled_module'; import { ThemeProvider } from 'styled-components'; @@ -50,7 +50,7 @@ describe('CtiEnabledModule', () => { }); it('renders CtiWithEvents when there are events', () => { - const wrapper = mount( + render( @@ -60,12 +60,12 @@ describe('CtiEnabledModule', () => { ); - expect(wrapper.exists('[data-test-subj="cti-with-events"]')).toBe(true); + expect(screen.getByTestId('cti-with-events')).toBeInTheDocument(); }); it('renders CtiWithNoEvents when there are no events', () => { useCTIEventCountsMock.mockReturnValueOnce({ totalCount: 0 }); - const wrapper = mount( + render( @@ -75,12 +75,12 @@ describe('CtiEnabledModule', () => { ); - expect(wrapper.exists('[data-test-subj="cti-with-no-events"]')).toBe(true); + expect(screen.getByTestId('cti-with-no-events')).toBeInTheDocument(); }); it('renders null while event counts are loading', () => { useCTIEventCountsMock.mockReturnValueOnce({ totalCount: -1 }); - const wrapper = mount( + const { container } = render( @@ -90,6 +90,6 @@ describe('CtiEnabledModule', () => { ); - expect(wrapper.html()).toEqual(''); + expect(container.firstChild).toBeNull(); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_enabled_module.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_enabled_module.tsx index 304e8b99135d3..5a40c79d6e5ec 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_enabled_module.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_enabled_module.tsx @@ -21,20 +21,24 @@ export const CtiEnabledModuleComponent: React.FC = (props case -1: return null; case 0: - return ; + return ( +
    + +
    + ); default: return ( - +
    + +
    ); } }; -CtiEnabledModuleComponent.displayName = 'CtiEnabledModule'; - export const CtiEnabledModule = React.memo(CtiEnabledModuleComponent); +CtiEnabledModule.displayName = 'CtiEnabledModule'; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.test.tsx index 7ecaccad19d64..926f6175c3129 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { cloneDeep } from 'lodash/fp'; -import { mount } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { I18nProvider } from '@kbn/i18n/react'; import { CtiNoEvents } from './cti_no_events'; import { ThemeProvider } from 'styled-components'; @@ -40,7 +40,7 @@ describe('CtiNoEvents', () => { }); it('renders warning inner panel', () => { - const wrapper = mount( + render( @@ -50,15 +50,12 @@ describe('CtiNoEvents', () => { ); - expect( - wrapper - .find('[data-test-subj="cti-dashboard-links"] [data-test-subj="cti-inner-panel-warning"]') - .hostNodes().length - ).toEqual(1); + expect(screen.getByTestId('cti-dashboard-links')).toBeInTheDocument(); + expect(screen.getByTestId('cti-inner-panel-warning')).toBeInTheDocument(); }); it('renders event counts as 0', () => { - const wrapper = mount( + render( @@ -68,8 +65,6 @@ describe('CtiNoEvents', () => { ); - expect(wrapper.find('[data-test-subj="cti-total-event-count"]').text()).toEqual( - 'Showing: 0 indicators' - ); + expect(screen.getByText('Showing: 0 indicators')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.tsx index 525235142ace1..fa7ac50c08765 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.tsx @@ -8,12 +8,12 @@ import React from 'react'; import { useCtiDashboardLinks } from '../../containers/overview_cti_links'; import { ThreatIntelPanelView } from './threat_intel_panel_view'; -import { CtiInnerPanel } from './cti_inner_panel'; +import { InnerLinkPanel } from '../link_panel'; import * as i18n from './translations'; import { emptyEventCountsByDataset } from '../../containers/overview_cti_links/helpers'; const warning = ( - { - const { buttonHref, listItems, isDashboardPluginDisabled } = useCtiDashboardLinks( + const { buttonHref, listItems, isPluginDisabled } = useCtiDashboardLinks( emptyEventCountsByDataset, to, from @@ -33,12 +33,10 @@ export const CtiNoEventsComponent = ({ to, from }: { to: string; from: string }) buttonHref={buttonHref} listItems={listItems} splitPanel={warning} - totalEventCount={0} - isDashboardPluginDisabled={isDashboardPluginDisabled} + isPluginDisabled={isPluginDisabled} /> ); }; -CtiNoEventsComponent.displayName = 'CtiNoEvents'; - export const CtiNoEvents = React.memo(CtiNoEventsComponent); +CtiNoEvents.displayName = 'CtiNoEvents'; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_with_events.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_with_events.tsx index b2f7c7d761d2c..f78451e205b1e 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_with_events.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_with_events.tsx @@ -21,7 +21,7 @@ export const CtiWithEventsComponent = ({ to: string; totalCount: number; }) => { - const { buttonHref, isDashboardPluginDisabled, listItems } = useCtiDashboardLinks( + const { buttonHref, isPluginDisabled, listItems } = useCtiDashboardLinks( eventCountsByDataset, to, from @@ -30,9 +30,9 @@ export const CtiWithEventsComponent = ({ return ( ); }; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/index.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/index.tsx index 0c50bbf145b17..5348c12fb6c8e 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/index.tsx @@ -21,15 +21,22 @@ export type ThreatIntelLinkPanelProps = Pick< const ThreatIntelLinkPanelComponent: React.FC = (props) => { switch (props.isThreatIntelModuleEnabled) { case true: - return ; + return ( +
    + +
    + ); case false: - return ; + return ( +
    + +
    + ); case undefined: default: return null; } }; -ThreatIntelLinkPanelComponent.displayName = 'ThreatIntelDashboardLinksComponent'; - export const ThreatIntelLinkPanel = React.memo(ThreatIntelLinkPanelComponent); +ThreatIntelLinkPanel.displayName = 'ThreatIntelDashboardLinksComponent'; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/mock.ts b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/mock.ts index 5da69d8c1af3a..1d02acaf65f48 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/mock.ts +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/mock.ts @@ -31,7 +31,7 @@ export const mockCtiEventCountsResponse = { }; export const mockCtiLinksResponse = { - isDashboardPluginDisabled: false, + isPluginDisabled: false, buttonHref: '/button', listItems: [ { title: 'abuseurl', count: 1, path: '/dashboard_path_abuseurl' }, @@ -45,7 +45,7 @@ export const mockCtiLinksResponse = { }; export const mockEmptyCtiLinksResponse = { - isDashboardPluginDisabled: false, + isPluginDisabled: false, buttonHref: '/button', listItems: [ { title: 'abuseurl', count: 0, path: '/dashboard_path_abuseurl' }, @@ -72,7 +72,7 @@ export const mockCtiWithEventsProps = { export const mockThreatIntelPanelViewProps = { buttonHref: '/button_href', - isDashboardPluginDisabled: false, + isPluginDisabled: false, listItems: mockCtiLinksResponse.listItems, splitPanel: undefined, totalEventCount: 1337, diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.test.tsx deleted file mode 100644 index ffd0c8e69e76d..0000000000000 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.test.tsx +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { Provider } from 'react-redux'; -import { cloneDeep } from 'lodash/fp'; -import { mount } from 'enzyme'; -import { I18nProvider } from '@kbn/i18n/react'; -import { ThreatIntelPanelView } from './threat_intel_panel_view'; -import { ThemeProvider } from 'styled-components'; -import { createStore, State } from '../../../common/store'; -import { - createSecuritySolutionStorageMock, - kibanaObservable, - mockGlobalState, - SUB_PLUGINS_REDUCER, -} from '../../../common/mock'; -import { mockTheme, mockThreatIntelPanelViewProps } from './mock'; - -jest.mock('../../../common/lib/kibana'); - -describe('ThreatIntelPanelView', () => { - const state: State = mockGlobalState; - - const { storage } = createSecuritySolutionStorageMock(); - let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - - beforeEach(() => { - const myState = cloneDeep(state); - store = createStore(myState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - }); - - it('renders enabled button when there is a button href', () => { - const wrapper = mount( - - - - - - - - ); - - expect(wrapper.find('button').props().disabled).toEqual(false); - }); - - it('renders disabled button when there is no button href', () => { - const wrapper = mount( - - - - - - - - ); - - expect(wrapper.find('button').at(1).props().disabled).toEqual(true); - }); - - it('renders info panel if dashboard plugin is disabled', () => { - const wrapper = mount( - - - - - - - - ); - - expect(wrapper.find('[data-test-subj="cti-inner-panel-info"]').hostNodes().length).toEqual(1); - }); - - it('does not render info panel if dashboard plugin is disabled', () => { - const wrapper = mount( - - - - - - - - ); - - expect(wrapper.find('[data-test-subj="cti-inner-panel-info"]').length).toEqual(0); - }); - - it('renders split panel if split panel is passed in as a prop', () => { - const wrapper = mount( - - - - , - }} - /> - - - - ); - - expect(wrapper.find('[data-test-subj="mock-split-panel"]').length).toEqual(1); - }); - - it('renders list items with links', () => { - const wrapper = mount( - - - - - - - - ); - - expect(wrapper.find('li a').at(0).props().href).toEqual( - mockThreatIntelPanelViewProps.listItems[0].path - ); - }); - - it('renders total event count', () => { - const wrapper = mount( - - - - - - - - ); - - expect(wrapper.find('[data-test-subj="cti-total-event-count"]').text()).toEqual( - `Showing: ${mockThreatIntelPanelViewProps.totalEventCount} indicators` - ); - }); - - it('renders inspect button by default', () => { - const wrapper = mount( - - - - - - - - ); - - expect(wrapper.exists('[data-test-subj="inspect-icon-button"]')).toBe(true); - }); - - it('does not render inspect button if isInspectEnabled is false', () => { - const wrapper = mount( - - - - - - - - ); - - expect(wrapper.exists('[data-test-subj="inspect-icon-button"]')).toBe(false); - }); -}); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx index 6bd7bef20fcbe..ba4851600c4b4 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx @@ -6,196 +6,102 @@ */ import React, { useMemo } from 'react'; -import styled from 'styled-components'; -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiHorizontalRule, - EuiLink, - EuiPanel, - EuiSpacer, - EuiText, -} from '@elastic/eui'; +import { EuiButton, EuiTableFieldDataColumnType } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { InspectButtonContainer } from '../../../common/components/inspect'; -import { HeaderSection } from '../../../common/components/header_section'; -import { ID as CTIEventCountQueryId } from '../../containers/overview_cti_links/use_cti_event_counts'; -import { CtiListItem } from '../../containers/overview_cti_links/helpers'; + import { useKibana } from '../../../common/lib/kibana'; -import { CtiInnerPanel } from './cti_inner_panel'; import * as i18n from './translations'; +import { LinkPanel, InnerLinkPanel, LinkPanelListItem } from '../link_panel'; +import { LinkPanelViewProps } from '../link_panel/types'; import { shortenCountIntoString } from '../../../common/utils/shorten_count_into_string'; +import { Link } from '../link_panel/link'; +import { ID as CTIEventCountQueryId } from '../../containers/overview_cti_links/use_cti_event_counts'; +import { LINK_COPY } from '../overview_risky_host_links/translations'; -const DashboardLink = styled.li` - margin: 0 ${({ theme }) => theme.eui.paddingSizes.s} 0 ${({ theme }) => theme.eui.paddingSizes.m}; -`; - -const DashboardLinkItems = styled(EuiFlexGroup)` - width: 100%; -`; - -const Title = styled(EuiFlexItem)` - min-width: 110px; -`; - -const List = styled.ul` - margin-bottom: ${({ theme }) => theme.eui.paddingSizes.l}; -`; - -const DashboardRightSideElement = styled(EuiFlexItem)` - align-items: flex-end; -`; - -const RightSideLink = styled(EuiLink)` - text-align: right; - min-width: 180px; -`; - -interface ThreatIntelPanelViewProps { - buttonHref?: string; - isDashboardPluginDisabled?: boolean; - isInspectEnabled?: boolean; - listItems: CtiListItem[]; - splitPanel?: JSX.Element; - totalEventCount: number; -} - -const linkCopy = ( - -); - -const panelTitle = ( - -); +const columns: Array> = [ + { name: 'Name', field: 'title', sortable: true, truncateText: true, width: '100%' }, + { + name: 'Indicator', + field: 'count', + render: shortenCountIntoString, + sortable: true, + truncateText: true, + width: '20%', + align: 'right', + }, + { + name: '', + field: 'path', + truncateText: true, + width: '80px', + // eslint-disable-next-line react/display-name + render: (path: string) => , + }, +]; -export const ThreatIntelPanelView: React.FC = ({ +export const ThreatIntelPanelView: React.FC = ({ buttonHref = '', - isDashboardPluginDisabled, + isPluginDisabled, isInspectEnabled = true, listItems, splitPanel, - totalEventCount, + totalCount = 0, }) => { - const subtitle = useMemo( - () => ( - - ), - [totalEventCount] - ); - - const button = useMemo( - () => ( - - - - ), - [buttonHref] - ); - const threatIntelDashboardDocLink = `${ useKibana().services.docLinks.links.filebeat.base }/load-kibana-dashboards.html`; - const infoPanel = useMemo( - () => - isDashboardPluginDisabled ? ( - - {i18n.INFO_BUTTON} - - } - /> - ) : null, - [isDashboardPluginDisabled, threatIntelDashboardDocLink] - ); return ( - <> - - - - - - - <>{button} - - {splitPanel} - {infoPanel} - - - {listItems.map(({ title, path, count }) => ( - - - - {title} - - - {shortenCountIntoString(count)} - - - {path ? ( - - {linkCopy} - - ) : ( - - {linkCopy} - - )} - - - - - ))} - - - - - - - - + ( + + {i18n.VIEW_DASHBOARD} + + ), + [buttonHref] + ), + columns, + dataTestSubj: 'cti-dashboard-links', + infoPanel: useMemo( + () => + isPluginDisabled ? ( + + {i18n.INFO_BUTTON} + + } + /> + ) : null, + [isPluginDisabled, threatIntelDashboardDocLink] + ), + inspectQueryId: isInspectEnabled ? CTIEventCountQueryId : undefined, + listItems, + panelTitle: i18n.PANEL_TITLE, + splitPanel, + subtitle: useMemo( + () => ( + + ), + [totalCount] + ), + }} + /> ); }; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts index 91abd48eb2b7e..4a64462b27ad5 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts @@ -64,3 +64,11 @@ export const DANGER_BUTTON = i18n.translate( defaultMessage: 'Enable Module', } ); + +export const PANEL_TITLE = i18n.translate('xpack.securitySolution.overview.ctiDashboardTitle', { + defaultMessage: 'Threat Intelligence', +}); + +export const VIEW_DASHBOARD = i18n.translate('xpack.securitySolution.overview.ctiViewDasboard', { + defaultMessage: 'View dashboard', +}); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.test.tsx new file mode 100644 index 0000000000000..0fd7184e0c55a --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.test.tsx @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { Provider } from 'react-redux'; +import { cloneDeep } from 'lodash/fp'; +import { render, screen } from '@testing-library/react'; +import { I18nProvider } from '@kbn/i18n/react'; +import { ThemeProvider } from 'styled-components'; +import { useRiskyHostLinks } from '../../containers/overview_risky_host_links/use_risky_host_links'; +import { mockTheme } from '../overview_cti_links/mock'; +import { RiskyHostLinks } from '.'; +import { createStore, State } from '../../../common/store'; +import { + createSecuritySolutionStorageMock, + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, +} from '../../../common/mock'; +import { useRiskyHostsDashboardButtonHref } from '../../containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href'; +import { useRiskyHostsDashboardLinks } from '../../containers/overview_risky_host_links/use_risky_hosts_dashboard_links'; + +jest.mock('../../../common/lib/kibana'); + +jest.mock('../../containers/overview_risky_host_links/use_risky_host_links'); +const useRiskyHostLinksMock = useRiskyHostLinks as jest.Mock; + +jest.mock('../../containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href'); +const useRiskyHostsDashboardButtonHrefMock = useRiskyHostsDashboardButtonHref as jest.Mock; +useRiskyHostsDashboardButtonHrefMock.mockReturnValue({ buttonHref: '/test' }); + +jest.mock('../../containers/overview_risky_host_links/use_risky_hosts_dashboard_links'); +const useRiskyHostsDashboardLinksMock = useRiskyHostsDashboardLinks as jest.Mock; +useRiskyHostsDashboardLinksMock.mockReturnValue({ + listItemsWithLinks: [{ title: 'a', count: 1, path: '/test' }], +}); + +describe('RiskyHostLinks', () => { + const state: State = mockGlobalState; + + const { storage } = createSecuritySolutionStorageMock(); + let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + beforeEach(() => { + const myState = cloneDeep(state); + store = createStore(myState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + }); + + it('renders enabled module view if module is enabled', () => { + useRiskyHostLinksMock.mockReturnValueOnce({ + loading: false, + isModuleEnabled: true, + listItems: [], + }); + + render( + + + + + + + + ); + + expect(screen.queryByTestId('risky-hosts-enable-module-button')).not.toBeInTheDocument(); + }); + + it('renders disabled module view if module is disabled', () => { + useRiskyHostLinksMock.mockReturnValueOnce({ + loading: false, + isModuleEnabled: false, + listItems: [], + }); + + render( + + + + + + + + ); + + expect(screen.getByTestId('risky-hosts-enable-module-button')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.tsx new file mode 100644 index 0000000000000..895037170c447 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; +import { useRiskyHostLinks } from '../../containers/overview_risky_host_links/use_risky_host_links'; +import { RiskyHostsEnabledModule } from './risky_hosts_enabled_module'; +import { RiskyHostsDisabledModule } from './risky_hosts_disabled_module'; +export type RiskyHostLinksProps = Pick; + +const RiskyHostLinksComponent: React.FC = (props) => { + const { listItems, isModuleEnabled } = useRiskyHostLinks(props); + + switch (isModuleEnabled) { + case true: + return ; + case false: + return ; + case undefined: + default: + return null; + } +}; + +export const RiskyHostLinks = React.memo(RiskyHostLinksComponent); +RiskyHostLinks.displayName = 'RiskyHostLinks'; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/navigate_to_host.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/navigate_to_host.tsx new file mode 100644 index 0000000000000..4680aedc0ba60 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/navigate_to_host.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import { EuiButtonEmpty, EuiText } from '@elastic/eui'; +import { APP_ID, SecurityPageName } from '../../../../common/constants'; +import { useKibana } from '../../../common/lib/kibana'; + +export const NavigateToHost: React.FC<{ name: string }> = ({ name }): JSX.Element => { + const { navigateToApp } = useKibana().services.application; + const { filterManager } = useKibana().services.data.query; + + const goToHostPage = useCallback( + (e) => { + e.preventDefault(); + filterManager.addFilters([ + { + meta: { + alias: null, + disabled: false, + negate: false, + }, + query: { match_phrase: { 'host.name': name } }, + }, + ]); + navigateToApp(APP_ID, { + deepLinkId: SecurityPageName.hosts, + }); + }, + [filterManager, name, navigateToApp] + ); + return ( + + {name} + + ); +}; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_disabled_module.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_disabled_module.test.tsx new file mode 100644 index 0000000000000..9aa1421287220 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_disabled_module.test.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { Provider } from 'react-redux'; +import { cloneDeep } from 'lodash/fp'; +import { render, screen } from '@testing-library/react'; +import { I18nProvider } from '@kbn/i18n/react'; +import { ThemeProvider } from 'styled-components'; +import { createStore, State } from '../../../common/store'; +import { + createSecuritySolutionStorageMock, + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, +} from '../../../common/mock'; +import { RiskyHostsDisabledModule } from './risky_hosts_disabled_module'; +import { mockTheme } from '../overview_cti_links/mock'; + +jest.mock('../../../common/lib/kibana'); + +describe('RiskyHostsModule', () => { + const state: State = mockGlobalState; + + const { storage } = createSecuritySolutionStorageMock(); + let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + beforeEach(() => { + const myState = cloneDeep(state); + store = createStore(myState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + }); + + it('renders expected children', () => { + render( + + + + + + + + ); + + expect(screen.getByTestId('risky-hosts-dashboard-links')).toBeInTheDocument(); + expect(screen.getByTestId('risky-hosts-view-dashboard-button')).toBeInTheDocument(); + expect(screen.getByTestId('risky-hosts-enable-module-button')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_disabled_module.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_disabled_module.tsx new file mode 100644 index 0000000000000..7d8436bd9dd25 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_disabled_module.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import * as i18n from './translations'; +import { DisabledLinkPanel } from '../link_panel/disabled_link_panel'; +import { RiskyHostsPanelView } from './risky_hosts_panel_view'; +import { RiskyHostsEnabledModule } from './risky_hosts_enabled_module'; + +const RISKY_HOSTS_DOC_LINK = + 'https://www.github.com/elastic/detection-rules/blob/main/docs/experimental-machine-learning/host-risk-score.md'; + +export const RiskyHostsDisabledModuleComponent = () => ( + +); + +export const RiskyHostsDisabledModule = React.memo(RiskyHostsDisabledModuleComponent); +RiskyHostsEnabledModule.displayName = 'RiskyHostsDisabledModule'; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.test.tsx new file mode 100644 index 0000000000000..f751abdfb3ab8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.test.tsx @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { Provider } from 'react-redux'; +import { cloneDeep } from 'lodash/fp'; +import { render, screen } from '@testing-library/react'; +import { I18nProvider } from '@kbn/i18n/react'; +import { ThemeProvider } from 'styled-components'; +import { createStore, State } from '../../../common/store'; +import { + createSecuritySolutionStorageMock, + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, +} from '../../../common/mock'; +import { useRiskyHostsDashboardButtonHref } from '../../containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href'; +import { useRiskyHostsDashboardLinks } from '../../containers/overview_risky_host_links/use_risky_hosts_dashboard_links'; +import { mockTheme } from '../overview_cti_links/mock'; +import { RiskyHostsEnabledModule } from './risky_hosts_enabled_module'; + +jest.mock('../../../common/lib/kibana'); + +jest.mock('../../containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href'); +const useRiskyHostsDashboardButtonHrefMock = useRiskyHostsDashboardButtonHref as jest.Mock; +useRiskyHostsDashboardButtonHrefMock.mockReturnValue({ buttonHref: '/test' }); + +jest.mock('../../containers/overview_risky_host_links/use_risky_hosts_dashboard_links'); +const useRiskyHostsDashboardLinksMock = useRiskyHostsDashboardLinks as jest.Mock; +useRiskyHostsDashboardLinksMock.mockReturnValue({ + listItemsWithLinks: [{ title: 'a', count: 1, path: '/test' }], +}); + +describe('RiskyHostsEnabledModule', () => { + const state: State = mockGlobalState; + + const { storage } = createSecuritySolutionStorageMock(); + let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + beforeEach(() => { + const myState = cloneDeep(state); + store = createStore(myState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + }); + + it('renders expected children', () => { + render( + + + + + + + + ); + expect(screen.getByTestId('risky-hosts-dashboard-links')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.tsx new file mode 100644 index 0000000000000..f26e0c7fb4338 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { RiskyHostsPanelView } from './risky_hosts_panel_view'; +import { LinkPanelListItem } from '../link_panel'; +import { useRiskyHostsDashboardButtonHref } from '../../containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href'; +import { useRiskyHostsDashboardLinks } from '../../containers/overview_risky_host_links/use_risky_hosts_dashboard_links'; + +const RiskyHostsEnabledModuleComponent: React.FC<{ + from: string; + listItems: LinkPanelListItem[]; + to: string; +}> = ({ listItems, to, from }) => { + const { buttonHref } = useRiskyHostsDashboardButtonHref(to, from); + const { listItemsWithLinks } = useRiskyHostsDashboardLinks(to, from, listItems); + + return ( + + ); +}; + +export const RiskyHostsEnabledModule = React.memo(RiskyHostsEnabledModuleComponent); +RiskyHostsEnabledModule.displayName = 'RiskyHostsEnabledModule'; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_panel_view.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_panel_view.tsx new file mode 100644 index 0000000000000..e227e66a7d4f0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_panel_view.tsx @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; + +import { EuiButton, EuiTableFieldDataColumnType } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { InnerLinkPanel, LinkPanel, LinkPanelListItem } from '../link_panel'; +import { LinkPanelViewProps } from '../link_panel/types'; +import { Link } from '../link_panel/link'; +import * as i18n from './translations'; +import { VIEW_DASHBOARD } from '../overview_cti_links/translations'; +import { QUERY_ID as RiskyHostsQueryId } from '../../containers/overview_risky_host_links/use_risky_host_links'; +import { NavigateToHost } from './navigate_to_host'; + +const columns: Array> = [ + { + name: 'Host Name', + field: 'title', + sortable: true, + truncateText: true, + width: '55%', + render: (name) => () as JSX.Element, + }, + { + align: 'right', + field: 'count', + name: 'Risk Score', + sortable: true, + truncateText: true, + width: '15%', + }, + { + field: 'copy', + name: 'Current Risk', + sortable: true, + truncateText: true, + width: '15%', + }, + { + field: 'path', + name: '', + render: (path: string) => () as JSX.Element, + truncateText: true, + width: '80px', + }, +]; + +const warningPanel = ( + +); + +export const RiskyHostsPanelView: React.FC = ({ + buttonHref = '', + isInspectEnabled, + listItems, + splitPanel, + totalCount = 0, +}) => { + const splitPanelElement = + typeof splitPanel === 'undefined' + ? listItems.length === 0 + ? warningPanel + : undefined + : splitPanel; + return ( + ( + + {VIEW_DASHBOARD} + + ), + [buttonHref] + ), + columns, + dataTestSubj: 'risky-hosts-dashboard-links', + defaultSortField: 'count', + defaultSortOrder: 'desc', + inspectQueryId: isInspectEnabled ? RiskyHostsQueryId : undefined, + listItems, + panelTitle: i18n.PANEL_TITLE, + splitPanel: splitPanelElement, + subtitle: useMemo( + () => ( + + ), + [totalCount] + ), + }} + /> + ); +}; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/translations.ts b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/translations.ts new file mode 100644 index 0000000000000..c175196857bbc --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/translations.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const WARNING_TITLE = i18n.translate( + 'xpack.securitySolution.overview.riskyHostsDashboardWarningPanelTitle', + { + defaultMessage: 'No host risk score data available to display', + } +); + +export const WARNING_BODY = i18n.translate( + 'xpack.securitySolution.overview.riskyHostsDashboardWarningPanelBody', + { + defaultMessage: `We haven't detected any host risk score data from the hosts in your environment for the selected time range.`, + } +); + +export const DANGER_TITLE = i18n.translate( + 'xpack.securitySolution.overview.riskyHostsDashboardDangerPanelTitle', + { + defaultMessage: 'No host risk score data to display', + } +); + +export const DANGER_BODY = i18n.translate( + 'xpack.securitySolution.overview.riskyHostsDashboardEnableThreatIntel', + { + defaultMessage: + 'Please enable the host risk score module in order to view the list of risky hosts.', + } +); + +export const DANGER_BUTTON = i18n.translate( + 'xpack.securitySolution.overview.riskyHostsDashboardDangerPanelButton', + { + defaultMessage: 'Enable Risk Score', + } +); + +export const LINK_COPY = i18n.translate('xpack.securitySolution.overview.riskyHostsSource', { + defaultMessage: 'Source', +}); + +export const PANEL_TITLE = i18n.translate( + 'xpack.securitySolution.overview.riskyHostsDashboardTitle', + { + defaultMessage: 'Current host risk scores', + } +); diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/helpers.ts b/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/helpers.ts index 6f7953e78731a..9ac61cc9487ee 100644 --- a/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/helpers.ts +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/helpers.ts @@ -7,17 +7,12 @@ import { SavedObjectAttributes } from '@kbn/securitysolution-io-ts-alerting-types'; import { CTI_DATASET_KEY_MAP } from '../../../../common/cti/constants'; +import { LinkPanelListItem } from '../../components/link_panel'; +import { EventCounts } from '../../components/link_panel/helpers'; -export interface CtiListItem { - path: string; - title: CtiDatasetTitle; - count: number; -} +export const ctiTitles = Object.keys(CTI_DATASET_KEY_MAP) as string[]; -export type CtiDatasetTitle = keyof typeof CTI_DATASET_KEY_MAP; -export const ctiTitles = Object.keys(CTI_DATASET_KEY_MAP) as CtiDatasetTitle[]; - -export const EMPTY_LIST_ITEMS: CtiListItem[] = ctiTitles.map((title) => ({ +export const EMPTY_LIST_ITEMS: LinkPanelListItem[] = ctiTitles.map((title) => ({ title, count: 0, path: '', @@ -30,23 +25,16 @@ export const TAG_REQUEST_BODY = { searchFields: ['name'], }; -export interface EventCounts { - [key: string]: number; -} - export const DASHBOARD_SO_TITLE_PREFIX = '[Filebeat Threat Intel] '; export const OVERVIEW_DASHBOARD_LINK_TITLE = 'Overview'; -export const getListItemsWithoutLinks = (eventCounts: EventCounts): CtiListItem[] => { +export const getCtiListItemsWithoutLinks = (eventCounts: EventCounts): LinkPanelListItem[] => { return EMPTY_LIST_ITEMS.map((item) => ({ ...item, count: eventCounts[CTI_DATASET_KEY_MAP[item.title]] ?? 0, })); }; -export const isCtiListItem = (item: CtiListItem | Partial): item is CtiListItem => - typeof item.title === 'string' && typeof item.path === 'string' && typeof item.count === 'number'; - export const isOverviewItem = (item: { path?: string; title?: string }) => item.title === OVERVIEW_DASHBOARD_LINK_TITLE; diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx b/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx index 8839aff7dc33d..a546d20e49583 100644 --- a/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_cti_links/index.tsx @@ -8,13 +8,13 @@ import { useState, useEffect, useCallback } from 'react'; import { SavedObjectAttributes } from '@kbn/securitysolution-io-ts-alerting-types'; import { useKibana } from '../../../common/lib/kibana'; import { - CtiListItem, TAG_REQUEST_BODY, createLinkFromDashboardSO, - getListItemsWithoutLinks, - isCtiListItem, + getCtiListItemsWithoutLinks, isOverviewItem, + EMPTY_LIST_ITEMS, } from './helpers'; +import { LinkPanelListItem, isLinkPanelListItem } from '../../components/link_panel'; export const useCtiDashboardLinks = ( eventCountsByDataset: { [key: string]: number }, @@ -25,15 +25,15 @@ export const useCtiDashboardLinks = ( const savedObjectsClient = useKibana().services.savedObjects.client; const [buttonHref, setButtonHref] = useState(); - const [listItems, setListItems] = useState([]); + const [listItems, setListItems] = useState(EMPTY_LIST_ITEMS); - const [isDashboardPluginDisabled, setIsDashboardPluginDisabled] = useState(false); + const [isPluginDisabled, setIsDashboardPluginDisabled] = useState(false); const handleDisabledPlugin = useCallback(() => { - if (!isDashboardPluginDisabled) { + if (!isPluginDisabled) { setIsDashboardPluginDisabled(true); } - setListItems(getListItemsWithoutLinks(eventCountsByDataset)); - }, [setIsDashboardPluginDisabled, setListItems, eventCountsByDataset, isDashboardPluginDisabled]); + setListItems(getCtiListItemsWithoutLinks(eventCountsByDataset)); + }, [setIsDashboardPluginDisabled, setListItems, eventCountsByDataset, isPluginDisabled]); const handleTagsReceived = useCallback( (TagsSO?) => { @@ -75,7 +75,7 @@ export const useCtiDashboardLinks = ( ) ); const items = DashboardsSO.savedObjects - ?.reduce((acc: CtiListItem[], dashboardSO, i) => { + ?.reduce((acc: LinkPanelListItem[], dashboardSO, i) => { const item = createLinkFromDashboardSO( dashboardSO, eventCountsByDataset, @@ -83,7 +83,7 @@ export const useCtiDashboardLinks = ( ); if (isOverviewItem(item)) { setButtonHref(item.path); - } else if (isCtiListItem(item)) { + } else if (isLinkPanelListItem(item)) { acc.push(item); } return acc; @@ -102,14 +102,14 @@ export const useCtiDashboardLinks = ( from, handleDisabledPlugin, handleTagsReceived, - isDashboardPluginDisabled, + isPluginDisabled, savedObjectsClient, to, ]); return { buttonHref, - isDashboardPluginDisabled, + isPluginDisabled, listItems, }; }; diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_host_links.ts b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_host_links.ts new file mode 100644 index 0000000000000..7df091cbbd463 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_host_links.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { i18n } from '@kbn/i18n'; + +import { useCallback, useEffect, useState } from 'react'; +import { useDispatch } from 'react-redux'; + +import { useRiskyHostsComplete } from './use_risky_hosts'; +import { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useKibana } from '../../../common/lib/kibana'; +import { inputsActions } from '../../../common/store/actions'; +import { LinkPanelListItem } from '../../components/link_panel'; +import { RISKY_HOSTS_INDEX } from '../../../../common/constants'; +import { isIndexNotFoundError } from '../../../common/utils/exceptions'; + +export const QUERY_ID = 'risky_hosts'; +const noop = () => {}; + +export interface RiskyHost { + host: { + name: string; + }; + risk_score: number; + risk: string; +} + +const isRecord = (item: unknown): item is Record => + typeof item === 'object' && !!item; + +const isRiskyHostHit = (item: unknown): item is RiskyHost => + isRecord(item) && + isRecord(item.host) && + typeof item.host.name === 'string' && + typeof item.risk_score === 'number' && + typeof item.risk === 'string'; + +const getListItemsFromHits = (items: RiskyHost[]): LinkPanelListItem[] => { + return items.map(({ host, risk_score: count, risk: copy }) => ({ + title: host.name, + count, + copy, + path: '', + })); +}; + +export const useRiskyHostLinks = ({ to, from }: { to: string; from: string }) => { + const [isModuleEnabled, setIsModuleEnabled] = useState(undefined); + + const { addError } = useAppToasts(); + const { data } = useKibana().services; + + const dispatch = useDispatch(); + + const { error, loading, result, start } = useRiskyHostsComplete(); + + const deleteQuery = useCallback(() => { + dispatch(inputsActions.deleteOneQuery({ inputId: 'global', id: QUERY_ID })); + }, [dispatch]); + + useEffect(() => { + if (!loading && result) { + setIsModuleEnabled(true); + dispatch( + inputsActions.setQuery({ + inputId: 'global', + id: QUERY_ID, + inspect: { + dsl: result.inspect?.dsl ?? [], + response: [JSON.stringify(result.rawResponse, null, 2)], + }, + loading, + refetch: noop, + }) + ); + } + return deleteQuery; + }, [deleteQuery, dispatch, loading, result, setIsModuleEnabled]); + + useEffect(() => { + if (error) { + if (isIndexNotFoundError(error)) { + setIsModuleEnabled(false); + } else { + addError(error, { + title: i18n.translate('xpack.securitySolution.overview.riskyHostsError', { + defaultMessage: 'Error Fetching Risky Hosts', + }), + }); + setIsModuleEnabled(true); + } + } + }, [addError, error, setIsModuleEnabled]); + + useEffect(() => { + start({ + data, + timerange: { to, from, interval: '' }, + defaultIndex: [RISKY_HOSTS_INDEX], + filterQuery: '', + }); + }, [start, data, to, from]); + + return { + listItems: isRiskyHostHit(result?.rawResponse?.hits?.hits?.[0]?._source) + ? getListItemsFromHits( + result?.rawResponse?.hits?.hits?.map((hit) => hit._source) as RiskyHost[] + ) + : [], + isModuleEnabled, + loading, + }; +}; diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts.ts b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts.ts new file mode 100644 index 0000000000000..baf7606e8e238 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Observable } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { useObservable, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; +import { + DataPublicPluginStart, + isCompleteResponse, + isErrorResponse, +} from '../../../../../../../src/plugins/data/public'; +import { + HostsQueries, + HostsRiskyHostsRequestOptions, + HostsRiskyHostsStrategyResponse, +} from '../../../../common'; + +type GetRiskyHostsProps = HostsRiskyHostsRequestOptions & { + data: DataPublicPluginStart; + signal: AbortSignal; +}; + +export const getRiskyHosts = ({ + data, + defaultIndex, + filterQuery, + timerange, + signal, +}: GetRiskyHostsProps): Observable => + data.search.search( + { + defaultIndex, + factoryQueryType: HostsQueries.riskyHosts, + filterQuery, + timerange, + }, + { + strategy: 'securitySolutionSearchStrategy', + abortSignal: signal, + } + ); + +export const getRiskyHostsComplete = ( + props: GetRiskyHostsProps +): Observable => { + return getRiskyHosts(props).pipe( + filter((response) => { + return isErrorResponse(response) || isCompleteResponse(response); + }) + ); +}; + +const getRiskyHostsWithOptionalSignal = withOptionalSignal(getRiskyHostsComplete); + +export const useRiskyHostsComplete = () => useObservable(getRiskyHostsWithOptionalSignal); diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href.ts b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href.ts new file mode 100644 index 0000000000000..555ae7544180b --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useState, useEffect } from 'react'; +import { SavedObjectAttributes } from '@kbn/securitysolution-io-ts-alerting-types'; +import { useKibana } from '../../../common/lib/kibana'; + +const DASHBOARD_REQUEST_BODY_SEARCH = '"Current Risk Score for Hosts"'; +export const DASHBOARD_REQUEST_BODY = { + type: 'dashboard', + search: DASHBOARD_REQUEST_BODY_SEARCH, + fields: ['title'], +}; + +export const useRiskyHostsDashboardButtonHref = (to: string, from: string) => { + const createDashboardUrl = useKibana().services.dashboard?.dashboardUrlGenerator?.createUrl; + const savedObjectsClient = useKibana().services.savedObjects.client; + + const [buttonHref, setButtonHref] = useState(); + + useEffect(() => { + if (createDashboardUrl && savedObjectsClient) { + savedObjectsClient.find(DASHBOARD_REQUEST_BODY).then( + async (DashboardsSO?: { + savedObjects?: Array<{ + attributes?: SavedObjectAttributes; + id?: string; + }>; + }) => { + if (DashboardsSO?.savedObjects?.length) { + const dashboardUrl = await createDashboardUrl({ + dashboardId: DashboardsSO.savedObjects[0].id, + timeRange: { + to, + from, + }, + }); + setButtonHref(dashboardUrl); + } + } + ); + } + }, [createDashboardUrl, from, savedObjectsClient, to]); + + return { + buttonHref, + }; +}; diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_id.ts b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_id.ts new file mode 100644 index 0000000000000..c01e65fa20e81 --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_id.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useState, useEffect } from 'react'; +import { SavedObjectAttributes } from '@kbn/securitysolution-io-ts-alerting-types'; +import { useKibana } from '../../../common/lib/kibana'; + +const DASHBOARD_REQUEST_BODY_SEARCH = '"Drilldown of Host Risk Score"'; +export const DASHBOARD_REQUEST_BODY = { + type: 'dashboard', + search: DASHBOARD_REQUEST_BODY_SEARCH, + fields: ['title'], +}; + +export const useRiskyHostsDashboardId = () => { + const savedObjectsClient = useKibana().services.savedObjects.client; + const [dashboardId, setDashboardId] = useState(); + + useEffect(() => { + if (savedObjectsClient) { + savedObjectsClient.find(DASHBOARD_REQUEST_BODY).then( + async (DashboardsSO?: { + savedObjects?: Array<{ + attributes?: SavedObjectAttributes; + id?: string; + }>; + }) => { + if (DashboardsSO?.savedObjects?.length) { + setDashboardId(DashboardsSO.savedObjects[0].id); + } + } + ); + } + }, [savedObjectsClient]); + + return dashboardId; +}; diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_links.tsx b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_links.tsx new file mode 100644 index 0000000000000..ad592f016badb --- /dev/null +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_links.tsx @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useState, useEffect } from 'react'; +import { useKibana } from '../../../common/lib/kibana'; +import { LinkPanelListItem } from '../../components/link_panel'; +import { useRiskyHostsDashboardId } from './use_risky_hosts_dashboard_id'; + +export const useRiskyHostsDashboardLinks = ( + to: string, + from: string, + listItems: LinkPanelListItem[] +) => { + const createDashboardUrl = useKibana().services.dashboard?.dashboardUrlGenerator?.createUrl; + const dashboardId = useRiskyHostsDashboardId(); + const [listItemsWithLinks, setListItemsWithLinks] = useState([]); + + useEffect(() => { + let cancelled = false; + const createLinks = async () => { + if (createDashboardUrl && dashboardId) { + const dashboardUrls = await Promise.all( + listItems.map((listItem) => + createDashboardUrl({ + dashboardId, + timeRange: { + to, + from, + }, + filters: [ + { + meta: { + alias: null, + disabled: false, + negate: false, + }, + query: { match_phrase: { 'host.name': listItem.title } }, + }, + ], + }) + ) + ); + if (!cancelled) { + setListItemsWithLinks( + listItems.map((item, i) => ({ + ...item, + path: dashboardUrls[i] as unknown as string, + })) + ); + } + } else { + setListItemsWithLinks(listItems); + } + }; + createLinks(); + return () => { + cancelled = true; + }; + }, [createDashboardUrl, dashboardId, from, listItems, to]); + + return { listItemsWithLinks }; +}; diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx index d40f43c81aead..aadedda5d6233 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx @@ -31,6 +31,8 @@ import { } from '../components/overview_cti_links/mock'; import { useCtiDashboardLinks } from '../containers/overview_cti_links'; import { EndpointPrivileges } from '../../common/components/user_privileges/use_endpoint_privileges'; +import { useRiskyHostLinks } from '../containers/overview_risky_host_links/use_risky_host_links'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; jest.mock('../../common/lib/kibana'); jest.mock('../../common/containers/source'); @@ -72,7 +74,6 @@ jest.mock('../../common/containers/local_storage/use_messages_storage'); jest.mock('../containers/overview_cti_links'); jest.mock('../containers/overview_cti_links/use_cti_event_counts'); -jest.mock('../containers/overview_cti_links'); const useCtiDashboardLinksMock = useCtiDashboardLinks as jest.Mock; useCtiDashboardLinksMock.mockReturnValue(mockCtiLinksResponse); @@ -85,6 +86,18 @@ jest.mock('../containers/overview_cti_links/use_is_threat_intel_module_enabled') const useIsThreatIntelModuleEnabledMock = useIsThreatIntelModuleEnabled as jest.Mock; useIsThreatIntelModuleEnabledMock.mockReturnValue(true); +jest.mock('../containers/overview_risky_host_links/use_risky_host_links'); +const useRiskyHostLinksMock = useRiskyHostLinks as jest.Mock; +useRiskyHostLinksMock.mockReturnValue({ + loading: false, + isModuleEnabled: false, + listItems: [], +}); + +jest.mock('../../common/hooks/use_experimental_features'); +const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; +useIsExperimentalFeatureEnabledMock.mockReturnValue(true); + const endpointNoticeMessage = (hasMessageValue: boolean) => { return { hasMessage: () => hasMessageValue, diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx index ffafe211960d5..93c0bac5a88d7 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx @@ -34,7 +34,9 @@ import { useDeepEqualSelector } from '../../common/hooks/use_selector'; import { ThreatIntelLinkPanel } from '../components/overview_cti_links'; import { useIsThreatIntelModuleEnabled } from '../containers/overview_cti_links/use_is_threat_intel_module_enabled'; import { useUserPrivileges } from '../../common/components/user_privileges'; +import { RiskyHostLinks } from '../components/overview_risky_host_links'; import { useAlertsPrivileges } from '../../detections/containers/detection_engine/alerts/use_alerts_privileges'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; const SidebarFlexItem = styled(EuiFlexItem)` margin-right: 24px; @@ -76,6 +78,9 @@ const OverviewComponent = () => { } = useUserPrivileges(); const { hasIndexRead, hasKibanaREAD } = useAlertsPrivileges(); const isThreatIntelModuleEnabled = useIsThreatIntelModuleEnabled(); + + const riskyHostsEnabled = useIsExperimentalFeatureEnabled('riskyHostsEnabled'); + return ( <> {indicesExist ? ( @@ -146,13 +151,27 @@ const OverviewComponent = () => { /> - + + + + + + {riskyHostsEnabled && ( + + )} + + diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index f8a2de61f5d6f..cd65808f28bce 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -53,6 +53,7 @@ import { import { SecurityAppStore } from './common/store/store'; import { licenseService } from './common/hooks/use_license'; import { SecuritySolutionUiConfigType } from './common/types'; +import { ExperimentalFeaturesService } from './common/experimental_features_service'; import { getLazyEndpointPolicyEditExtension } from './management/pages/policy/view/ingest_manager_integration/lazy_endpoint_policy_edit_extension'; import { LazyEndpointPolicyCreateExtension } from './management/pages/policy/view/ingest_manager_integration/lazy_endpoint_policy_create_extension'; @@ -184,6 +185,7 @@ export class Plugin implements IPlugin = { enableExperimental: true, }, schema: configSchema, - deprecations: ({ renameFromRoot }) => [ + deprecations: ({ deprecate, renameFromRoot }) => [ + deprecate('enabled', '8.0.0'), renameFromRoot('xpack.siem.enabled', 'xpack.securitySolution.enabled'), renameFromRoot( 'xpack.siem.maxRuleImportExportSize', diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts index 1c03e52c67ae7..771e3e059c336 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts @@ -11,6 +11,8 @@ export const TELEMETRY_CHANNEL_LISTS = 'security-lists'; export const TELEMETRY_CHANNEL_ENDPOINT_META = 'endpoint-metadata'; +export const LIST_TRUSTED_APPLICATION = 'trusted_application'; + export const LIST_ENDPOINT_EXCEPTION = 'endpoint_exception'; export const LIST_ENDPOINT_EVENT_FILTER = 'endpoint_event_filter'; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/filters.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/filters.test.ts new file mode 100644 index 0000000000000..4844a10d99f90 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/telemetry/filters.test.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { copyAllowlistedFields } from './filters'; + +describe('Security Telemetry filters', () => { + describe('allowlistEventFields', () => { + const allowlist = { + a: true, + b: true, + c: { + d: true, + }, + }; + + it('filters top level', () => { + const event = { + a: 'a', + a1: 'a1', + b: 'b', + b1: 'b1', + }; + expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ + a: 'a', + b: 'b', + }); + }); + + it('filters nested', () => { + const event = { + a: { + a1: 'a1', + }, + a1: 'a1', + b: { + b1: 'b1', + }, + b1: 'b1', + c: { + d: 'd', + e: 'e', + f: 'f', + }, + }; + expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ + a: { + a1: 'a1', + }, + b: { + b1: 'b1', + }, + c: { + d: 'd', + }, + }); + }); + + it('filters arrays of objects', () => { + const event = { + a: [ + { + a1: 'a1', + }, + ], + b: { + b1: 'b1', + }, + c: [ + { + d: 'd1', + e: 'e1', + f: 'f1', + }, + { + d: 'd2', + e: 'e2', + f: 'f2', + }, + { + d: 'd3', + e: 'e3', + f: 'f3', + }, + ], + }; + expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ + a: [ + { + a1: 'a1', + }, + ], + b: { + b1: 'b1', + }, + c: [ + { + d: 'd1', + }, + { + d: 'd2', + }, + { + d: 'd3', + }, + ], + }); + }); + + it("doesn't create empty objects", () => { + const event = { + a: 'a', + b: 'b', + c: { + e: 'e', + }, + }; + expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ + a: 'a', + b: 'b', + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts b/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts index 18c3baccf9aa0..61172fac511f7 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/filters.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { TelemetryEvent } from './types'; + export interface AllowlistFields { [key: string]: boolean | AllowlistFields; } @@ -124,3 +126,48 @@ export const allowlistEventFields: AllowlistFields = { }, ...allowlistBaseEventFields, }; + +export const exceptionListEventFields: AllowlistFields = { + created_at: true, + description: true, + effectScope: true, + entries: true, + id: true, + name: true, + os: true, + os_types: true, +}; + +/** + * Filters out information not required for downstream analysis + * + * @param allowlist + * @param event + * @returns + */ +export function copyAllowlistedFields( + allowlist: AllowlistFields, + event: TelemetryEvent +): TelemetryEvent { + return Object.entries(allowlist).reduce((newEvent, [allowKey, allowValue]) => { + const eventValue = event[allowKey]; + if (eventValue !== null && eventValue !== undefined) { + if (allowValue === true) { + return { ...newEvent, [allowKey]: eventValue }; + } else if (typeof allowValue === 'object' && Array.isArray(eventValue)) { + const subValues = eventValue.filter((v) => typeof v === 'object'); + return { + ...newEvent, + [allowKey]: subValues.map((v) => copyAllowlistedFields(allowValue, v as TelemetryEvent)), + }; + } else if (typeof allowValue === 'object' && typeof eventValue === 'object') { + const values = copyAllowlistedFields(allowValue, eventValue as TelemetryEvent); + return { + ...newEvent, + ...(Object.keys(values).length > 0 ? { [allowKey]: values } : {}), + }; + } + } + return newEvent; + }, {}); +} diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts index a4d11b71f2a8e..647219e8c5585 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts @@ -7,17 +7,19 @@ import moment from 'moment'; import { createMockPackagePolicy } from './mocks'; -import { TrustedApp } from '../../../common/endpoint/types'; -import { LIST_ENDPOINT_EXCEPTION, LIST_ENDPOINT_EVENT_FILTER } from './constants'; +import { + LIST_ENDPOINT_EXCEPTION, + LIST_ENDPOINT_EVENT_FILTER, + LIST_TRUSTED_APPLICATION, +} from './constants'; import { getPreviousDiagTaskTimestamp, getPreviousEpMetaTaskTimestamp, batchTelemetryRecords, isPackagePolicyList, - templateTrustedApps, - templateEndpointExceptions, + templateExceptionList, } from './helpers'; -import { EndpointExceptionListItem } from './types'; +import { ExceptionListItem } from './types'; describe('test diagnostic telemetry scheduled task timing helper', () => { test('test -5 mins is returned when there is no previous task run', async () => { @@ -133,8 +135,8 @@ describe('test package policy type guard', () => { describe('list telemetry schema', () => { test('trusted apps document is correctly formed', () => { - const data = [{ id: 'test_1' }] as TrustedApp[]; - const templatedItems = templateTrustedApps(data); + const data = [{ id: 'test_1' }] as ExceptionListItem[]; + const templatedItems = templateExceptionList(data, LIST_TRUSTED_APPLICATION); expect(templatedItems[0]?.trusted_application.length).toEqual(1); expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); @@ -142,8 +144,8 @@ describe('list telemetry schema', () => { }); test('trusted apps document is correctly formed with multiple entries', () => { - const data = [{ id: 'test_2' }, { id: 'test_2' }] as TrustedApp[]; - const templatedItems = templateTrustedApps(data); + const data = [{ id: 'test_2' }, { id: 'test_2' }] as ExceptionListItem[]; + const templatedItems = templateExceptionList(data, LIST_TRUSTED_APPLICATION); expect(templatedItems[0]?.trusted_application.length).toEqual(1); expect(templatedItems[1]?.trusted_application.length).toEqual(1); @@ -152,8 +154,8 @@ describe('list telemetry schema', () => { }); test('endpoint exception document is correctly formed', () => { - const data = [{ id: 'test_3' }] as EndpointExceptionListItem[]; - const templatedItems = templateEndpointExceptions(data, LIST_ENDPOINT_EXCEPTION); + const data = [{ id: 'test_3' }] as ExceptionListItem[]; + const templatedItems = templateExceptionList(data, LIST_ENDPOINT_EXCEPTION); expect(templatedItems[0]?.trusted_application.length).toEqual(0); expect(templatedItems[0]?.endpoint_exception.length).toEqual(1); @@ -161,12 +163,8 @@ describe('list telemetry schema', () => { }); test('endpoint exception document is correctly formed with multiple entries', () => { - const data = [ - { id: 'test_4' }, - { id: 'test_4' }, - { id: 'test_4' }, - ] as EndpointExceptionListItem[]; - const templatedItems = templateEndpointExceptions(data, LIST_ENDPOINT_EXCEPTION); + const data = [{ id: 'test_4' }, { id: 'test_4' }, { id: 'test_4' }] as ExceptionListItem[]; + const templatedItems = templateExceptionList(data, LIST_ENDPOINT_EXCEPTION); expect(templatedItems[0]?.trusted_application.length).toEqual(0); expect(templatedItems[0]?.endpoint_exception.length).toEqual(1); @@ -176,8 +174,8 @@ describe('list telemetry schema', () => { }); test('endpoint event filters document is correctly formed', () => { - const data = [{ id: 'test_5' }] as EndpointExceptionListItem[]; - const templatedItems = templateEndpointExceptions(data, LIST_ENDPOINT_EVENT_FILTER); + const data = [{ id: 'test_5' }] as ExceptionListItem[]; + const templatedItems = templateExceptionList(data, LIST_ENDPOINT_EVENT_FILTER); expect(templatedItems[0]?.trusted_application.length).toEqual(0); expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); @@ -185,8 +183,8 @@ describe('list telemetry schema', () => { }); test('endpoint event filters document is correctly formed with multiple entries', () => { - const data = [{ id: 'test_6' }, { id: 'test_6' }] as EndpointExceptionListItem[]; - const templatedItems = templateEndpointExceptions(data, LIST_ENDPOINT_EVENT_FILTER); + const data = [{ id: 'test_6' }, { id: 'test_6' }] as ExceptionListItem[]; + const templatedItems = templateExceptionList(data, LIST_ENDPOINT_EVENT_FILTER); expect(templatedItems[0]?.trusted_application.length).toEqual(0); expect(templatedItems[0]?.endpoint_exception.length).toEqual(0); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts index bb2cc4f42ca90..a9eaef3ce6edc 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts @@ -7,10 +7,15 @@ import moment from 'moment'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { TrustedApp } from '../../../common/endpoint/types'; import { PackagePolicy } from '../../../../fleet/common/types/models/package_policy'; -import { EndpointExceptionListItem, ListTemplate } from './types'; -import { LIST_ENDPOINT_EXCEPTION, LIST_ENDPOINT_EVENT_FILTER } from './constants'; +import { copyAllowlistedFields, exceptionListEventFields } from './filters'; +import { ExceptionListItem, ListTemplate, TelemetryEvent } from './types'; +import { + LIST_ENDPOINT_EXCEPTION, + LIST_ENDPOINT_EVENT_FILTER, + LIST_TRUSTED_APPLICATION, +} from './constants'; +import { TrustedApp } from '../../../common/endpoint/types'; /** * Determines the when the last run was in order to execute to. @@ -89,43 +94,41 @@ export function isPackagePolicyList( } /** - * Maps Exception list item to parsable object + * Maps trusted application to shared telemetry object * * @param exceptionListItem * @returns collection of endpoint exceptions */ -export const exceptionListItemToEndpointEntry = (exceptionListItem: ExceptionListItemSchema) => { +export const trustedApplicationToTelemetryEntry = (trustedApplication: TrustedApp) => { + return { + id: trustedApplication.id, + version: trustedApplication.version || '', + name: trustedApplication.name, + description: trustedApplication.description, + created_at: trustedApplication.created_at, + updated_at: trustedApplication.updated_at, + entries: trustedApplication.entries, + os: trustedApplication.os, + } as ExceptionListItem; +}; + +/** + * Maps endpoint lists to shared telemetry object + * + * @param exceptionListItem + * @returns collection of endpoint exceptions + */ +export const exceptionListItemToTelemetryEntry = (exceptionListItem: ExceptionListItemSchema) => { return { id: exceptionListItem.id, version: exceptionListItem._version || '', name: exceptionListItem.name, description: exceptionListItem.description, created_at: exceptionListItem.created_at, - created_by: exceptionListItem.created_by, updated_at: exceptionListItem.updated_at, - updated_by: exceptionListItem.updated_by, entries: exceptionListItem.entries, os_types: exceptionListItem.os_types, - } as EndpointExceptionListItem; -}; - -/** - * Constructs the lists telemetry schema from a collection of Trusted Apps - * - * @param listData - * @returns lists telemetry schema - */ -export const templateTrustedApps = (listData: TrustedApp[]) => { - return listData.map((item) => { - const template: ListTemplate = { - trusted_application: [], - endpoint_exception: [], - endpoint_event_filter: [], - }; - - template.trusted_application.push(item); - return template; - }); + } as ExceptionListItem; }; /** @@ -135,10 +138,7 @@ export const templateTrustedApps = (listData: TrustedApp[]) => { * @param listType * @returns lists telemetry schema */ -export const templateEndpointExceptions = ( - listData: EndpointExceptionListItem[], - listType: string -) => { +export const templateExceptionList = (listData: ExceptionListItem[], listType: string) => { return listData.map((item) => { const template: ListTemplate = { trusted_application: [], @@ -146,13 +146,24 @@ export const templateEndpointExceptions = ( endpoint_event_filter: [], }; + // cast exception list type to a TelemetryEvent for allowlist filtering + const filteredListItem = copyAllowlistedFields( + exceptionListEventFields, + item as unknown as TelemetryEvent + ); + + if (listType === LIST_TRUSTED_APPLICATION) { + template.trusted_application.push(filteredListItem); + return template; + } + if (listType === LIST_ENDPOINT_EXCEPTION) { - template.endpoint_exception.push(item); + template.endpoint_exception.push(filteredListItem); return template; } if (listType === LIST_ENDPOINT_EVENT_FILTER) { - template.endpoint_event_filter.push(item); + template.endpoint_event_filter.push(filteredListItem); return template; } diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts index 06dffdddc49c8..8b715b8e8d585 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts @@ -17,7 +17,7 @@ import { AgentService, AgentPolicyServiceInterface } from '../../../../fleet/ser import { ExceptionListClient } from '../../../../lists/server'; import { EndpointAppContextService } from '../../endpoint/endpoint_app_context_services'; import { TELEMETRY_MAX_BUFFER_SIZE } from './constants'; -import { exceptionListItemToEndpointEntry } from './helpers'; +import { exceptionListItemToTelemetryEntry, trustedApplicationToTelemetryEntry } from './helpers'; import { TelemetryEvent, ESLicense, ESClusterInfo, GetEndpointListResponse } from './types'; export class TelemetryReceiver { @@ -202,7 +202,16 @@ export class TelemetryReceiver { throw Error('exception list client is unavailable: cannot retrieve trusted applications'); } - return getTrustedAppsList(this.exceptionListClient, { page: 1, per_page: 10_000 }); + const results = await getTrustedAppsList(this.exceptionListClient, { + page: 1, + per_page: 10_000, + }); + return { + data: results?.data.map(trustedApplicationToTelemetryEntry), + total: results?.total ?? 0, + page: results?.page ?? 1, + per_page: results?.per_page ?? this.max_records, + }; } public async fetchEndpointList(listId: string): Promise { @@ -224,7 +233,7 @@ export class TelemetryReceiver { }); return { - data: results?.data.map(exceptionListItemToEndpointEntry) ?? [], + data: results?.data.map(exceptionListItemToTelemetryEntry) ?? [], total: results?.total ?? 0, page: results?.page ?? 1, per_page: results?.per_page ?? this.max_records, diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts index d04d0ab49afe9..21e6b2cf6d9c4 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.test.ts @@ -6,7 +6,7 @@ */ /* eslint-disable dot-notation */ -import { TelemetryEventsSender, copyAllowlistedFields } from './sender'; +import { TelemetryEventsSender } from './sender'; import { loggingSystemMock } from 'src/core/server/mocks'; import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; import { URL } from 'url'; @@ -220,123 +220,6 @@ describe('TelemetryEventsSender', () => { }); }); -describe('allowlistEventFields', () => { - const allowlist = { - a: true, - b: true, - c: { - d: true, - }, - }; - - it('filters top level', () => { - const event = { - a: 'a', - a1: 'a1', - b: 'b', - b1: 'b1', - }; - expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ - a: 'a', - b: 'b', - }); - }); - - it('filters nested', () => { - const event = { - a: { - a1: 'a1', - }, - a1: 'a1', - b: { - b1: 'b1', - }, - b1: 'b1', - c: { - d: 'd', - e: 'e', - f: 'f', - }, - }; - expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ - a: { - a1: 'a1', - }, - b: { - b1: 'b1', - }, - c: { - d: 'd', - }, - }); - }); - - it('filters arrays of objects', () => { - const event = { - a: [ - { - a1: 'a1', - }, - ], - b: { - b1: 'b1', - }, - c: [ - { - d: 'd1', - e: 'e1', - f: 'f1', - }, - { - d: 'd2', - e: 'e2', - f: 'f2', - }, - { - d: 'd3', - e: 'e3', - f: 'f3', - }, - ], - }; - expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ - a: [ - { - a1: 'a1', - }, - ], - b: { - b1: 'b1', - }, - c: [ - { - d: 'd1', - }, - { - d: 'd2', - }, - { - d: 'd3', - }, - ], - }); - }); - - it("doesn't create empty objects", () => { - const event = { - a: 'a', - b: 'b', - c: { - e: 'e', - }, - }; - expect(copyAllowlistedFields(allowlist, event)).toStrictEqual({ - a: 'a', - b: 'b', - }); - }); -}); - describe('getV3UrlFromV2', () => { let logger: ReturnType; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 2e615a2681174..0037aaa28fee3 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -17,7 +17,7 @@ import { TaskManagerStartContract, } from '../../../../task_manager/server'; import { TelemetryReceiver } from './receiver'; -import { AllowlistFields, allowlistEventFields } from './filters'; +import { allowlistEventFields, copyAllowlistedFields } from './filters'; import { DiagnosticTask, EndpointTask, ExceptionListsTask } from './tasks'; import { createUsageCounterLabel } from './helpers'; import { TelemetryEvent } from './types'; @@ -194,8 +194,8 @@ export class TelemetryEventsSender { /** * This function sends events to the elastic telemetry channel. Caution is required - * because it does no allowlist filtering. The caller is responsible for making sure - * that there is no sensitive material or PII in the records that are sent upstream. + * because it does no allowlist filtering at send time. The function call site is + * responsible for ensuring sure no sensitive material is in telemetry events. * * @param channel the elastic telemetry channel * @param toSend telemetry events @@ -294,30 +294,3 @@ export class TelemetryEventsSender { } } } - -export function copyAllowlistedFields( - allowlist: AllowlistFields, - event: TelemetryEvent -): TelemetryEvent { - return Object.entries(allowlist).reduce((newEvent, [allowKey, allowValue]) => { - const eventValue = event[allowKey]; - if (eventValue !== null && eventValue !== undefined) { - if (allowValue === true) { - return { ...newEvent, [allowKey]: eventValue }; - } else if (typeof allowValue === 'object' && Array.isArray(eventValue)) { - const subValues = eventValue.filter((v) => typeof v === 'object'); - return { - ...newEvent, - [allowKey]: subValues.map((v) => copyAllowlistedFields(allowValue, v as TelemetryEvent)), - }; - } else if (typeof allowValue === 'object' && typeof eventValue === 'object') { - const values = copyAllowlistedFields(allowValue, eventValue as TelemetryEvent); - return { - ...newEvent, - ...(Object.keys(values).length > 0 ? { [allowKey]: values } : {}), - }; - } - } - return newEvent; - }, {}); -} diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts index b54858e1f5f42..fe2039419b02d 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts @@ -19,9 +19,10 @@ import { import { LIST_ENDPOINT_EXCEPTION, LIST_ENDPOINT_EVENT_FILTER, + LIST_TRUSTED_APPLICATION, TELEMETRY_CHANNEL_LISTS, } from '../constants'; -import { batchTelemetryRecords, templateEndpointExceptions, templateTrustedApps } from '../helpers'; +import { batchTelemetryRecords, templateExceptionList } from '../helpers'; import { TelemetryEventsSender } from '../sender'; import { TelemetryReceiver } from '../receiver'; @@ -110,7 +111,7 @@ export class TelemetryExceptionListsTask { // Lists Telemetry: Trusted Applications const trustedApps = await this.receiver.fetchTrustedApplications(); - const trustedAppsJson = templateTrustedApps(trustedApps.data); + const trustedAppsJson = templateExceptionList(trustedApps.data, LIST_TRUSTED_APPLICATION); this.logger.debug(`Trusted Apps: ${trustedAppsJson}`); batchTelemetryRecords(trustedAppsJson, MAX_TELEMETRY_BATCH).forEach((batch) => @@ -120,7 +121,7 @@ export class TelemetryExceptionListsTask { // Lists Telemetry: Endpoint Exceptions const epExceptions = await this.receiver.fetchEndpointList(ENDPOINT_LIST_ID); - const epExceptionsJson = templateEndpointExceptions(epExceptions.data, LIST_ENDPOINT_EXCEPTION); + const epExceptionsJson = templateExceptionList(epExceptions.data, LIST_ENDPOINT_EXCEPTION); this.logger.debug(`EP Exceptions: ${epExceptionsJson}`); batchTelemetryRecords(epExceptionsJson, MAX_TELEMETRY_BATCH).forEach((batch) => @@ -130,7 +131,7 @@ export class TelemetryExceptionListsTask { // Lists Telemetry: Endpoint Event Filters const epFilters = await this.receiver.fetchEndpointList(ENDPOINT_EVENT_FILTERS_LIST_ID); - const epFiltersJson = templateEndpointExceptions(epFilters.data, LIST_ENDPOINT_EVENT_FILTER); + const epFiltersJson = templateExceptionList(epFilters.data, LIST_ENDPOINT_EVENT_FILTER); this.logger.debug(`EP Event Filters: ${epFiltersJson}`); batchTelemetryRecords(epFiltersJson, MAX_TELEMETRY_BATCH).forEach((batch) => diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/types.ts b/x-pack/plugins/security_solution/server/lib/telemetry/types.ts index b78017314a982..abcad26ed000c 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/types.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/types.ts @@ -6,7 +6,6 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; -import { TrustedApp } from '../../../common/endpoint/types'; type BaseSearchTypes = string | number | boolean | object; export type SearchTypes = BaseSearchTypes | BaseSearchTypes[] | undefined; @@ -211,26 +210,25 @@ export interface GetEndpointListResponse { per_page: number; page: number; total: number; - data: EndpointExceptionListItem[]; + data: ExceptionListItem[]; } // Telemetry List types -export interface EndpointExceptionListItem { +export interface ExceptionListItem { id: string; version: string; name: string; description: string; created_at: string; - created_by: string; updated_at: string; - updated_by: string; entries: object; + os: string; os_types: object; } export interface ListTemplate { - trusted_application: TrustedApp[]; - endpoint_exception: EndpointExceptionListItem[]; - endpoint_event_filter: EndpointExceptionListItem[]; + trusted_application: TelemetryEvent[]; + endpoint_exception: TelemetryEvent[]; + endpoint_event_filter: TelemetryEvent[]; } diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/field_migrator.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/field_migrator.ts new file mode 100644 index 0000000000000..5939676c2a924 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/field_migrator.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TIMELINE_ID_REF_NAME } from '../../constants'; +import { timelineSavedObjectType } from '../../saved_object_mappings'; +import { FieldMigrator } from '../../utils/migrator'; + +/** + * A migrator to handle moving specific fields that reference the timeline saved object to the references field within a note saved + * object. + */ +export const pinnedEventFieldsMigrator = new FieldMigrator([ + { path: 'timelineId', type: timelineSavedObjectType, name: TIMELINE_ID_REF_NAME }, +]); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts index b3d262b13cbf3..260531e1106bf 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts @@ -19,13 +19,13 @@ import { PinnedEventSavedObjectRuntimeType, SavedPinnedEvent, PinnedEvent as PinnedEventResponse, + PinnedEventWithoutExternalRefs, } from '../../../../../common/types/timeline/pinned_event'; -import { PageInfoNote, SortNote } from '../../../../../common/types/timeline/note'; import { FrameworkRequest } from '../../../framework'; -import { pickSavedTimeline } from '../../saved_object/timelines'; -import { convertSavedObjectToSavedTimeline } from '../timelines'; +import { createTimeline } from '../../saved_object/timelines'; import { pinnedEventSavedObjectType } from '../../saved_object_mappings/pinned_events'; +import { pinnedEventFieldsMigrator } from './field_migrator'; import { timelineSavedObjectType } from '../../saved_object_mappings'; export interface PinnedEvent { @@ -46,13 +46,6 @@ export interface PinnedEvent { timelineId: string ) => Promise; - getAllPinnedEvents: ( - request: FrameworkRequest, - pageInfo: PageInfoNote | null, - search: string | null, - sort: SortNote | null - ) => Promise; - persistPinnedEventOnTimeline: ( request: FrameworkRequest, pinnedEventId: string | null, // pinned event saved object id @@ -117,26 +110,7 @@ export const getAllPinnedEventsByTimelineId = async ( ): Promise => { const options: SavedObjectsFindOptions = { type: pinnedEventSavedObjectType, - search: timelineId, - searchFields: ['timelineId'], - }; - return getAllSavedPinnedEvents(request, options); -}; - -export const getAllPinnedEvents = async ( - request: FrameworkRequest, - pageInfo: PageInfoNote | null, - search: string | null, - sort: SortNote | null -): Promise => { - const options: SavedObjectsFindOptions = { - type: pinnedEventSavedObjectType, - perPage: pageInfo != null ? pageInfo.pageSize : undefined, - page: pageInfo != null ? pageInfo.pageIndex : undefined, - search: search != null ? search : undefined, - searchFields: ['timelineId', 'eventId'], - sortField: sort != null ? sort.sortField : undefined, - sortOrder: sort != null ? sort.sortOrder : undefined, + hasReference: { type: timelineSavedObjectType, id: timelineId }, }; return getAllSavedPinnedEvents(request, options); }; @@ -147,51 +121,35 @@ export const persistPinnedEventOnTimeline = async ( eventId: string, timelineId: string | null ): Promise => { - const savedObjectsClient = request.context.core.savedObjects.client; - try { - if (pinnedEventId == null) { - const timelineVersionSavedObject = - timelineId == null - ? await (async () => { - const timelineResult = convertSavedObjectToSavedTimeline( - await savedObjectsClient.create( - timelineSavedObjectType, - pickSavedTimeline(null, {}, request.user || null) - ) - ); - timelineId = timelineResult.savedObjectId; // eslint-disable-line no-param-reassign - return timelineResult.version; - })() - : null; - - if (timelineId != null) { - const allPinnedEventId = await getAllPinnedEventsByTimelineId(request, timelineId); - const isPinnedAlreadyExisting = allPinnedEventId.filter( - (pinnedEvent) => pinnedEvent.eventId === eventId - ); - - if (isPinnedAlreadyExisting.length === 0) { - const savedPinnedEvent: SavedPinnedEvent = { - eventId, - timelineId, - }; - // create Pinned Event on Timeline - return convertSavedObjectToSavedPinnedEvent( - await savedObjectsClient.create( - pinnedEventSavedObjectType, - pickSavedPinnedEvent(pinnedEventId, savedPinnedEvent, request.user || null) - ), - timelineVersionSavedObject != null ? timelineVersionSavedObject : undefined - ); - } - return isPinnedAlreadyExisting[0]; - } - throw new Error('You can NOT pinned event without a timelineID'); + if (pinnedEventId != null) { + // Delete Pinned Event on Timeline + await deletePinnedEventOnTimeline(request, [pinnedEventId]); + return null; } - // Delete Pinned Event on Timeline - await deletePinnedEventOnTimeline(request, [pinnedEventId]); - return null; + + const { timelineId: validatedTimelineId, timelineVersion } = await getValidTimelineIdAndVersion( + request, + timelineId + ); + + const pinnedEvents = await getPinnedEventsInTimelineWithEventId( + request, + validatedTimelineId, + eventId + ); + + // we already had this event pinned so let's just return the one we already had + if (pinnedEvents.length > 0) { + return pinnedEvents[0]; + } + + return await createPinnedEvent({ + request, + eventId, + timelineId: validatedTimelineId, + timelineVersion, + }); } catch (err) { if (getOr(null, 'output.statusCode', err) === 404) { /* @@ -215,11 +173,91 @@ export const persistPinnedEventOnTimeline = async ( } }; +const getValidTimelineIdAndVersion = async ( + request: FrameworkRequest, + timelineId: string | null +): Promise<{ timelineId: string; timelineVersion?: string }> => { + if (timelineId != null) { + return { + timelineId, + }; + } + + const savedObjectsClient = request.context.core.savedObjects.client; + + // create timeline because it didn't exist + const { timeline: timelineResult } = await createTimeline({ + timelineId: null, + timeline: {}, + savedObjectsClient, + userInfo: request.user, + }); + + return { + timelineId: timelineResult.savedObjectId, + timelineVersion: timelineResult.version, + }; +}; + +const getPinnedEventsInTimelineWithEventId = async ( + request: FrameworkRequest, + timelineId: string, + eventId: string +): Promise => { + const allPinnedEventId = await getAllPinnedEventsByTimelineId(request, timelineId); + const pinnedEvents = allPinnedEventId.filter((pinnedEvent) => pinnedEvent.eventId === eventId); + + return pinnedEvents; +}; + +const createPinnedEvent = async ({ + request, + eventId, + timelineId, + timelineVersion, +}: { + request: FrameworkRequest; + eventId: string; + timelineId: string; + timelineVersion?: string; +}) => { + const savedObjectsClient = request.context.core.savedObjects.client; + + const savedPinnedEvent: SavedPinnedEvent = { + eventId, + timelineId, + }; + + const pinnedEventWithCreator = pickSavedPinnedEvent(null, savedPinnedEvent, request.user); + + const { transformedFields: migratedAttributes, references } = + pinnedEventFieldsMigrator.extractFieldsToReferences({ + data: pinnedEventWithCreator, + }); + + const createdPinnedEvent = await savedObjectsClient.create( + pinnedEventSavedObjectType, + migratedAttributes, + { references } + ); + + const repopulatedSavedObject = + pinnedEventFieldsMigrator.populateFieldsFromReferences(createdPinnedEvent); + + // create Pinned Event on Timeline + return convertSavedObjectToSavedPinnedEvent(repopulatedSavedObject, timelineVersion); +}; + const getSavedPinnedEvent = async (request: FrameworkRequest, pinnedEventId: string) => { const savedObjectsClient = request.context.core.savedObjects.client; - const savedObject = await savedObjectsClient.get(pinnedEventSavedObjectType, pinnedEventId); + const savedObject = await savedObjectsClient.get( + pinnedEventSavedObjectType, + pinnedEventId + ); + + const populatedPinnedEvent = pinnedEventFieldsMigrator.populateFieldsFromReferences(savedObject); - return convertSavedObjectToSavedPinnedEvent(savedObject); + return convertSavedObjectToSavedPinnedEvent(populatedPinnedEvent); }; const getAllSavedPinnedEvents = async ( @@ -227,11 +265,14 @@ const getAllSavedPinnedEvents = async ( options: SavedObjectsFindOptions ) => { const savedObjectsClient = request.context.core.savedObjects.client; - const savedObjects = await savedObjectsClient.find(options); + const savedObjects = await savedObjectsClient.find(options); - return savedObjects.saved_objects.map((savedObject) => - convertSavedObjectToSavedPinnedEvent(savedObject) - ); + return savedObjects.saved_objects.map((savedObject) => { + const populatedPinnedEvent = + pinnedEventFieldsMigrator.populateFieldsFromReferences(savedObject); + + return convertSavedObjectToSavedPinnedEvent(populatedPinnedEvent); + }); }; export const savePinnedEvents = ( @@ -284,11 +325,10 @@ export const pickSavedPinnedEvent = ( if (pinnedEventId == null) { savedPinnedEvent.created = dateNow; savedPinnedEvent.createdBy = userInfo?.username ?? UNAUTHENTICATED_USER; - savedPinnedEvent.updated = dateNow; - savedPinnedEvent.updatedBy = userInfo?.username ?? UNAUTHENTICATED_USER; - } else if (pinnedEventId != null) { - savedPinnedEvent.updated = dateNow; - savedPinnedEvent.updatedBy = userInfo?.username ?? UNAUTHENTICATED_USER; } + + savedPinnedEvent.updated = dateNow; + savedPinnedEvent.updatedBy = userInfo?.username ?? UNAUTHENTICATED_USER; + return savedPinnedEvent; }; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/notes.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/notes.test.ts deleted file mode 100644 index b9649896c25a6..0000000000000 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/notes.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { TIMELINE_ID_REF_NAME } from '../../constants'; -import { migrateNoteTimelineIdToReferences, TimelineId } from './notes'; - -describe('notes migrations', () => { - describe('7.16.0 timelineId', () => { - it('removes the timelineId from the migrated document', () => { - const migratedDoc = migrateNoteTimelineIdToReferences({ - id: '1', - type: 'awesome', - attributes: { timelineId: '123' }, - }); - - expect(migratedDoc.attributes).toEqual({}); - expect(migratedDoc.references).toEqual([ - // importing the timeline saved object type from the timeline saved object causes a circular import and causes the jest tests to fail - { id: '123', name: TIMELINE_ID_REF_NAME, type: 'siem-ui-timeline' }, - ]); - }); - - it('preserves additional fields when migrating timeline id', () => { - const migratedDoc = migrateNoteTimelineIdToReferences({ - id: '1', - type: 'awesome', - attributes: { awesome: 'yes', timelineId: '123' } as unknown as TimelineId, - }); - - expect(migratedDoc.attributes).toEqual({ awesome: 'yes' }); - expect(migratedDoc.references).toEqual([ - { id: '123', name: TIMELINE_ID_REF_NAME, type: 'siem-ui-timeline' }, - ]); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/notes.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/notes.ts index a8d753e916afb..76773b7fcd518 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/notes.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/notes.ts @@ -5,39 +5,9 @@ * 2.0. */ -import { - SavedObjectMigrationMap, - SavedObjectSanitizedDoc, - SavedObjectUnsanitizedDoc, -} from 'kibana/server'; -import { timelineSavedObjectType } from '..'; -import { TIMELINE_ID_REF_NAME } from '../../constants'; -import { createMigratedDoc, createReference } from './utils'; - -export interface TimelineId { - timelineId?: string | null; -} - -export const migrateNoteTimelineIdToReferences = ( - doc: SavedObjectUnsanitizedDoc -): SavedObjectSanitizedDoc => { - const { timelineId, ...restAttributes } = doc.attributes; - - const { references: docReferences = [] } = doc; - const timelineIdReferences = createReference( - timelineId, - TIMELINE_ID_REF_NAME, - timelineSavedObjectType - ); - - return createMigratedDoc({ - doc, - attributes: restAttributes, - docReferences, - migratedReferences: timelineIdReferences, - }); -}; +import { SavedObjectMigrationMap } from 'kibana/server'; +import { migrateTimelineIdToReferences } from './utils'; export const notesMigrations: SavedObjectMigrationMap = { - '7.16.0': migrateNoteTimelineIdToReferences, + '7.16.0': migrateTimelineIdToReferences, }; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/pinned_events.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/pinned_events.ts new file mode 100644 index 0000000000000..4d21190d9381c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/pinned_events.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectMigrationMap } from 'kibana/server'; +import { migrateTimelineIdToReferences } from './utils'; + +export const pinnedEventsMigrations: SavedObjectMigrationMap = { + '7.16.0': migrateTimelineIdToReferences, +}; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/types.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/types.ts new file mode 100644 index 0000000000000..7c62310a99aa6 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/types.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface TimelineId { + timelineId?: string | null; +} diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/utils.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/utils.test.ts index 02e3fca996d5d..329f09e85f3a7 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/utils.test.ts @@ -5,9 +5,39 @@ * 2.0. */ -import { createMigratedDoc, createReference } from './utils'; +import { timelineSavedObjectType } from '../timelines'; +import { TIMELINE_ID_REF_NAME } from '../../constants'; +import { TimelineId } from './types'; +import { createMigratedDoc, createReference, migrateTimelineIdToReferences } from './utils'; describe('migration utils', () => { + describe('migrateTimelineIdToReferences', () => { + it('removes the timelineId from the migrated document', () => { + const migratedDoc = migrateTimelineIdToReferences({ + id: '1', + type: 'awesome', + attributes: { timelineId: '123' }, + }); + + expect(migratedDoc.attributes).toEqual({}); + expect(migratedDoc.references).toEqual([ + { id: '123', name: TIMELINE_ID_REF_NAME, type: timelineSavedObjectType }, + ]); + }); + + it('preserves additional fields when migrating timeline id', () => { + const migratedDoc = migrateTimelineIdToReferences({ + id: '1', + type: 'awesome', + attributes: { awesome: 'yes', timelineId: '123' } as unknown as TimelineId, + }); + + expect(migratedDoc.attributes).toEqual({ awesome: 'yes' }); + expect(migratedDoc.references).toEqual([ + { id: '123', name: TIMELINE_ID_REF_NAME, type: timelineSavedObjectType }, + ]); + }); + }); describe('createReference', () => { it('returns an array with a reference when the id is defined', () => { expect(createReference('awesome', 'name', 'type')).toEqual([ diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/utils.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/utils.ts index ff9b56e6ae2c9..7bd7bc148c263 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/migrations/utils.ts @@ -10,6 +10,9 @@ import { SavedObjectSanitizedDoc, SavedObjectUnsanitizedDoc, } from 'kibana/server'; +import { timelineSavedObjectType } from '../timelines'; +import { TIMELINE_ID_REF_NAME } from '../../constants'; +import { TimelineId } from './types'; export function createReference( id: string | null | undefined, @@ -19,6 +22,26 @@ export function createReference( return id != null ? [{ id, name, type }] : []; } +export const migrateTimelineIdToReferences = ( + doc: SavedObjectUnsanitizedDoc +): SavedObjectSanitizedDoc => { + const { timelineId, ...restAttributes } = doc.attributes; + + const { references: docReferences = [] } = doc; + const timelineIdReferences = createReference( + timelineId, + TIMELINE_ID_REF_NAME, + timelineSavedObjectType + ); + + return createMigratedDoc({ + doc, + attributes: restAttributes, + docReferences, + migratedReferences: timelineIdReferences, + }); +}; + export const createMigratedDoc = ({ doc, attributes, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts index 387f78e5059f4..eda2478e7809d 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts @@ -6,7 +6,7 @@ */ import { SavedObjectsType } from '../../../../../../../src/core/server'; -import { notesMigrations } from './migrations'; +import { notesMigrations } from './migrations/notes'; export const noteSavedObjectType = 'siem-ui-timeline-note'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts index fbbffe35a58c0..2f8e72ad763f9 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts @@ -6,14 +6,12 @@ */ import { SavedObjectsType } from '../../../../../../../src/core/server'; +import { pinnedEventsMigrations } from './migrations/pinned_events'; export const pinnedEventSavedObjectType = 'siem-ui-timeline-pinned-event'; export const pinnedEventSavedObjectMappings: SavedObjectsType['mappings'] = { properties: { - timelineId: { - type: 'keyword', - }, eventId: { type: 'keyword', }, @@ -37,4 +35,5 @@ export const pinnedEventType: SavedObjectsType = { hidden: false, namespaceType: 'single', mappings: pinnedEventSavedObjectMappings, + migrations: pinnedEventsMigrations, }; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts index 8300f72a162ed..e1e3a454087f9 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts @@ -6,7 +6,7 @@ */ import { SavedObjectsType } from '../../../../../../../src/core/server'; -import { timelinesMigrations } from './migrations'; +import { timelinesMigrations } from './migrations/timelines'; export const timelineSavedObjectType = 'siem-ui-timeline'; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.test.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.test.ts index fbe1ac6413bef..b807806e18091 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.test.ts @@ -10,6 +10,7 @@ import { HostsQueries, HostsKpiQueries } from '../../../../../common/search_stra import { allHosts } from './all'; import { hostDetails } from './details'; import { hostOverview } from './overview'; +import { riskyHosts } from './risky_hosts'; import { firstOrLastSeenHost } from './last_first_seen'; import { uncommonProcesses } from './uncommon_processes'; import { authentications, authenticationsEntities } from './authentications'; @@ -26,6 +27,7 @@ jest.mock('./authentications'); jest.mock('./kpi/authentications'); jest.mock('./kpi/hosts'); jest.mock('./kpi/unique_ips'); +jest.mock('./risky_hosts'); describe('hostsFactory', () => { test('should include correct apis', () => { @@ -37,6 +39,7 @@ describe('hostsFactory', () => { [HostsQueries.uncommonProcesses]: uncommonProcesses, [HostsQueries.authentications]: authentications, [HostsQueries.authenticationsEntities]: authenticationsEntities, + [HostsQueries.riskyHosts]: riskyHosts, [HostsKpiQueries.kpiAuthentications]: hostsKpiAuthentications, [HostsKpiQueries.kpiAuthenticationsEntities]: hostsKpiAuthenticationsEntities, [HostsKpiQueries.kpiHosts]: hostsKpiHosts, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts index cd95a38ec3092..d067dacfc5290 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts @@ -21,6 +21,7 @@ import { authentications, authenticationsEntities } from './authentications'; import { hostsKpiAuthentications, hostsKpiAuthenticationsEntities } from './kpi/authentications'; import { hostsKpiHosts, hostsKpiHostsEntities } from './kpi/hosts'; import { hostsKpiUniqueIps, hostsKpiUniqueIpsEntities } from './kpi/unique_ips'; +import { riskyHosts } from './risky_hosts'; export const hostsFactory: Record< HostsQueries | HostsKpiQueries, @@ -34,6 +35,7 @@ export const hostsFactory: Record< [HostsQueries.uncommonProcesses]: uncommonProcesses, [HostsQueries.authentications]: authentications, [HostsQueries.authenticationsEntities]: authenticationsEntities, + [HostsQueries.riskyHosts]: riskyHosts, [HostsKpiQueries.kpiAuthentications]: hostsKpiAuthentications, [HostsKpiQueries.kpiAuthenticationsEntities]: hostsKpiAuthenticationsEntities, [HostsKpiQueries.kpiHosts]: hostsKpiHosts, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risky_hosts/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risky_hosts/index.ts new file mode 100644 index 0000000000000..0b2fd1c00c3df --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risky_hosts/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SecuritySolutionFactory } from '../../types'; +import { HostsQueries } from '../../../../../../common'; +import { IEsSearchResponse } from '../../../../../../../../../src/plugins/data/common'; +import { inspectStringifyObject } from '../../../../../utils/build_query'; +import { buildRiskyHostsQuery } from './query.risky_hosts.dsl'; +import { + HostsRiskyHostsRequestOptions, + HostsRiskyHostsStrategyResponse, +} from '../../../../../../common/search_strategy/security_solution/hosts/risky_hosts'; + +export const riskyHosts: SecuritySolutionFactory = { + buildDsl: (options: HostsRiskyHostsRequestOptions) => buildRiskyHostsQuery(options), + parse: async ( + options: HostsRiskyHostsRequestOptions, + response: IEsSearchResponse + ): Promise => { + const inspect = { + dsl: [inspectStringifyObject(buildRiskyHostsQuery(options))], + }; + + return { + ...response, + inspect, + }; + }, +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risky_hosts/query.risky_hosts.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risky_hosts/query.risky_hosts.dsl.ts new file mode 100644 index 0000000000000..79b6a91ff403c --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risky_hosts/query.risky_hosts.dsl.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { HostsRiskyHostsRequestOptions } from '../../../../../../common/search_strategy/security_solution/hosts/risky_hosts'; +import { createQueryFilterClauses } from '../../../../../utils/build_query'; + +export const buildRiskyHostsQuery = ({ + filterQuery, + timerange: { from, to }, + defaultIndex, +}: HostsRiskyHostsRequestOptions) => { + const filter = [ + ...createQueryFilterClauses(filterQuery), + { + range: { + '@timestamp': { + gte: from, + lte: to, + format: 'strict_date_optional_time', + }, + }, + }, + ]; + + const dslQuery = { + index: defaultIndex, + allowNoIndices: false, + ignoreUnavailable: true, + track_total_hits: false, + body: { + query: { + bool: { + filter, + }, + }, + }, + }; + + return dslQuery; +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/__mocks__/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/__mocks__/index.ts index 8616a2ef14856..e46c2c20aa1a8 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/__mocks__/index.ts @@ -81,7 +81,7 @@ export const formattedSearchStrategyResponse = { issuers: { terms: { field: 'tls.server.issuer' } }, subjects: { terms: { field: 'tls.server.subject' } }, not_after: { terms: { field: 'tls.server.not_after' } }, - ja3: { terms: { field: 'tls.server.ja3s' } }, + ja3: { terms: { field: 'tls.client.ja3' } }, }, }, }, @@ -136,7 +136,7 @@ export const expectedDsl = { issuers: { terms: { field: 'tls.server.issuer' } }, subjects: { terms: { field: 'tls.server.subject' } }, not_after: { terms: { field: 'tls.server.not_after' } }, - ja3: { terms: { field: 'tls.server.ja3s' } }, + ja3: { terms: { field: 'tls.client.ja3' } }, }, }, }, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/query.tls_network.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/query.tls_network.dsl.ts index be60b33ae2d22..4f724cf9b15f9 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/query.tls_network.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/query.tls_network.dsl.ts @@ -47,7 +47,7 @@ const getAggs = (querySize: number, sort: SortField) => ({ }, ja3: { terms: { - field: 'tls.server.ja3s', + field: 'tls.client.ja3', }, }, }, diff --git a/x-pack/plugins/snapshot_restore/server/index.ts b/x-pack/plugins/snapshot_restore/server/index.ts index d85d03923df1f..e10bffd6073d2 100644 --- a/x-pack/plugins/snapshot_restore/server/index.ts +++ b/x-pack/plugins/snapshot_restore/server/index.ts @@ -12,6 +12,7 @@ import { configSchema, SnapshotRestoreConfig } from './config'; export const plugin = (ctx: PluginInitializerContext) => new SnapshotRestoreServerPlugin(ctx); export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: configSchema, exposeToBrowser: { slm_ui: true, diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 0f9bc43cdf37d..98c81a6f9c677 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -4051,6 +4051,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -4093,6 +4118,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -4135,6 +4185,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -4177,6 +4252,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -4219,6 +4319,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -4261,6 +4386,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -4303,6 +4453,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -4940,6 +5115,31 @@ } } }, + "output_size": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "available": { "type": "boolean" }, @@ -4962,6 +5162,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -5004,6 +5229,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -5046,6 +5296,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -5088,6 +5363,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -5130,6 +5430,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -5172,6 +5497,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -5214,6 +5564,31 @@ "deprecated": { "type": "long" }, + "sizes": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } + }, "app": { "properties": { "search": { @@ -5850,6 +6225,31 @@ } } } + }, + "output_size": { + "properties": { + "1.0": { + "type": "long" + }, + "5.0": { + "type": "long" + }, + "25.0": { + "type": "long" + }, + "50.0": { + "type": "long" + }, + "75.0": { + "type": "long" + }, + "95.0": { + "type": "long" + }, + "99.0": { + "type": "long" + } + } } } } diff --git a/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx b/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx index cc20c856f0e13..644b38d551337 100644 --- a/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx +++ b/x-pack/plugins/timelines/common/types/timeline/columns/index.tsx @@ -8,7 +8,7 @@ import { ReactNode } from 'react'; import { EuiDataGridColumn, EuiDataGridColumnCellActionProps } from '@elastic/eui'; -import { IFieldSubType } from '../../../../../../../src/plugins/data/common'; +import { Filter, IFieldSubType } from '../../../../../../../src/plugins/data/common'; import { BrowserFields } from '../../../search_strategy/index_fields'; import { TimelineNonEcsData } from '../../../search_strategy/timeline'; @@ -45,14 +45,16 @@ export type ColumnId = string; export type TGridCellAction = ({ browserFields, data, - timelineId, + globalFilters, pageSize, + timelineId, }: { browserFields: BrowserFields; /** each row of data is represented as one TimelineNonEcsData[] */ data: TimelineNonEcsData[][]; - timelineId: string; + globalFilters?: Filter[]; pageSize: number; + timelineId: string; }) => (props: EuiDataGridColumnCellActionProps) => ReactNode; /** The specification of a column header */ diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx index 86f42d2f68f78..d67cc746f352f 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx @@ -74,6 +74,7 @@ import type { EuiTheme } from '../../../../../../../src/plugins/kibana_react/com import { ViewSelection } from '../event_rendered_view/selector'; import { EventRenderedView } from '../event_rendered_view'; import { useDataGridHeightHack } from './height_hack'; +import { Filter } from '../../../../../../../src/plugins/data/public'; const StatefulAlertStatusBulkActions = lazy( () => import('../toolbar/bulk_actions/alert_status_bulk_actions') @@ -86,6 +87,7 @@ interface OwnProps { bulkActions?: BulkActionsProp; data: TimelineItem[]; defaultCellActions?: TGridCellAction[]; + filters?: Filter[]; filterQuery: string; filterStatus?: AlertStatus; id: string; @@ -300,15 +302,18 @@ export const BodyComponent = React.memo( data, defaultCellActions, filterQuery, + filters, filterStatus, + hasAlertsCrud, + hasAlertsCrudPermissions, id, indexNames, isEventViewer = false, + isLoading, isSelectAllChecked, itemsPerPageOptions, leadingControlColumns = EMPTY_CONTROL_COLUMNS, loadingEventIds, - isLoading, loadPage, onRuleChange, pageSize, @@ -322,11 +327,9 @@ export const BodyComponent = React.memo( tableView = 'gridView', tabType, totalItems, + totalSelectAllAlerts, trailingControlColumns = EMPTY_CONTROL_COLUMNS, unit = defaultUnit, - hasAlertsCrud, - hasAlertsCrudPermissions, - totalSelectAllAlerts, }) => { const dispatch = useDispatch(); const getManageTimeline = useMemo(() => tGridSelectors.getManageTimelineById(), []); @@ -641,10 +644,11 @@ export const BodyComponent = React.memo( columnHeaders.map((header) => { const buildAction = (tGridCellAction: TGridCellAction) => tGridCellAction({ - data: data.map((row) => row.data), browserFields, - timelineId: id, + data: data.map((row) => row.data), + globalFilters: filters, pageSize, + timelineId: id, }); return { @@ -653,7 +657,7 @@ export const BodyComponent = React.memo( header.tGridCellActions?.map(buildAction) ?? defaultCellActions?.map(buildAction), }; }), - [browserFields, columnHeaders, data, defaultCellActions, id, pageSize] + [browserFields, columnHeaders, data, defaultCellActions, id, pageSize, filters] ); const renderTGridCellValue = useMemo(() => { diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx index fb37bab7668b9..b649dc36abe0a 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx @@ -347,30 +347,31 @@ const TGridIntegratedComponent: React.FC = ({ > diff --git a/x-pack/plugins/timelines/server/index.ts b/x-pack/plugins/timelines/server/index.ts index 8ad2bafdcc13a..229a257d8f549 100644 --- a/x-pack/plugins/timelines/server/index.ts +++ b/x-pack/plugins/timelines/server/index.ts @@ -5,11 +5,12 @@ * 2.0. */ -import { PluginInitializerContext } from '../../../../src/core/server'; +import { PluginInitializerContext, PluginConfigDescriptor } from '../../../../src/core/server'; import { TimelinesPlugin } from './plugin'; -import { ConfigSchema } from './config'; +import { ConfigSchema, ConfigType } from './config'; -export const config = { +export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: ConfigSchema, exposeToBrowser: { enabled: true, diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 423b2d001381c..84e43f1f632a1 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -59,6 +59,9 @@ export const APP_CLUSTER_PRIVILEGES = [ 'cluster:admin/transform/stop', ]; +// Minimum privileges required to return transform node count +export const NODES_INFO_PRIVILEGES = ['cluster:monitor/transform/get']; + // Equivalent of capabilities.canGetTransform export const APP_GET_TRANSFORM_CLUSTER_PRIVILEGES = [ 'cluster.cluster:monitor/transform/get', diff --git a/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts b/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts index c9a0795c32210..29a3c50b2eea9 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts @@ -5,6 +5,9 @@ * 2.0. */ +import Boom from '@hapi/boom'; + +import { NODES_INFO_PRIVILEGES } from '../../../common/constants'; import { isPopulatedObject } from '../../../common/shared_imports'; import { RouteDependencies } from '../../types'; @@ -44,6 +47,22 @@ export function registerTransformNodesRoutes({ router, license }: RouteDependenc }, license.guardApiRoute(async (ctx, req, res) => { try { + // If security is enabled, check that the user has at least permission to + // view transforms before calling the _nodes endpoint with the internal user. + if (license.getStatus().isSecurityEnabled === true) { + const { + body: { has_all_requested: hasAllPrivileges }, + } = await ctx.core.elasticsearch.client.asCurrentUser.security.hasPrivileges({ + body: { + cluster: NODES_INFO_PRIVILEGES, + }, + }); + + if (!hasAllPrivileges) { + return res.customError(wrapError(new Boom.Boom('Forbidden', { statusCode: 403 }))); + } + } + const { body: { nodes }, } = await ctx.core.elasticsearch.client.asInternalUser.nodes.info({ diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f49d2d674330f..34173a0ed6170 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4369,14 +4369,11 @@ "savedObjects.saveModalOrigin.originAfterSavingSwitchLabel": "保存後に{originVerb}から{origin}", "savedObjects.saveModalOrigin.returnToOriginLabel": "戻る", "savedObjects.saveModalOrigin.saveAndReturnLabel": "保存して戻る", - "savedObjectsManagement.breadcrumb.edit": "{savedObjectType}を編集", "savedObjectsManagement.breadcrumb.index": "保存されたオブジェクト", "savedObjectsManagement.deleteConfirm.modalDeleteButtonLabel": "削除", "savedObjectsManagement.deleteConfirm.modalDescription": "このアクションはオブジェクトをKibanaから永久に削除します。", "savedObjectsManagement.deleteConfirm.modalTitle": "「{title}」を削除しますか?", "savedObjectsManagement.deleteSavedObjectsConfirmModalDescription": "この操作は次の保存されたオブジェクトを削除します:", - "savedObjectsManagement.field.offLabel": "オフ", - "savedObjectsManagement.field.onLabel": "オン", "savedObjectsManagement.importSummary.createdCountHeader": "{createdCount}件の新規項目", "savedObjectsManagement.importSummary.createdOutcomeLabel": "作成済み", "savedObjectsManagement.importSummary.errorCountHeader": "{errorCount}件のエラー", @@ -4385,7 +4382,6 @@ "savedObjectsManagement.importSummary.overwrittenOutcomeLabel": "上書き", "savedObjectsManagement.importSummary.warnings.defaultButtonLabel": "Go", "savedObjectsManagement.managementSectionLabel": "保存されたオブジェクト", - "savedObjectsManagement.objects.savedObjectsDescription": "保存された検索、ビジュアライゼーション、ダッシュボードのインポート、エクスポート、管理を行います。", "savedObjectsManagement.objects.savedObjectsTitle": "保存されたオブジェクト", "savedObjectsManagement.objectsTable.deleteConfirmModal.sharedObjectsCallout.content": "共有オブジェクトは属しているすべてのスペースから削除されます。", "savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel": "キャンセル", @@ -4478,21 +4474,10 @@ "savedObjectsManagement.objectsTable.unableFindSavedObjectNotificationMessage": "保存されたオブジェクトが見つかりません", "savedObjectsManagement.objectsTable.unableFindSavedObjectsNotificationMessage": "保存されたオブジェクトが見つかりません", "savedObjectsManagement.objectView.unableFindSavedObjectNotificationMessage": "保存されたオブジェクトが見つかりません", - "savedObjectsManagement.view.cancelButtonAriaLabel": "キャンセル", - "savedObjectsManagement.view.cancelButtonLabel": "キャンセル", - "savedObjectsManagement.view.deleteItemButtonLabel": "{title}を削除", - "savedObjectsManagement.view.editItemTitle": "{title}の編集", "savedObjectsManagement.view.fieldDoesNotExistErrorMessage": "このオブジェクトに関連付けられたフィールドは、現在このインデックスパターンに存在しません。", - "savedObjectsManagement.view.howToFixErrorDescription": "このエラーの原因がわかる場合は修正してください。わからない場合は上の削除ボタンをクリックしてください。", - "savedObjectsManagement.view.howToModifyObjectDescription": "オブジェクトの編集は上級ユーザー向けです。オブジェクトのプロパティが検証されておらず、無効なオブジェクトはエラー、データ損失、またはそれ以上の問題の原因となります。コードを熟知した人に指示されていない限り、この設定は変更しない方が無難です。", - "savedObjectsManagement.view.howToModifyObjectTitle": "十分ご注意ください!", "savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage": "このオブジェクトに関連付けられたインデックスパターンは現在存在しません。", - "savedObjectsManagement.view.saveButtonAriaLabel": "{ title }オブジェクトを保存", - "savedObjectsManagement.view.saveButtonLabel": "{ title }オブジェクトを保存", "savedObjectsManagement.view.savedObjectProblemErrorMessage": "この保存されたオブジェクトに問題があります", "savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage": "このオブジェクトに関連付けられた保存された検索は現在存在しません。", - "savedObjectsManagement.view.viewItemButtonLabel": "{title}を表示", - "savedObjectsManagement.view.viewItemTitle": "{title}を表示", "security.checkup.dismissButtonText": "閉じる", "security.checkup.dontShowAgain": "今後表示しない", "security.checkup.insecureClusterMessage": "1 ビットを失わないでください。Elastic では無料でデータを保護できます。", @@ -5241,9 +5226,7 @@ "visTypeTimeseries.indexPatternSelect.label": "インデックスパターン", "visTypeTimeseries.indexPatternSelect.queryAllIndexesText": "すべてのインデックスにクエリを実行するには * を使用します", "visTypeTimeseries.indexPatternSelect.switchModePopover.areaLabel": "インデックスパターン選択モードを構成", - "visTypeTimeseries.indexPatternSelect.switchModePopover.text": "インデックスパターンは、データ探索で対象とする1つ以上のElasticsearchインデックスを定義します。ElasticsearchインデックスまたはKibanaインデックスパターン(推奨)を使用できます。", "visTypeTimeseries.indexPatternSelect.switchModePopover.title": "インデックスパターン選択モード", - "visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices": "Kibanaインデックスパターンのみを使用", "visTypeTimeseries.kbnVisTypes.metricsDescription": "時系列データの高度な分析を実行します。", "visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB", "visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "バケット:{lastBucketDate}", @@ -5570,7 +5553,6 @@ "visTypeTimeseries.visEditorVisualization.changesWillBeAutomaticallyAppliedMessage": "変更が自動的に適用されます。", "visTypeTimeseries.visEditorVisualization.indexPatternMode.dismissNoticeButtonText": "閉じる", "visTypeTimeseries.visEditorVisualization.indexPatternMode.link": "確認してください。", - "visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationMessage": "お知らせElasticsearchインデックスまたはKibanaインデックスパターンからデータを可視化できるようになりました。{indexPatternModeLink}。", "visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationTitle": "TSVBはインデックスパターンをサポートします", "visTypeTimeseries.visPicker.gaugeLabel": "ゲージ", "visTypeTimeseries.visPicker.metricLabel": "メトリック", @@ -6293,14 +6275,6 @@ "xpack.apm.correlations.correlationsTable.filterLabel": "フィルター", "xpack.apm.correlations.correlationsTable.loadingText": "読み込み中", "xpack.apm.correlations.correlationsTable.noDataText": "データなし", - "xpack.apm.correlations.customize.buttonLabel": "フィールドのカスタマイズ", - "xpack.apm.correlations.customize.fieldHelpText": "相関関係を分析するフィールドをカスタマイズまたは{reset}します。{docsLink}", - "xpack.apm.correlations.customize.fieldHelpTextDocsLink": "デフォルトフィールドの詳細。", - "xpack.apm.correlations.customize.fieldHelpTextReset": "リセット", - "xpack.apm.correlations.customize.fieldLabel": "フィールド", - "xpack.apm.correlations.customize.fieldPlaceholder": "オプションを選択または作成", - "xpack.apm.correlations.customize.thresholdLabel": "しきい値", - "xpack.apm.correlations.customize.thresholdPercentile": "{percentile}パーセンタイル", "xpack.apm.correlations.failedTransactions.correlationsTable.fieldNameLabel": "フィールド名", "xpack.apm.correlations.failedTransactions.correlationsTable.fieldValueLabel": "フィールド値", "xpack.apm.correlations.failedTransactions.correlationsTable.impactLabel": "インパクト", @@ -6854,7 +6828,6 @@ "xpack.apm.settings.unsupportedConfigs.errorToast.title": "APMサーバー設定を取り込めません", "xpack.apm.settingsLinkLabel": "設定", "xpack.apm.setupInstructionsButtonLabel": "セットアップの手順", - "xpack.apm.significanTerms.license.text": "相関関係APIを使用するには、Elastic Platinumライセンスのサブスクリプションが必要です。", "xpack.apm.stacktraceTab.causedByFramesToogleButtonLabel": "作成元", "xpack.apm.stacktraceTab.localVariablesToogleButtonLabel": "ローカル変数", "xpack.apm.stacktraceTab.noStacktraceAvailableLabel": "利用可能なスタックトレースがありません。", @@ -10243,7 +10216,6 @@ "xpack.enterpriseSearch.workplaceSearch.sources.additionalConfig.heading": "追加の構成が必要", "xpack.enterpriseSearch.workplaceSearch.sources.applicationLinkTitles.github": "GitHub開発者ポータル", "xpack.enterpriseSearch.workplaceSearch.sources.baseUrlTitles.github": "GitHub Enterprise URL", - "xpack.enterpriseSearch.workplaceSearch.sources.config.description": "変更するコンテンツソースコネクター設定を編集します。", "xpack.enterpriseSearch.workplaceSearch.sources.config.link": "コンテンツソースコネクター設定を編集", "xpack.enterpriseSearch.workplaceSearch.sources.config.title": "コンテンツソース構成", "xpack.enterpriseSearch.workplaceSearch.sources.configuration.title": "構成", @@ -10839,7 +10811,6 @@ "xpack.fleet.epm.updateAvailableTooltip": "更新が利用可能です", "xpack.fleet.epm.usedByLabel": "エージェントポリシー", "xpack.fleet.epm.versionLabel": "バージョン", - "xpack.fleet.epmList.allFilterLinkText": "すべて", "xpack.fleet.epmList.allPackagesFilterLinkText": "すべて", "xpack.fleet.epmList.allTitle": "カテゴリで参照", "xpack.fleet.epmList.installedTitle": "インストールされている統合", @@ -12426,7 +12397,6 @@ "xpack.indexLifecycleMgmt.editPolicy.dataTierAllocation.nodeAllocationFieldLabel": "ノード属性を選択", "xpack.indexLifecycleMgmt.editPolicy.dataTierHotLabel": "ホット", "xpack.indexLifecycleMgmt.editPolicy.dataTierWarmLabel": "ウォーム", - "xpack.indexLifecycleMgmt.editPolicy.daysOptionLabel": "日", "xpack.indexLifecycleMgmt.editPolicy.defaultToDataNodesDescription": "データを特定のデータノードに割り当てるには、{roleBasedGuidance}か、elasticsearch.ymlでカスタムノード属性を構成します。", "xpack.indexLifecycleMgmt.editPolicy.defaultToDataNodesDescription.migrationGuidanceMessage": "ユーザーロールに基づく割り当て", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.activateWarmPhaseSwitchLabel": "削除フェーズを有効にする", @@ -12481,7 +12451,6 @@ "xpack.indexLifecycleMgmt.editPolicy.hotPhase.learnAboutRolloverLinkText": "詳細", "xpack.indexLifecycleMgmt.editPolicy.hotPhase.rolloverDefaultsTipContent": "インデックスが30日経過するか、50 GBに達したときにロールオーバーします。", "xpack.indexLifecycleMgmt.editPolicy.hotPhase.rolloverDescriptionMessage": "現在のインデックスが特定のサイズ、ドキュメント数、または年齢に達したときに、新しいインデックスへの書き込みを開始します。時系列データを操作するときに、パフォーマンスを最適化し、リソースの使用状況を管理できます。", - "xpack.indexLifecycleMgmt.editPolicy.hoursOptionLabel": "時間", "xpack.indexLifecycleMgmt.editPolicy.indexPriority.indexPriorityEnabledFieldLabel": "インデックスの優先度を設定", "xpack.indexLifecycleMgmt.editPolicy.indexPriorityLabel": "インデックスの優先順位", "xpack.indexLifecycleMgmt.editPolicy.indexPriorityText": "インデックスの優先順位", @@ -12492,16 +12461,12 @@ "xpack.indexLifecycleMgmt.editPolicy.lifecyclePoliciesReloadButton": "再試行", "xpack.indexLifecycleMgmt.editPolicy.loadSnapshotRepositoriesErrorBody": "このフィールドを更新し、既存のスナップショットリポジトリの名前を入力します。", "xpack.indexLifecycleMgmt.editPolicy.loadSnapshotRepositoriesErrorTitle": "スナップショットリポジトリを読み込めません", - "xpack.indexLifecycleMgmt.editPolicy.microSecondsOptionLabel": "マイクロ秒", - "xpack.indexLifecycleMgmt.editPolicy.milliSecondsOptionLabel": "ミリ秒", "xpack.indexLifecycleMgmt.editPolicy.minAgeSmallerThanColdPhaseError": "コールドフェーズ値({value})以上でなければなりません", "xpack.indexLifecycleMgmt.editPolicy.minAgeSmallerThanFrozenPhaseError": "フローズンフェーズ値({value})以上でなければなりません", "xpack.indexLifecycleMgmt.editPolicy.minAgeSmallerThanWarmPhaseError": "ウォームフェーズ値({value})以上でなければなりません", "xpack.indexLifecycleMgmt.editPolicy.minimumAge.minimumAgeFieldLabel": "次のときに、データをフェーズに移動します。", "xpack.indexLifecycleMgmt.editPolicy.minimumAge.minimumAgeFieldSuffixLabel": "古", "xpack.indexLifecycleMgmt.editPolicy.minimumAge.rolloverToolTipDescription": "データの年齢はロールオーバーから計算されます。ロールオーバーはホットフェーズで構成されます。", - "xpack.indexLifecycleMgmt.editPolicy.minutesOptionLabel": "分", - "xpack.indexLifecycleMgmt.editPolicy.nanoSecondsOptionLabel": "ナノ秒", "xpack.indexLifecycleMgmt.editPolicy.noCustomAttributesTitle": "カスタム属性が定義されていません", "xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.allocateToDataNodesOption": "任意のデータノード", "xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.customOption.description": "ノード属性を使用して、シャード割り当てを制御します。{learnMoreLink}。", @@ -12553,7 +12518,6 @@ "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotRepoFieldLabel": "スナップショットリポジトリ", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotRepoRequiredError": "スナップショットリポジトリ名が必要です。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotStorageFieldLabel": "検索可能スナップショットストレージ", - "xpack.indexLifecycleMgmt.editPolicy.secondsOptionLabel": "秒", "xpack.indexLifecycleMgmt.editPolicy.showPolicyJsonButton": "リクエストを表示", "xpack.indexLifecycleMgmt.editPolicy.shrinkIndexExplanationText": "インデックス情報をプライマリシャードの少ない新規インデックスに縮小します。", "xpack.indexLifecycleMgmt.editPolicy.shrinkText": "縮小", @@ -12572,30 +12536,16 @@ "xpack.indexLifecycleMgmt.forcemerge.enableLabel": "データを強制結合", "xpack.indexLifecycleMgmt.forceMerge.numberOfSegmentsLabel": "セグメントの数", "xpack.indexLifecycleMgmt.frozePhase.freezeIndexLabel": "インデックスを凍結", - "xpack.indexLifecycleMgmt.hotPhase.bytesLabel": "バイト", - "xpack.indexLifecycleMgmt.hotPhase.daysLabel": "日", "xpack.indexLifecycleMgmt.hotPhase.enableRolloverLabel": "ロールオーバーを有効にする", - "xpack.indexLifecycleMgmt.hotPhase.gigabytesLabel": "ギガバイト", - "xpack.indexLifecycleMgmt.hotPhase.hoursLabel": "時間", "xpack.indexLifecycleMgmt.hotPhase.isUsingDefaultRollover": "推奨のデフォルト値を使用", - "xpack.indexLifecycleMgmt.hotPhase.kilobytesLabel": "キロバイト", "xpack.indexLifecycleMgmt.hotPhase.maximumAgeLabel": "最高年齢", "xpack.indexLifecycleMgmt.hotPhase.maximumAgeUnitsAriaLabel": "最高年齢の単位", "xpack.indexLifecycleMgmt.hotPhase.maximumDocumentsLabel": "最高ドキュメント数", "xpack.indexLifecycleMgmt.hotPhase.maximumIndexSizeDeprecationMessage": "最大インデックスサイズは廃止予定であり、将来のバージョンでは削除されます。代わりに最大プライマリシャードサイズを使用してください。", "xpack.indexLifecycleMgmt.hotPhase.maximumIndexSizeLabel": "最大インデックスサイズ", "xpack.indexLifecycleMgmt.hotPhase.maximumIndexSizeUnitsAriaLabel": "最大インデックスサイズの単位", - "xpack.indexLifecycleMgmt.hotPhase.maximumPrimaryShardSizeAriaLabel": "最大プライマリシャードサイズ単位", "xpack.indexLifecycleMgmt.hotPhase.maximumPrimaryShardSizeLabel": "最大プライマリシャードサイズ", - "xpack.indexLifecycleMgmt.hotPhase.megabytesLabel": "メガバイト", - "xpack.indexLifecycleMgmt.hotPhase.microsecondsLabel": "マイクロ秒", - "xpack.indexLifecycleMgmt.hotPhase.millisecondsLabel": "ミリ秒", - "xpack.indexLifecycleMgmt.hotPhase.minutesLabel": "分", - "xpack.indexLifecycleMgmt.hotPhase.nanosecondsLabel": "ナノ秒", - "xpack.indexLifecycleMgmt.hotPhase.petabytesLabel": "ペタバイト", "xpack.indexLifecycleMgmt.hotPhase.rolloverFieldTitle": "ロールオーバー", - "xpack.indexLifecycleMgmt.hotPhase.secondsLabel": "秒", - "xpack.indexLifecycleMgmt.hotPhase.terabytesLabel": "テラバイト", "xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.actionStatusTitle": "アクションステータス", "xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentActionHeader": "現在のステータス", "xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentActionTimeHeader": "現在のアクション時間", @@ -12698,7 +12648,6 @@ "xpack.indexLifecycleMgmt.searchableSnapshot.disallowedCalloutBody": "このフェーズで検索可能なスナップショットを使用するには、ホットフェーズで検索可能なスナップショットを無効にする必要があります。", "xpack.indexLifecycleMgmt.searchableSnapshot.disallowedCalloutTitle": "検索可能スナップショットが無効です", "xpack.indexLifecycleMgmt.searchSnapshotlicenseCheckErrorMessage": "検索可能なスナップショットを使用するには、1 つ以上のエンタープライズレベルのライセンスが必要です。", - "xpack.indexLifecycleMgmt.shrink.indexFieldLabel": "インデックスを縮小", "xpack.indexLifecycleMgmt.shrink.numberOfPrimaryShardsLabel": "プライマリシャードの数", "xpack.indexLifecycleMgmt.templateNotFoundMessage": "テンプレート{name}が見つかりません。", "xpack.indexLifecycleMgmt.timeline.coldPhaseSectionTitle": "コールドフェーズ", @@ -17476,7 +17425,6 @@ "xpack.monitoring.alerts.kibanaVersionMismatch.label": "Kibana バージョン不一致", "xpack.monitoring.alerts.kibanaVersionMismatch.shortAction": "すべてのインスタンスのバージョンが同じことを確認してください。", "xpack.monitoring.alerts.kibanaVersionMismatch.ui.firingMessage": "このクラスターでは、複数のバージョンの Kibana({versions})が実行されています。", - "xpack.monitoring.alerts.legacyAlert.expressionText": "構成するものがありません。", "xpack.monitoring.alerts.licenseExpiration.action": "ライセンスを更新してください。", "xpack.monitoring.alerts.licenseExpiration.actionVariables.clusterName": "ライセンスが属しているクラスター。", "xpack.monitoring.alerts.licenseExpiration.actionVariables.expiredDate": "ライセンスの有効期限。", @@ -22897,7 +22845,6 @@ "xpack.securitySolution.overview.ctiDashboardWarningPanelBody": "選択した時間範囲からデータが検出されませんでした。別の時間範囲の検索を試してください。", "xpack.securitySolution.overview.ctiDashboardWarningPanelTitle": "表示する脅威インテリジェンスデータがありません", "xpack.securitySolution.overview.ctiViewDasboard": "ダッシュボードを表示", - "xpack.securitySolution.overview.ctiViewSourceDasboard": "ソースダッシュボードを表示", "xpack.securitySolution.overview.endgameDnsTitle": "DNS", "xpack.securitySolution.overview.endgameFileTitle": "ファイル", "xpack.securitySolution.overview.endgameImageLoadTitle": "画像読み込み", @@ -22968,7 +22915,6 @@ "xpack.securitySolution.paginatedTable.tooManyResultsToastText": "クエリ範囲を縮めて結果をさらにフィルタリングしてください", "xpack.securitySolution.paginatedTable.tooManyResultsToastTitle": " - 結果が多すぎます", "xpack.securitySolution.policiesTab": "ポリシー", - "xpack.securitySolution.policySelect.policySpecificSectionTitle": "特定のエンドポイントポリシーに適用", "xpack.securitySolution.policyStatusText.failure": "失敗", "xpack.securitySolution.policyStatusText.success": "成功", "xpack.securitySolution.policyStatusText.unsupported": "サポートされていない", @@ -23379,8 +23325,6 @@ "xpack.securitySolution.trustedapps.logicalConditionBuilder.group.andOperator": "AND", "xpack.securitySolution.trustedapps.logicalConditionBuilder.noEntries": "条件が定義されていません", "xpack.securitySolution.trustedapps.middleware.editIdMissing": "IDが指定されていません", - "xpack.securitySolution.trustedapps.policySelect.globalSectionTitle": "割り当て", - "xpack.securitySolution.trustedapps.policySelect.globalSwitchTitle": "信頼できるアプリケーションをグローバルに適用", "xpack.securitySolution.trustedapps.trustedapp.entry.field": "フィールド", "xpack.securitySolution.trustedapps.trustedapp.entry.operator": "演算子", "xpack.securitySolution.trustedapps.trustedapp.entry.value": "値", @@ -26137,13 +26081,7 @@ "xpack.uptime.createPackagePolicy.stepConfigure.tlsSettings.label": "TLS設定", "xpack.uptime.durationChart.emptyPrompt.description": "このモニターは選択された時間範囲で一度も{emphasizedText}していません。", "xpack.uptime.durationChart.emptyPrompt.title": "利用可能な期間データがありません", - "xpack.uptime.emptyState.configureHeartbeatIndexSettings": "Heartbeatがすでに設定されている場合は、データがElasticsearchに送信されていることを確認してから、Heartbeat構成に合わせてインデックスパターン設定を更新します。", - "xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage": "サービスの監視を開始するには、Heartbeatを設定します。", "xpack.uptime.emptyState.loadingMessage": "読み込み中…", - "xpack.uptime.emptyState.noDataMessage": "インデックス{indexName}にはアップタイムデータが見つかりません", - "xpack.uptime.emptyState.noIndexTitle": "パターン{indexName}のインデックスが見つかりません", - "xpack.uptime.emptyState.updateIndexPattern": "インデックスパターン設定を更新", - "xpack.uptime.emptyState.viewSetupInstructions": "セットアップの手順を表示", "xpack.uptime.emptyStateError.notAuthorized": "アップタイムデータの表示が承認されていません。システム管理者にお問い合わせください。", "xpack.uptime.emptyStateError.notFoundPage": "ページが見つかりません", "xpack.uptime.emptyStateError.title": "エラー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 85e11905e5eb7..01e3f65361407 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4409,14 +4409,11 @@ "savedObjects.saveModalOrigin.originAfterSavingSwitchLabel": "保存后{originVerb}至{origin}", "savedObjects.saveModalOrigin.returnToOriginLabel": "返回", "savedObjects.saveModalOrigin.saveAndReturnLabel": "保存并返回", - "savedObjectsManagement.breadcrumb.edit": "编辑 {savedObjectType}", "savedObjectsManagement.breadcrumb.index": "已保存对象", "savedObjectsManagement.deleteConfirm.modalDeleteButtonLabel": "删除", "savedObjectsManagement.deleteConfirm.modalDescription": "此操作会将对象从 Kibana 永久移除。", "savedObjectsManagement.deleteConfirm.modalTitle": "删除“{title}”?", "savedObjectsManagement.deleteSavedObjectsConfirmModalDescription": "此操作将删除以下已保存对象:", - "savedObjectsManagement.field.offLabel": "关闭", - "savedObjectsManagement.field.onLabel": "开启", "savedObjectsManagement.importSummary.createdCountHeader": "{createdCount} 个新", "savedObjectsManagement.importSummary.createdOutcomeLabel": "已创建", "savedObjectsManagement.importSummary.errorCountHeader": "{errorCount} 个错误", @@ -4426,7 +4423,6 @@ "savedObjectsManagement.importSummary.overwrittenOutcomeLabel": "已覆盖", "savedObjectsManagement.importSummary.warnings.defaultButtonLabel": "执行", "savedObjectsManagement.managementSectionLabel": "已保存对象", - "savedObjectsManagement.objects.savedObjectsDescription": "导入、导出和管理您的已保存搜索、可视化和仪表板。", "savedObjectsManagement.objects.savedObjectsTitle": "已保存对象", "savedObjectsManagement.objectsTable.deleteConfirmModal.sharedObjectsCallout.content": "共享对象已从其所在的各个工作区中移除。", "savedObjectsManagement.objectsTable.deleteConfirmModal.sharedObjectsCallout.title": "{sharedObjectsCount, plural, one {# 个已保存对象已共享} other {您的已保存对象有 # 个已共享}}", @@ -4523,21 +4519,10 @@ "savedObjectsManagement.objectsTable.unableFindSavedObjectNotificationMessage": "找不到已保存对象", "savedObjectsManagement.objectsTable.unableFindSavedObjectsNotificationMessage": "找不到已保存对象", "savedObjectsManagement.objectView.unableFindSavedObjectNotificationMessage": "找不到已保存对象", - "savedObjectsManagement.view.cancelButtonAriaLabel": "取消", - "savedObjectsManagement.view.cancelButtonLabel": "取消", - "savedObjectsManagement.view.deleteItemButtonLabel": "删除“{title}”", - "savedObjectsManagement.view.editItemTitle": "编辑“{title}”", "savedObjectsManagement.view.fieldDoesNotExistErrorMessage": "与此对象关联的字段在该索引模式中已不存在。", - "savedObjectsManagement.view.howToFixErrorDescription": "如果您清楚此错误的含义,请修复该错误 — 否则单击上面的删除按钮。", - "savedObjectsManagement.view.howToModifyObjectDescription": "修改对象仅适用于高级用户。对象属性未得到验证,无效的对象可能会导致错误、数据丢失或更坏的情况发生。除非熟悉该代码的人让您来这里,否则您可能不应到访此处。", - "savedObjectsManagement.view.howToModifyObjectTitle": "谨慎操作!", "savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage": "与此对象关联的索引模式已不存在。", - "savedObjectsManagement.view.saveButtonAriaLabel": "保存 { title } 对象", - "savedObjectsManagement.view.saveButtonLabel": "保存 { title } 对象", "savedObjectsManagement.view.savedObjectProblemErrorMessage": "此已保存对象有问题", "savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage": "与此对象关联的已保存搜索已不存在。", - "savedObjectsManagement.view.viewItemButtonLabel": "查看“{title}”", - "savedObjectsManagement.view.viewItemTitle": "查看“{title}”", "security.checkup.dismissButtonText": "关闭", "security.checkup.dontShowAgain": "不再显示", "security.checkup.insecureClusterMessage": "不要丢失一位。使用 Elastic,免费保护您的数据。", @@ -5286,9 +5271,7 @@ "visTypeTimeseries.indexPatternSelect.label": "索引模式", "visTypeTimeseries.indexPatternSelect.queryAllIndexesText": "要查询所有索引,请使用 *", "visTypeTimeseries.indexPatternSelect.switchModePopover.areaLabel": "配置索引模式选择模式", - "visTypeTimeseries.indexPatternSelect.switchModePopover.text": "索引模式可识别一个或多个您希望浏览的 Elasticsearch 索引。可用使用 Elasticsearch 索引或 Kibana 索引模式(推荐)。", "visTypeTimeseries.indexPatternSelect.switchModePopover.title": "索引模式选择模式", - "visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices": "仅使用 Kibana 索引模式", "visTypeTimeseries.kbnVisTypes.metricsDescription": "对时间序列数据执行高级分析。", "visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB", "visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "存储桶:{lastBucketDate}", @@ -5616,7 +5599,6 @@ "visTypeTimeseries.visEditorVisualization.changesWillBeAutomaticallyAppliedMessage": "将自动应用更改。", "visTypeTimeseries.visEditorVisualization.indexPatternMode.dismissNoticeButtonText": "关闭", "visTypeTimeseries.visEditorVisualization.indexPatternMode.link": "请查看。", - "visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationMessage": "好消息!现在可以可视化 Elasticsearch 索引或 Kibana 索引模式的数据。{indexPatternModeLink}。", "visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationTitle": "TSVB 现在支持索引模式", "visTypeTimeseries.visPicker.gaugeLabel": "仪表盘", "visTypeTimeseries.visPicker.metricLabel": "指标", @@ -6343,14 +6325,6 @@ "xpack.apm.correlations.correlationsTable.filterLabel": "筛选", "xpack.apm.correlations.correlationsTable.loadingText": "正在加载", "xpack.apm.correlations.correlationsTable.noDataText": "无数据", - "xpack.apm.correlations.customize.buttonLabel": "定制字段", - "xpack.apm.correlations.customize.fieldHelpText": "定制或{reset}要针对相关性分析的字段。{docsLink}", - "xpack.apm.correlations.customize.fieldHelpTextDocsLink": "详细了解默认字段。", - "xpack.apm.correlations.customize.fieldHelpTextReset": "重置", - "xpack.apm.correlations.customize.fieldLabel": "字段", - "xpack.apm.correlations.customize.fieldPlaceholder": "选择或创建选项", - "xpack.apm.correlations.customize.thresholdLabel": "阈值", - "xpack.apm.correlations.customize.thresholdPercentile": "第 {percentile} 个百分位数", "xpack.apm.correlations.failedTransactions.correlationsTable.fieldNameLabel": "字段名称", "xpack.apm.correlations.failedTransactions.correlationsTable.fieldValueLabel": "字段值", "xpack.apm.correlations.failedTransactions.correlationsTable.impactLabel": "影响", @@ -6909,7 +6883,6 @@ "xpack.apm.settings.unsupportedConfigs.errorToast.title": "无法获取 APM Server 设置", "xpack.apm.settingsLinkLabel": "设置", "xpack.apm.setupInstructionsButtonLabel": "设置说明", - "xpack.apm.significanTerms.license.text": "要使用相关性 API,必须订阅 Elastic 白金级许可证。", "xpack.apm.stacktraceTab.causedByFramesToogleButtonLabel": "原因", "xpack.apm.stacktraceTab.libraryFramesToogleButtonLabel": "{count, plural, other {# 个库帧}}", "xpack.apm.stacktraceTab.localVariablesToogleButtonLabel": "本地变量", @@ -10344,7 +10317,6 @@ "xpack.enterpriseSearch.workplaceSearch.sources.additionalConfig.heading": "需要其他配置", "xpack.enterpriseSearch.workplaceSearch.sources.applicationLinkTitles.github": "GitHub 开发者门户", "xpack.enterpriseSearch.workplaceSearch.sources.baseUrlTitles.github": "GitHub Enterprise URL", - "xpack.enterpriseSearch.workplaceSearch.sources.config.description": "编辑要更改的内容源连接器设置。", "xpack.enterpriseSearch.workplaceSearch.sources.config.link": "编辑内容源连接器设置", "xpack.enterpriseSearch.workplaceSearch.sources.config.title": "内容源配置", "xpack.enterpriseSearch.workplaceSearch.sources.configuration.title": "配置", @@ -10953,7 +10925,6 @@ "xpack.fleet.epm.updateAvailableTooltip": "有可用更新", "xpack.fleet.epm.usedByLabel": "代理策略", "xpack.fleet.epm.versionLabel": "版本", - "xpack.fleet.epmList.allFilterLinkText": "全部", "xpack.fleet.epmList.allPackagesFilterLinkText": "全部", "xpack.fleet.epmList.allTitle": "按类别浏览", "xpack.fleet.epmList.installedTitle": "已安装集成", @@ -12590,7 +12561,6 @@ "xpack.indexLifecycleMgmt.editPolicy.dataTierAllocation.nodeAllocationFieldLabel": "选择节点属性", "xpack.indexLifecycleMgmt.editPolicy.dataTierHotLabel": "热", "xpack.indexLifecycleMgmt.editPolicy.dataTierWarmLabel": "温", - "xpack.indexLifecycleMgmt.editPolicy.daysOptionLabel": "天", "xpack.indexLifecycleMgmt.editPolicy.defaultToDataNodesDescription": "要将数据分配给特定数据节点,请{roleBasedGuidance}或在 elasticsearch.yml 中配置定制节点属性。", "xpack.indexLifecycleMgmt.editPolicy.defaultToDataNodesDescription.migrationGuidanceMessage": "使用基于角色的分配", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.activateWarmPhaseSwitchLabel": "激活删除阶段", @@ -12646,7 +12616,6 @@ "xpack.indexLifecycleMgmt.editPolicy.hotPhase.learnAboutRolloverLinkText": "了解详情", "xpack.indexLifecycleMgmt.editPolicy.hotPhase.rolloverDefaultsTipContent": "当索引已存在 30 天或任何主分片达到 50 GB 时滚动更新。", "xpack.indexLifecycleMgmt.editPolicy.hotPhase.rolloverDescriptionMessage": "在当前索引达到特定大小、文档计数或存在时间时,开始写入到新索引。允许您在使用时间序列数据时优化性能并管理资源使用。", - "xpack.indexLifecycleMgmt.editPolicy.hoursOptionLabel": "小时", "xpack.indexLifecycleMgmt.editPolicy.indexPriority.indexPriorityEnabledFieldLabel": "设置索引优先级", "xpack.indexLifecycleMgmt.editPolicy.indexPriorityLabel": "索引优先级", "xpack.indexLifecycleMgmt.editPolicy.indexPriorityText": "索引优先级", @@ -12659,16 +12628,12 @@ "xpack.indexLifecycleMgmt.editPolicy.linkedIndices": "{indicesCount, plural, other {# 个已链接索引}}", "xpack.indexLifecycleMgmt.editPolicy.loadSnapshotRepositoriesErrorBody": "刷新此字段并输入现有快照储存库的名称。", "xpack.indexLifecycleMgmt.editPolicy.loadSnapshotRepositoriesErrorTitle": "无法加载快照存储库", - "xpack.indexLifecycleMgmt.editPolicy.microSecondsOptionLabel": "微秒", - "xpack.indexLifecycleMgmt.editPolicy.milliSecondsOptionLabel": "毫秒", "xpack.indexLifecycleMgmt.editPolicy.minAgeSmallerThanColdPhaseError": "必须大于或等于冷阶段值 ({value})", "xpack.indexLifecycleMgmt.editPolicy.minAgeSmallerThanFrozenPhaseError": "必须大于或等于冻结阶段值 ({value})", "xpack.indexLifecycleMgmt.editPolicy.minAgeSmallerThanWarmPhaseError": "必须大于或等于温阶段值 ({value})", "xpack.indexLifecycleMgmt.editPolicy.minimumAge.minimumAgeFieldLabel": "在以下情况下将数据移到相应阶段:", "xpack.indexLifecycleMgmt.editPolicy.minimumAge.minimumAgeFieldSuffixLabel": "以前", "xpack.indexLifecycleMgmt.editPolicy.minimumAge.rolloverToolTipDescription": "数据存在时间计算自滚动更新。滚动更新配置于热阶段。", - "xpack.indexLifecycleMgmt.editPolicy.minutesOptionLabel": "分钟", - "xpack.indexLifecycleMgmt.editPolicy.nanoSecondsOptionLabel": "纳秒", "xpack.indexLifecycleMgmt.editPolicy.noCustomAttributesTitle": "未定义定制属性", "xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.allocateToDataNodesOption": "任何数据节点", "xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.customOption.description": "使用节点属性控制分片分配。{learnMoreLink}。", @@ -12720,7 +12685,6 @@ "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotRepoFieldLabel": "快照存储库", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotRepoRequiredError": "快照存储库名称必填。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotStorageFieldLabel": "可搜索快照存储", - "xpack.indexLifecycleMgmt.editPolicy.secondsOptionLabel": "秒", "xpack.indexLifecycleMgmt.editPolicy.showPolicyJsonButton": "显示请求", "xpack.indexLifecycleMgmt.editPolicy.shrinkIndexExplanationText": "将索引缩小成具有较少主分片的新索引。", "xpack.indexLifecycleMgmt.editPolicy.shrinkText": "缩小", @@ -12739,30 +12703,16 @@ "xpack.indexLifecycleMgmt.forcemerge.enableLabel": "强制合并数据", "xpack.indexLifecycleMgmt.forceMerge.numberOfSegmentsLabel": "分段数目", "xpack.indexLifecycleMgmt.frozePhase.freezeIndexLabel": "冻结索引", - "xpack.indexLifecycleMgmt.hotPhase.bytesLabel": "字节", - "xpack.indexLifecycleMgmt.hotPhase.daysLabel": "天", "xpack.indexLifecycleMgmt.hotPhase.enableRolloverLabel": "启用滚动更新", - "xpack.indexLifecycleMgmt.hotPhase.gigabytesLabel": "千兆字节", - "xpack.indexLifecycleMgmt.hotPhase.hoursLabel": "小时", "xpack.indexLifecycleMgmt.hotPhase.isUsingDefaultRollover": "使用建议的默认值", - "xpack.indexLifecycleMgmt.hotPhase.kilobytesLabel": "千字节", "xpack.indexLifecycleMgmt.hotPhase.maximumAgeLabel": "最大存在时间", "xpack.indexLifecycleMgmt.hotPhase.maximumAgeUnitsAriaLabel": "最大存在时间单位", "xpack.indexLifecycleMgmt.hotPhase.maximumDocumentsLabel": "最大文档数", "xpack.indexLifecycleMgmt.hotPhase.maximumIndexSizeDeprecationMessage": "最大索引大小已弃用,将在未来版本中移除。改用最大主分片大小。", "xpack.indexLifecycleMgmt.hotPhase.maximumIndexSizeLabel": "最大索引大小", "xpack.indexLifecycleMgmt.hotPhase.maximumIndexSizeUnitsAriaLabel": "最大索引大小单位", - "xpack.indexLifecycleMgmt.hotPhase.maximumPrimaryShardSizeAriaLabel": "最大主分片大小单位", "xpack.indexLifecycleMgmt.hotPhase.maximumPrimaryShardSizeLabel": "最大主分片大小", - "xpack.indexLifecycleMgmt.hotPhase.megabytesLabel": "兆字节", - "xpack.indexLifecycleMgmt.hotPhase.microsecondsLabel": "微秒", - "xpack.indexLifecycleMgmt.hotPhase.millisecondsLabel": "毫秒", - "xpack.indexLifecycleMgmt.hotPhase.minutesLabel": "分钟", - "xpack.indexLifecycleMgmt.hotPhase.nanosecondsLabel": "纳秒", - "xpack.indexLifecycleMgmt.hotPhase.petabytesLabel": "万兆字节", "xpack.indexLifecycleMgmt.hotPhase.rolloverFieldTitle": "滚动更新", - "xpack.indexLifecycleMgmt.hotPhase.secondsLabel": "秒", - "xpack.indexLifecycleMgmt.hotPhase.terabytesLabel": "兆兆字节", "xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.actionStatusTitle": "操作状态", "xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentActionHeader": "当前操作", "xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentActionTimeHeader": "当前操作名称", @@ -12869,7 +12819,6 @@ "xpack.indexLifecycleMgmt.searchableSnapshot.disallowedCalloutBody": "要在此阶段使用可搜索快照,必须在热阶段禁用可搜索快照。", "xpack.indexLifecycleMgmt.searchableSnapshot.disallowedCalloutTitle": "可搜索快照已禁用", "xpack.indexLifecycleMgmt.searchSnapshotlicenseCheckErrorMessage": "要使用可搜索快照,至少需要企业级许可证。", - "xpack.indexLifecycleMgmt.shrink.indexFieldLabel": "缩小索引", "xpack.indexLifecycleMgmt.shrink.numberOfPrimaryShardsLabel": "主分片数目", "xpack.indexLifecycleMgmt.templateNotFoundMessage": "找不到模板 {name}。", "xpack.indexLifecycleMgmt.timeline.coldPhaseSectionTitle": "冷阶段", @@ -17750,7 +17699,6 @@ "xpack.monitoring.alerts.kibanaVersionMismatch.label": "Kibana 版本不匹配", "xpack.monitoring.alerts.kibanaVersionMismatch.shortAction": "确认所有实例具有相同的版本。", "xpack.monitoring.alerts.kibanaVersionMismatch.ui.firingMessage": "在此集群中正运行着多个 Kibana 版本 ({versions})。", - "xpack.monitoring.alerts.legacyAlert.expressionText": "没有可配置的内容。", "xpack.monitoring.alerts.licenseExpiration.action": "请更新您的许可证。", "xpack.monitoring.alerts.licenseExpiration.actionVariables.clusterName": "许可证所属的集群。", "xpack.monitoring.alerts.licenseExpiration.actionVariables.expiredDate": "许可证过期日期。", @@ -23266,12 +23214,11 @@ "xpack.securitySolution.overview.ctiDashboardInfoPanelBody": "按照此指南启用您的仪表板,以便可以在可视化中查看您的源。", "xpack.securitySolution.overview.ctiDashboardInfoPanelButton": "如何加载 Kibana 仪表板", "xpack.securitySolution.overview.ctiDashboardInfoPanelTitle": "启用 Kibana 仪表板以查看源", - "xpack.securitySolution.overview.ctiDashboardSubtitle": "正在显示:{totalEventCount} 个{totalEventCount, plural, other {指标}}", + "xpack.securitySolution.overview.ctiDashboardSubtitle": "正在显示:{totalCount} 个{totalCount, plural, other {指标}}", "xpack.securitySolution.overview.ctiDashboardTitle": "威胁情报", "xpack.securitySolution.overview.ctiDashboardWarningPanelBody": "我们尚未从选定时间范围检测到任何数据,请尝试搜索其他时间范围。", "xpack.securitySolution.overview.ctiDashboardWarningPanelTitle": "没有可显示的威胁情报数据", "xpack.securitySolution.overview.ctiViewDasboard": "查看仪表板", - "xpack.securitySolution.overview.ctiViewSourceDasboard": "查看源仪表板", "xpack.securitySolution.overview.endgameDnsTitle": "DNS", "xpack.securitySolution.overview.endgameFileTitle": "文件", "xpack.securitySolution.overview.endgameImageLoadTitle": "映像加载", @@ -23346,7 +23293,6 @@ "xpack.securitySolution.paginatedTable.tooManyResultsToastText": "缩减您的查询范围,以更好地筛选结果", "xpack.securitySolution.paginatedTable.tooManyResultsToastTitle": " - 结果过多", "xpack.securitySolution.policiesTab": "策略", - "xpack.securitySolution.policySelect.policySpecificSectionTitle": "应用到特定终端策略", "xpack.securitySolution.policyStatusText.failure": "失败", "xpack.securitySolution.policyStatusText.success": "成功", "xpack.securitySolution.policyStatusText.unsupported": "不支持", @@ -23760,8 +23706,6 @@ "xpack.securitySolution.trustedapps.logicalConditionBuilder.group.andOperator": "AND", "xpack.securitySolution.trustedapps.logicalConditionBuilder.noEntries": "未定义条件", "xpack.securitySolution.trustedapps.middleware.editIdMissing": "未提供 ID", - "xpack.securitySolution.trustedapps.policySelect.globalSectionTitle": "分配", - "xpack.securitySolution.trustedapps.policySelect.globalSwitchTitle": "全局应用受信任的应用程序", "xpack.securitySolution.trustedapps.trustedapp.entry.field": "字段", "xpack.securitySolution.trustedapps.trustedapp.entry.operator": "运算符", "xpack.securitySolution.trustedapps.trustedapp.entry.value": "值", @@ -26572,13 +26516,7 @@ "xpack.uptime.createPackagePolicy.stepConfigure.tlsSettings.label": "TLS 设置", "xpack.uptime.durationChart.emptyPrompt.description": "在选定时间范围内此监测从未{emphasizedText}。", "xpack.uptime.durationChart.emptyPrompt.title": "没有持续时间数据", - "xpack.uptime.emptyState.configureHeartbeatIndexSettings": "如果已设置 Heartbeat,请确认其正向 Elasticsearch 发送数据,然后更新索引模式设置以匹配 Heartbeat 配置。", - "xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage": "设置 Heartbeat 以开始监测您的服务。", "xpack.uptime.emptyState.loadingMessage": "正在加载……", - "xpack.uptime.emptyState.noDataMessage": "在索引 {indexName} 中找不到运行时间数据", - "xpack.uptime.emptyState.noIndexTitle": "找不到模式 {indexName} 的索引", - "xpack.uptime.emptyState.updateIndexPattern": "更新索引模式设置", - "xpack.uptime.emptyState.viewSetupInstructions": "查看设置说明", "xpack.uptime.emptyStateError.notAuthorized": "您无权查看 Uptime 数据,请联系系统管理员。", "xpack.uptime.emptyStateError.notFoundPage": "未找到页面", "xpack.uptime.emptyStateError.title": "错误", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.test.tsx index ed56ca05538b1..ec86f149e9a43 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.test.tsx @@ -48,6 +48,7 @@ describe('connector validation', () => { secrets: { user: 'user', password: 'pass', + clientSecret: null, }, id: 'test', actionTypeId: '.email', @@ -70,12 +71,15 @@ describe('connector validation', () => { port: [], host: [], service: [], + clientId: [], + tenantId: [], }, }, secrets: { errors: { user: [], password: [], + clientSecret: [], }, }, }); @@ -86,6 +90,7 @@ describe('connector validation', () => { secrets: { user: null, password: null, + clientSecret: null, }, id: 'test', actionTypeId: '.email', @@ -108,12 +113,15 @@ describe('connector validation', () => { port: [], host: [], service: [], + clientId: [], + tenantId: [], }, }, secrets: { errors: { user: [], password: [], + clientSecret: [], }, }, }); @@ -141,12 +149,15 @@ describe('connector validation', () => { port: ['Port is required.'], host: ['Host is required.'], service: [], + clientId: [], + tenantId: [], }, }, secrets: { errors: { user: [], password: [], + clientSecret: [], }, }, }); @@ -156,6 +167,7 @@ describe('connector validation', () => { secrets: { user: 'user', password: null, + clientSecret: null, }, id: 'test', actionTypeId: '.email', @@ -178,12 +190,15 @@ describe('connector validation', () => { port: [], host: [], service: [], + clientId: [], + tenantId: [], }, }, secrets: { errors: { user: [], password: ['Password is required when username is used.'], + clientSecret: [], }, }, }); @@ -193,6 +208,7 @@ describe('connector validation', () => { secrets: { user: null, password: 'password', + clientSecret: null, }, id: 'test', actionTypeId: '.email', @@ -215,12 +231,15 @@ describe('connector validation', () => { port: [], host: [], service: [], + clientId: [], + tenantId: [], }, }, secrets: { errors: { user: ['Username is required when password is used.'], password: [], + clientSecret: [], }, }, }); @@ -253,12 +272,53 @@ describe('connector validation', () => { port: [], host: [], service: ['Service is required.'], + clientId: [], + tenantId: [], }, }, secrets: { errors: { user: [], password: [], + clientSecret: [], + }, + }, + }); + }); + test('connector validation fails when for exchange service selected, but clientId, tenantId and clientSecrets were not defined', async () => { + const actionConnector = { + secrets: { + user: 'user', + password: 'pass', + clientSecret: null, + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + isPreconfigured: false, + config: { + from: 'test@test.com', + hasAuth: true, + service: 'exchange_server', + }, + } as EmailActionConnector; + + expect(await actionTypeModel.validateConnector(actionConnector)).toEqual({ + config: { + errors: { + from: [], + port: [], + host: [], + service: [], + clientId: ['Client ID is required.'], + tenantId: ['Tenant ID is required.'], + }, + }, + secrets: { + errors: { + clientSecret: ['Client Secret is required.'], + password: [], + user: [], }, }, }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.tsx index fe0b18b1b2e61..709101396edf0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.tsx @@ -14,6 +14,7 @@ import { GenericValidationResult, } from '../../../../types'; import { EmailActionParams, EmailConfig, EmailSecrets, EmailActionConnector } from '../types'; +import { AdditionalEmailServices } from '../../../../../../actions/common'; const emailServices: EuiSelectOption[] = [ { @@ -106,10 +107,13 @@ export function getActionType(): ActionTypeModel(), host: new Array(), service: new Array(), + clientId: new Array(), + tenantId: new Array(), }; const secretsErrors = { user: new Array(), password: new Array(), + clientSecret: new Array(), }; const validationResult = { @@ -122,17 +126,29 @@ export function getActionType(): ActionTypeModel import('./exchange_form')); export const EmailActionConnectorFields: React.FunctionComponent< ActionConnectorFieldsProps > = ({ action, editActionConfig, editActionSecrets, errors, readOnly }) => { @@ -61,6 +63,88 @@ export const EmailActionConnectorFields: React.FunctionComponent< password !== undefined && errors.password !== undefined && errors.password.length > 0; const isUserInvalid: boolean = user !== undefined && errors.user !== undefined && errors.user.length > 0; + + const authForm = ( + <> + {getEncryptedFieldNotifyLabel( + !action.id, + 2, + action.isMissingSecrets ?? false, + i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.emailAction.reenterValuesLabel', + { + defaultMessage: + 'Username and password are encrypted. Please reenter values for these fields.', + } + ) + )} + + + + { + editActionSecrets('user', nullableString(e.target.value)); + }} + onBlur={() => { + if (!user) { + editActionSecrets('user', ''); + } + }} + /> + + + + + { + editActionSecrets('password', nullableString(e.target.value)); + }} + onBlur={() => { + if (!password) { + editActionSecrets('password', ''); + } + }} + /> + + + + + ); + return ( <> @@ -130,214 +214,149 @@ export const EmailActionConnectorFields: React.FunctionComponent< /> - - - { - editActionConfig('host', e.target.value); - }} - onBlur={() => { - if (!host) { - editActionConfig('host', ''); - } - }} - /> - - - + + {service === AdditionalEmailServices.EXCHANGE ? ( + + ) : ( + <> - { - editActionConfig('port', parseInt(e.target.value, 10)); + editActionConfig('host', e.target.value); }} onBlur={() => { - if (!port) { - editActionConfig('port', 0); + if (!host) { + editActionConfig('host', ''); } }} /> - - - + + { - editActionConfig('secure', e.target.checked); - }} - /> - - + > + { + editActionConfig('port', parseInt(e.target.value, 10)); + }} + onBlur={() => { + if (!port) { + editActionConfig('port', 0); + } + }} + /> + + + + + + { + editActionConfig('secure', e.target.checked); + }} + /> + + + + - - - - - - -

    - -

    -
    - - { - editActionConfig('hasAuth', e.target.checked); - if (!e.target.checked) { - editActionSecrets('user', null); - editActionSecrets('password', null); - } - }} - /> -
    -
    - {hasAuth ? ( - <> - {getEncryptedFieldNotifyLabel( - !action.id, - 2, - action.isMissingSecrets ?? false, - i18n.translate( - 'xpack.triggersActionsUI.components.builtinActionTypes.emailAction.reenterValuesLabel', - { - defaultMessage: - 'Username and password are encrypted. Please reenter values for these fields.', - } - ) - )} - + - + +

    + +

    +
    + + - { - editActionSecrets('user', nullableString(e.target.value)); - }} - onBlur={() => { - if (!user) { - editActionSecrets('user', ''); - } - }} - /> -
    -
    - - { + editActionConfig('hasAuth', e.target.checked); + if (!e.target.checked) { + editActionSecrets('user', null); + editActionSecrets('password', null); } - )} - > - { - editActionSecrets('password', nullableString(e.target.value)); - }} - onBlur={() => { - if (!password) { - editActionSecrets('password', ''); - } - }} - /> - + }} + />
    + {hasAuth ? authForm : null} - ) : null} + )} ); }; // if the string == null or is empty, return null, else return string -function nullableString(str: string | null | undefined) { +export function nullableString(str: string | null | undefined) { if (str == null || str.trim() === '') return null; return str; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/exchange_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/exchange_form.test.tsx new file mode 100644 index 0000000000000..2a08c9b19e602 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/exchange_form.test.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { mountWithIntl } from '@kbn/test/jest'; +import { EmailActionConnector } from '../types'; +import ExchangeFormFields from './exchange_form'; + +jest.mock('../../../../common/lib/kibana'); + +describe('ExchangeFormFields renders', () => { + test('should display exchange form fields', () => { + const actionConnector = { + secrets: { + clientSecret: 'user', + }, + id: 'test', + actionTypeId: '.email', + name: 'exchange email', + config: { + from: 'test@test.com', + hasAuth: true, + service: 'exchange_server', + clientId: '123', + tenantId: '1234', + }, + } as EmailActionConnector; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + readOnly={false} + /> + ); + expect(wrapper.find('[data-test-subj="emailClientSecret"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailClientId"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailTenantId"]').length > 0).toBeTruthy(); + }); + + test('exchange field defaults to empty when not defined', () => { + const actionConnector = { + secrets: {}, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + from: 'test@test.com', + hasAuth: true, + service: 'exchange_server', + }, + } as EmailActionConnector; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + readOnly={false} + /> + ); + expect(wrapper.find('[data-test-subj="emailClientSecret"]').length > 0).toBeTruthy(); + expect(wrapper.find('input[data-test-subj="emailClientSecret"]').prop('value')).toEqual(''); + + expect(wrapper.find('[data-test-subj="emailClientId"]').length > 0).toBeTruthy(); + expect(wrapper.find('input[data-test-subj="emailClientId"]').prop('value')).toEqual(''); + + expect(wrapper.find('[data-test-subj="emailTenantId"]').length > 0).toBeTruthy(); + expect(wrapper.find('input[data-test-subj="emailTenantId"]').prop('value')).toEqual(''); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/exchange_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/exchange_form.tsx new file mode 100644 index 0000000000000..52fa53da19cd8 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/exchange_form.tsx @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiFieldText, + EuiFlexItem, + EuiFlexGroup, + EuiFormRow, + EuiFieldPassword, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { IErrorObject } from '../../../../types'; +import { EmailActionConnector } from '../types'; +import { nullableString } from './email_connector'; +import { getEncryptedFieldNotifyLabel } from '../../get_encrypted_field_notify_label'; + +interface ExchangeFormFieldsProps { + action: EmailActionConnector; + editActionConfig: (property: string, value: unknown) => void; + editActionSecrets: (property: string, value: unknown) => void; + errors: IErrorObject; + readOnly: boolean; +} + +const ExchangeFormFields: React.FunctionComponent = ({ + action, + editActionConfig, + editActionSecrets, + errors, + readOnly, +}) => { + const { tenantId, clientId } = action.config; + const { clientSecret } = action.secrets; + + const isClientIdInvalid: boolean = + clientId !== undefined && errors.clientId !== undefined && errors.clientId.length > 0; + const isTenantIdInvalid: boolean = + tenantId !== undefined && errors.tenantId !== undefined && errors.tenantId.length > 0; + const isClientSecretInvalid: boolean = + clientSecret !== undefined && + errors.clientSecret !== undefined && + errors.clientSecret.length > 0; + + return ( + <> + + + + { + editActionConfig('tenantId', nullableString(e.target.value)); + }} + onBlur={() => { + if (!tenantId) { + editActionConfig('tenantId', ''); + } + }} + /> + + + + + { + editActionConfig('clientId', nullableString(e.target.value)); + }} + onBlur={() => { + if (!clientId) { + editActionConfig('clientId', ''); + } + }} + /> + + + + {getEncryptedFieldNotifyLabel( + !action.id, + 1, + action.isMissingSecrets ?? false, + i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.emailAction.reenterClientSecretLabel', + { + defaultMessage: 'Client Secret is encrypted. Please reenter value for this field.', + } + ) + )} + + + + { + editActionSecrets('clientSecret', nullableString(e.target.value)); + }} + onBlur={() => { + if (!clientSecret) { + editActionSecrets('clientSecret', ''); + } + }} + /> + + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export { ExchangeFormFields as default }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/translations.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/translations.ts index df68d0d1237ed..38e16f6046184 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/translations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/translations.ts @@ -21,6 +21,27 @@ export const SENDER_NOT_VALID = i18n.translate( } ); +export const CLIENT_ID_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredClientIdText', + { + defaultMessage: 'Client ID is required.', + } +); + +export const TENANT_ID_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredTenantIdText', + { + defaultMessage: 'Tenant ID is required.', + } +); + +export const CLIENT_SECRET_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredClientSecretText', + { + defaultMessage: 'Client Secret is required.', + } +); + export const PORT_REQUIRED = i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredPortText', { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/use_email_config.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/use_email_config.ts index fad71cf5d6385..9e6df1d1a1019 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/use_email_config.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/use_email_config.ts @@ -10,6 +10,7 @@ import { HttpSetup } from 'kibana/public'; import { isEmpty } from 'lodash'; import { EmailConfig } from '../types'; import { getServiceConfig } from './api'; +import { AdditionalEmailServices } from '../../../../../../actions/common'; export function useEmailConfig( http: HttpSetup, @@ -39,9 +40,12 @@ export function useEmailConfig( useEffect(() => { (async () => { if (emailService) { + editActionConfig('service', emailService); + if (emailService === AdditionalEmailServices.EXCHANGE) { + return; + } const serviceConfig = await getEmailServiceConfig(emailService); - editActionConfig('service', emailService); editActionConfig('host', serviceConfig?.host ? serviceConfig.host : ''); editActionConfig('port', serviceConfig?.port ? serviceConfig.port : 0); editActionConfig('secure', null != serviceConfig?.secure ? serviceConfig.secure : false); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts index 60e0a0f14b897..abacc5544c712 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts @@ -79,11 +79,14 @@ export interface EmailConfig { secure?: boolean; hasAuth: boolean; service: string; + clientId?: string; + tenantId?: string; } export interface EmailSecrets { user: string | null; password: string | null; + clientSecret: string | null; } export type EmailActionConnector = UserConfiguredActionConnector; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx index b998067424edd..ff5992a6542b7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx @@ -114,7 +114,7 @@ describe('health check', () => { ); expect(action.getAttribute('href')).toMatchInlineSnapshot( - `"https://www.elastic.co/guide/en/kibana/mocked-test-branch/configuring-tls.html"` + `"https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/security-basic-setup.html#encrypt-internode-communication"` ); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx index d198c82366fbf..c7c41ac4e8171 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx @@ -39,6 +39,10 @@ jest.mock('react-router-dom', () => ({ }), })); +jest.mock('../../../lib/action_connector_api', () => ({ + loadAllActions: jest.fn().mockResolvedValue([]), +})); + jest.mock('../../../lib/capabilities', () => ({ hasAllPrivilege: jest.fn(() => true), hasSaveAlertsCapability: jest.fn(() => true), @@ -60,24 +64,22 @@ const authorizedConsumers = { }; const recoveryActionGroup: ActionGroup<'recovered'> = { id: 'recovered', name: 'Recovered' }; -describe('alert_details', () => { - // mock Api handlers +const alertType: AlertType = { + id: '.noop', + name: 'No Op', + actionGroups: [{ id: 'default', name: 'Default' }], + recoveryActionGroup, + actionVariables: { context: [], state: [], params: [] }, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + producer: ALERTS_FEATURE_ID, + authorizedConsumers, + enabledInLicense: true, +}; +describe('alert_details', () => { it('renders the alert name as a title', () => { const alert = mockAlert(); - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - enabledInLicense: true, - }; - expect( shallow( @@ -87,19 +89,6 @@ describe('alert_details', () => { it('renders the alert type badge', () => { const alert = mockAlert(); - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - enabledInLicense: true, - }; - expect( shallow( @@ -118,19 +107,6 @@ describe('alert_details', () => { }, }, }); - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - enabledInLicense: true, - }; - expect( shallow( @@ -155,19 +131,6 @@ describe('alert_details', () => { ], }); - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - enabledInLicense: true, - }; - const actionTypes: ActionType[] = [ { id: '.server-log', @@ -212,18 +175,6 @@ describe('alert_details', () => { }, ], }); - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - minimumLicenseRequired: 'basic', - authorizedConsumers, - enabledInLicense: true, - }; const actionTypes: ActionType[] = [ { id: '.server-log', @@ -273,20 +224,6 @@ describe('alert_details', () => { describe('links', () => { it('links to the app that created the alert', () => { const alert = mockAlert(); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - expect( shallow( @@ -296,19 +233,6 @@ describe('alert_details', () => { it('links to the Edit flyout', () => { const alert = mockAlert(); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; const pageHeaderProps = shallow( ) @@ -316,22 +240,22 @@ describe('alert_details', () => { .props() as EuiPageHeaderProps; const rightSideItems = pageHeaderProps.rightSideItems; expect(!!rightSideItems && rightSideItems[2]!).toMatchInlineSnapshot(` - - - - - - `); + + + + + + `); }); }); }); @@ -341,20 +265,6 @@ describe('disable button', () => { const alert = mockAlert({ enabled: true, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const enableButton = shallow( ) @@ -368,55 +278,43 @@ describe('disable button', () => { }); }); - it('should render a enable button when alert is disabled', () => { + it('should render a enable button and empty state when alert is disabled', async () => { const alert = mockAlert({ enabled: false, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - - const enableButton = shallow( + const wrapper = mountWithIntl( - ) - .find(EuiSwitch) - .find('[name="enable"]') - .first(); + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + const enableButton = wrapper.find(EuiSwitch).find('[name="enable"]').first(); + const disabledEmptyPrompt = wrapper.find('[data-test-subj="disabledEmptyPrompt"]'); + const disabledEmptyPromptAction = wrapper.find('[data-test-subj="disabledEmptyPromptAction"]'); expect(enableButton.props()).toMatchObject({ checked: false, disabled: false, }); + expect(disabledEmptyPrompt.exists()).toBeTruthy(); + expect(disabledEmptyPromptAction.exists()).toBeTruthy(); + + disabledEmptyPromptAction.first().simulate('click'); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(mockAlertApis.enableAlert).toHaveBeenCalledTimes(1); }); - it('should enable the alert when alert is disabled and button is clicked', () => { + it('should disable the alert when alert is enabled and button is clicked', () => { const alert = mockAlert({ enabled: true, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const disableAlert = jest.fn(); const enableButton = shallow( { expect(disableAlert).toHaveBeenCalledTimes(1); }); - it('should disable the alert when alert is enabled and button is clicked', () => { + it('should enable the alert when alert is disabled and button is clicked', () => { const alert = mockAlert({ enabled: false, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const enableAlert = jest.fn(); const enableButton = shallow( { }, }); - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const disableAlert = jest.fn(); const enableAlert = jest.fn(); const wrapper = mountWithIntl( @@ -565,19 +436,6 @@ describe('disable button', () => { }, }); - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const disableAlert = jest.fn(async () => { await new Promise((resolve) => setTimeout(resolve, 6000)); }); @@ -630,27 +488,12 @@ describe('mute button', () => { enabled: true, muteAll: false, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const enableButton = shallow( ) .find(EuiSwitch) .find('[name="mute"]') .first(); - expect(enableButton.props()).toMatchObject({ checked: false, disabled: false, @@ -662,27 +505,12 @@ describe('mute button', () => { enabled: true, muteAll: true, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const enableButton = shallow( ) .find(EuiSwitch) .find('[name="mute"]') .first(); - expect(enableButton.props()).toMatchObject({ checked: true, disabled: false, @@ -694,20 +522,6 @@ describe('mute button', () => { enabled: true, muteAll: false, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const muteAlert = jest.fn(); const enableButton = shallow( { .find(EuiSwitch) .find('[name="mute"]') .first(); - enableButton.simulate('click'); const handler = enableButton.prop('onChange'); expect(typeof handler).toEqual('function'); @@ -735,20 +548,6 @@ describe('mute button', () => { enabled: true, muteAll: true, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const unmuteAlert = jest.fn(); const enableButton = shallow( { .find(EuiSwitch) .find('[name="mute"]') .first(); - enableButton.simulate('click'); const handler = enableButton.prop('onChange'); expect(typeof handler).toEqual('function'); @@ -776,27 +574,12 @@ describe('mute button', () => { enabled: false, muteAll: false, }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const enableButton = shallow( ) .find(EuiSwitch) .find('[name="mute"]') .first(); - expect(enableButton.props()).toMatchObject({ checked: false, disabled: true, @@ -843,20 +626,6 @@ describe('edit button', () => { }, ], }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: 'alerting', - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const pageHeaderProps = shallow( { .props() as EuiPageHeaderProps; const rightSideItems = pageHeaderProps.rightSideItems; expect(!!rightSideItems && rightSideItems[2]!).toMatchInlineSnapshot(` - - - - - - `); + + + + + + `); }); it('should not render an edit button when alert editable but actions arent', () => { const { hasExecuteActionsCapability } = jest.requireMock('../../../lib/capabilities'); - hasExecuteActionsCapability.mockReturnValue(false); + hasExecuteActionsCapability.mockReturnValueOnce(false); const alert = mockAlert({ enabled: true, muteAll: false, @@ -902,20 +671,6 @@ describe('edit button', () => { }, ], }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: 'alerting', - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - expect( shallow( { it('should render an edit button when alert editable but actions arent when there are no actions on the alert', async () => { const { hasExecuteActionsCapability } = jest.requireMock('../../../lib/capabilities'); - hasExecuteActionsCapability.mockReturnValue(false); + hasExecuteActionsCapability.mockReturnValueOnce(false); const alert = mockAlert({ enabled: true, muteAll: false, actions: [], }); - - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - producer: 'alerting', - authorizedConsumers, - minimumLicenseRequired: 'basic', - enabledInLicense: true, - }; - const pageHeaderProps = shallow( { .props() as EuiPageHeaderProps; const rightSideItems = pageHeaderProps.rightSideItems; expect(!!rightSideItems && rightSideItems[2]!).toMatchInlineSnapshot(` - - - - - - `); + + + + + + `); }); }); -describe('refresh button', () => { - it('should call requestRefresh when clicked', () => { - const alert = mockAlert(); - const alertType: AlertType = { - id: '.noop', - name: 'No Op', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup, - actionVariables: { context: [], state: [], params: [] }, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - producer: ALERTS_FEATURE_ID, - authorizedConsumers, +describe('broken connector indicator', () => { + const actionTypes: ActionType[] = [ + { + id: '.server-log', + name: 'Server log', + enabled: true, + enabledInConfig: true, enabledInLicense: true, - }; + minimumLicenseRequired: 'basic', + }, + ]; + ruleTypeRegistry.has.mockReturnValue(true); + const alertTypeR: AlertTypeModel = { + id: 'my-alert-type', + iconClass: 'test', + description: 'Alert when testing', + documentationUrl: 'https://localhost.local/docs', + validate: () => { + return { errors: {} }; + }, + alertParamsExpression: jest.fn(), + requiresAppContext: false, + }; + ruleTypeRegistry.get.mockReturnValue(alertTypeR); + useKibanaMock().services.ruleTypeRegistry = ruleTypeRegistry; + const { loadAllActions } = jest.requireMock('../../../lib/action_connector_api'); + loadAllActions.mockResolvedValue([ + { + secrets: {}, + isMissingSecrets: false, + id: 'connector-id-1', + actionTypeId: '.server-log', + name: 'Test connector', + config: {}, + isPreconfigured: false, + }, + { + secrets: {}, + isMissingSecrets: false, + id: 'connector-id-2', + actionTypeId: '.server-log', + name: 'Test connector 2', + config: {}, + isPreconfigured: false, + }, + ]); + it('should not render broken connector indicator or warning if all rule actions connectors exist', async () => { + const alert = mockAlert({ + enabled: true, + muteAll: false, + actions: [ + { + group: 'default', + id: 'connector-id-1', + params: {}, + actionTypeId: '.server-log', + }, + { + group: 'default', + id: 'connector-id-2', + params: {}, + actionTypeId: '.server-log', + }, + ], + }); + const wrapper = mountWithIntl( + + ); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + const brokenConnectorIndicator = wrapper + .find('[data-test-subj="actionWithBrokenConnector"]') + .first(); + const brokenConnectorWarningBanner = wrapper + .find('[data-test-subj="actionWithBrokenConnectorWarningBanner"]') + .first(); + expect(brokenConnectorIndicator.exists()).toBeFalsy(); + expect(brokenConnectorWarningBanner.exists()).toBeFalsy(); + }); + + it('should render broken connector indicator and warning if any rule actions connector does not exist', async () => { + const alert = mockAlert({ + enabled: true, + muteAll: false, + actions: [ + { + group: 'default', + id: 'connector-id-1', + params: {}, + actionTypeId: '.server-log', + }, + { + group: 'default', + id: 'connector-id-2', + params: {}, + actionTypeId: '.server-log', + }, + { + group: 'default', + id: 'connector-id-doesnt-exist', + params: {}, + actionTypeId: '.server-log', + }, + ], + }); + const wrapper = mountWithIntl( + + ); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + const brokenConnectorIndicator = wrapper + .find('[data-test-subj="actionWithBrokenConnector"]') + .first(); + const brokenConnectorWarningBanner = wrapper + .find('[data-test-subj="actionWithBrokenConnectorWarningBanner"]') + .first(); + const brokenConnectorWarningBannerAction = wrapper + .find('[data-test-subj="actionWithBrokenConnectorWarningBannerEdit"]') + .first(); + expect(brokenConnectorIndicator.exists()).toBeTruthy(); + expect(brokenConnectorWarningBanner.exists()).toBeTruthy(); + expect(brokenConnectorWarningBannerAction.exists()).toBeTruthy(); + }); + + it('should render broken connector indicator and warning with no edit button if any rule actions connector does not exist and user has no edit access', async () => { + const alert = mockAlert({ + enabled: true, + muteAll: false, + actions: [ + { + group: 'default', + id: 'connector-id-1', + params: {}, + actionTypeId: '.server-log', + }, + { + group: 'default', + id: 'connector-id-2', + params: {}, + actionTypeId: '.server-log', + }, + { + group: 'default', + id: 'connector-id-doesnt-exist', + params: {}, + actionTypeId: '.server-log', + }, + ], + }); + const { hasExecuteActionsCapability } = jest.requireMock('../../../lib/capabilities'); + hasExecuteActionsCapability.mockReturnValue(false); + const wrapper = mountWithIntl( + + ); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + const brokenConnectorIndicator = wrapper + .find('[data-test-subj="actionWithBrokenConnector"]') + .first(); + const brokenConnectorWarningBanner = wrapper + .find('[data-test-subj="actionWithBrokenConnectorWarningBanner"]') + .first(); + const brokenConnectorWarningBannerAction = wrapper + .find('[data-test-subj="actionWithBrokenConnectorWarningBannerEdit"]') + .first(); + expect(brokenConnectorIndicator.exists()).toBeTruthy(); + expect(brokenConnectorWarningBanner.exists()).toBeTruthy(); + expect(brokenConnectorWarningBannerAction.exists()).toBeFalsy(); + }); +}); + +describe('refresh button', () => { + it('should call requestRefresh when clicked', async () => { + const alert = mockAlert(); const requestRefresh = jest.fn(); const wrapper = mountWithIntl( { /> ); + await act(async () => { + await nextTick(); + wrapper.update(); + }); const refreshButton = wrapper.find('[data-test-subj="refreshAlertsButton"]').first(); expect(refreshButton.exists()).toBeTruthy(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index 2558993a13fe6..2b13bdf613d96 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -22,13 +22,16 @@ import { EuiButtonEmpty, EuiButton, EuiLoadingSpinner, + EuiIconTip, + EuiEmptyPrompt, + EuiPageTemplate, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { AlertExecutionStatusErrorReasons } from '../../../../../../alerting/common'; import { hasAllPrivilege, hasExecuteActionsCapability } from '../../../lib/capabilities'; import { getAlertingSectionBreadcrumb, getAlertDetailsBreadcrumb } from '../../../lib/breadcrumb'; import { getCurrentDocTitle } from '../../../lib/doc_title'; -import { Alert, AlertType, ActionType } from '../../../../types'; +import { Alert, AlertType, ActionType, ActionConnector } from '../../../../types'; import { ComponentOpts as BulkOperationsComponentOpts, withBulkAlertOperations, @@ -40,6 +43,7 @@ import { routeToRuleDetails } from '../../../constants'; import { alertsErrorReasonTranslationsMapping } from '../../alerts_list/translations'; import { useKibana } from '../../../../common/lib/kibana'; import { alertReducer } from '../../alert_form/alert_reducer'; +import { loadAllActions as loadConnectors } from '../../../lib/action_connector_api'; export type AlertDetailsProps = { alert: Alert; @@ -72,6 +76,9 @@ export const AlertDetails: React.FunctionComponent = ({ dispatch({ command: { type: 'setAlert' }, payload: { key: 'alert', value } }); }; + const [hasActionsWithBrokenConnector, setHasActionsWithBrokenConnector] = + useState(false); + // Set breadcrumb and page title useEffect(() => { setBreadcrumbs([ @@ -82,6 +89,28 @@ export const AlertDetails: React.FunctionComponent = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + // Determine if any attached action has an issue with its connector + useEffect(() => { + (async () => { + let loadedConnectors: ActionConnector[] = []; + try { + loadedConnectors = await loadConnectors({ http }); + } catch (err) { + loadedConnectors = []; + } + + if (loadedConnectors.length > 0) { + const hasActionWithBrokenConnector = alert.actions.some( + (action) => !loadedConnectors.find((connector) => connector.id === action.id) + ); + if (setHasActionsWithBrokenConnector) { + setHasActionsWithBrokenConnector(hasActionWithBrokenConnector); + } + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const canExecuteActions = hasExecuteActionsCapability(capabilities); const canSaveAlert = hasAllPrivilege(alert, alertType) && @@ -197,13 +226,27 @@ export const AlertDetails: React.FunctionComponent = ({ {uniqueActions && uniqueActions.length ? ( <> -

    - {' '} + {hasActionsWithBrokenConnector && ( + -

    + )}
    + {uniqueActions.map((action, index) => ( @@ -358,6 +401,42 @@ export const AlertDetails: React.FunctionComponent = ({ ) : null} + {hasActionsWithBrokenConnector && ( + + + + + {hasEditButton && ( + + + setEditFlyoutVisibility(true)} + > + + + + + )} + + + + )} {alert.enabled ? ( @@ -370,23 +449,46 @@ export const AlertDetails: React.FunctionComponent = ({ ) : ( <> - + + + } - )} - color="warning" - iconType="help" - > -

    - -

    -
    + body={ + <> +

    + +

    + + } + actions={[ + { + setIsEnabledUpdating(true); + setIsEnabled(true); + await enableAlert(alert); + requestRefresh(); + setIsEnabledUpdating(false); + }} + > + Enable + , + ]} + /> + )}
    diff --git a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx index ee2587f61fbc8..f0ec601a0cc2f 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx @@ -15,7 +15,6 @@ import { } from 'src/plugins/embeddable/public'; import { Action, IncompatibleActionError } from '../../../../src/plugins/ui_actions/public'; import { TimeRange } from '../../../../src/plugins/data/public'; -import { CustomizeTimeRangeModal } from './customize_time_range_modal'; import { OpenModal, CommonlyUsedRange } from './types'; export const CUSTOM_TIME_RANGE = 'CUSTOM_TIME_RANGE'; @@ -97,6 +96,9 @@ export class CustomTimeRangeAction implements Action { // Only here for typescript if (hasTimeRange(embeddable)) { + const CustomizeTimeRangeModal = await import('./customize_time_range_modal').then( + (m) => m.CustomizeTimeRangeModal + ); const modalSession = this.openModal( modalSession.close()} diff --git a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.tsx b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.tsx index 441381cd76fe1..28d936475f6b1 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.tsx @@ -10,7 +10,6 @@ import { prettyDuration, commonDurationRanges } from '@elastic/eui'; import { IEmbeddable, Embeddable, EmbeddableInput } from 'src/plugins/embeddable/public'; import { Action, IncompatibleActionError } from '../../../../src/plugins/ui_actions/public'; import { TimeRange } from '../../../../src/plugins/data/public'; -import { CustomizeTimeRangeModal } from './customize_time_range_modal'; import { doesInheritTimeRange } from './does_inherit_time_range'; import { OpenModal, CommonlyUsedRange } from './types'; @@ -77,6 +76,9 @@ export class CustomTimeRangeBadge implements Action { // Only here for typescript if (hasTimeRange(embeddable)) { + const CustomizeTimeRangeModal = await import('./customize_time_range_modal').then( + (m) => m.CustomizeTimeRangeModal + ); const modalSession = this.openModal( modalSession.close()} diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/create_public_drilldown_manager.tsx b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/create_public_drilldown_manager.tsx index 6b7d8a7a19360..17251958abde0 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/create_public_drilldown_manager.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/create_public_drilldown_manager.tsx @@ -7,11 +7,15 @@ import * as React from 'react'; import { DrilldownManagerDependencies, PublicDrilldownManagerProps } from '../../types'; -import { DrilldownManagerProvider } from '../context'; -import { DrilldownManager } from './drilldown_manager'; export type PublicDrilldownManagerComponent = React.FC; +const LazyDrilldownManager = React.lazy(() => + import('./drilldown_manager_with_provider').then((m) => ({ + default: m.DrilldownManagerWithProvider, + })) +); + /** * This HOC creates a "public" `` component `PublicDrilldownManagerComponent`, * which can be exported from plugin contract for other plugins to consume. @@ -21,9 +25,9 @@ export const createPublicDrilldownManager = ( ): PublicDrilldownManagerComponent => { const PublicDrilldownManager: PublicDrilldownManagerComponent = (drilldownManagerProps) => { return ( - - - + + + ); }; diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/drilldown_manager_with_provider.tsx b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/drilldown_manager_with_provider.tsx new file mode 100644 index 0000000000000..6f67a91f3feaa --- /dev/null +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/drilldown_manager_with_provider.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { DrilldownManagerProvider, DrilldownManagerProviderProps } from '../context'; +import { DrilldownManager } from './drilldown_manager'; + +export const DrilldownManagerWithProvider: React.FC = (props) => { + return ( + + + + ); +}; diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/index.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/index.ts index fd2b7adf3e4bc..82cb861d496b9 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/index.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/containers/drilldown_manager/index.ts @@ -5,5 +5,4 @@ * 2.0. */ -export * from './drilldown_manager'; export * from './create_public_drilldown_manager'; diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/handlebars.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/handlebars.ts new file mode 100644 index 0000000000000..3f831bc5c9057 --- /dev/null +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/handlebars.ts @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { create as createHandlebars, HelperDelegate, HelperOptions } from 'handlebars'; +import { encode, RisonValue } from 'rison-node'; +import dateMath from '@elastic/datemath'; +import moment, { Moment } from 'moment'; +import numeral from '@elastic/numeral'; +import { url } from '../../../../../../src/plugins/kibana_utils/public'; + +const handlebars = createHandlebars(); + +function createSerializationHelper( + fnName: string, + serializeFn: (value: unknown) => string +): HelperDelegate { + return (...args) => { + const { hash } = args.slice(-1)[0] as HelperOptions; + const hasHash = Object.keys(hash).length > 0; + const hasValues = args.length > 1; + if (hasHash && hasValues) { + throw new Error(`[${fnName}]: both value list and hash are not supported`); + } + if (hasHash) { + if (Object.values(hash).some((v) => typeof v === 'undefined')) + throw new Error(`[${fnName}]: unknown variable`); + return serializeFn(hash); + } else { + const values = args.slice(0, -1) as unknown[]; + if (values.some((value) => typeof value === 'undefined')) + throw new Error(`[${fnName}]: unknown variable`); + if (values.length === 0) throw new Error(`[${fnName}]: unknown variable`); + if (values.length === 1) return serializeFn(values[0]); + return serializeFn(values); + } + }; +} + +handlebars.registerHelper('json', createSerializationHelper('json', JSON.stringify)); +handlebars.registerHelper( + 'rison', + createSerializationHelper('rison', (v) => encode(v as RisonValue)) +); + +handlebars.registerHelper('date', (...args) => { + const values = args.slice(0, -1) as [string | Date, string | undefined]; + // eslint-disable-next-line prefer-const + let [date, format] = values; + if (typeof date === 'undefined') throw new Error(`[date]: unknown variable`); + let momentDate: Moment | undefined; + if (typeof date === 'string') { + momentDate = dateMath.parse(date); + if (!momentDate || !momentDate.isValid()) { + const ts = Number(date); + if (!Number.isNaN(ts)) { + momentDate = moment(ts); + } + } + } else { + momentDate = moment(date); + } + + if (!momentDate || !momentDate.isValid()) { + // do not throw error here, because it could be that in preview `__testValue__` is not parsable, + // but in runtime it is + return date; + } + return format ? momentDate.format(format) : momentDate.toISOString(); +}); + +handlebars.registerHelper('formatNumber', (rawValue: unknown, pattern: string) => { + if (!pattern || typeof pattern !== 'string') + throw new Error(`[formatNumber]: pattern string is required`); + const value = Number(rawValue); + if (rawValue == null || Number.isNaN(value)) return rawValue; + return numeral(value).format(pattern); +}); + +handlebars.registerHelper('lowercase', (rawValue: unknown) => String(rawValue).toLowerCase()); +handlebars.registerHelper('uppercase', (rawValue: unknown) => String(rawValue).toUpperCase()); +handlebars.registerHelper('trim', (rawValue: unknown) => String(rawValue).trim()); +handlebars.registerHelper('trimLeft', (rawValue: unknown) => String(rawValue).trimLeft()); +handlebars.registerHelper('trimRight', (rawValue: unknown) => String(rawValue).trimRight()); +handlebars.registerHelper('left', (rawValue: unknown, numberOfChars: number) => { + if (typeof numberOfChars !== 'number') + throw new Error('[left]: expected "number of characters to extract" to be a number'); + return String(rawValue).slice(0, numberOfChars); +}); +handlebars.registerHelper('right', (rawValue: unknown, numberOfChars: number) => { + if (typeof numberOfChars !== 'number') + throw new Error('[left]: expected "number of characters to extract" to be a number'); + return String(rawValue).slice(-numberOfChars); +}); +handlebars.registerHelper('mid', (rawValue: unknown, start: number, length: number) => { + if (typeof start !== 'number') throw new Error('[left]: expected "start" to be a number'); + if (typeof length !== 'number') throw new Error('[left]: expected "length" to be a number'); + return String(rawValue).substr(start, length); +}); +handlebars.registerHelper('concat', (...args) => { + const values = args.slice(0, -1) as unknown[]; + return values.join(''); +}); +handlebars.registerHelper('split', (...args) => { + const [str, splitter] = args.slice(0, -1) as [string, string]; + if (typeof splitter !== 'string') throw new Error('[split] "splitter" expected to be a string'); + return String(str).split(splitter); +}); +handlebars.registerHelper('replace', (...args) => { + const [str, searchString, valueString] = args.slice(0, -1) as [string, string, string]; + if (typeof searchString !== 'string' || typeof valueString !== 'string') + throw new Error( + '[replace]: "searchString" and "valueString" parameters expected to be strings, but not a string or missing' + ); + return String(str).split(searchString).join(valueString); +}); + +handlebars.registerHelper('encodeURIComponent', (component: unknown) => { + const str = String(component); + return encodeURIComponent(str); +}); +handlebars.registerHelper('encodeURIQuery', (component: unknown) => { + const str = String(component); + return url.encodeUriQuery(str); +}); + +export { handlebars }; diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.test.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.test.ts index e2a287f700947..032a54364b940 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.test.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.test.ts @@ -8,83 +8,83 @@ import { compile } from './url_template'; import moment from 'moment-timezone'; -test('should compile url without variables', () => { +test('should compile url without variables', async () => { const url = 'https://elastic.co'; - expect(compile(url, {})).toBe(url); + expect(await compile(url, {})).toBe(url); }); -test('by default, encodes URI', () => { +test('by default, encodes URI', async () => { const url = 'https://elastic.co?foo=head%26shoulders'; - expect(compile(url, {})).not.toBe(url); - expect(compile(url, {})).toBe('https://elastic.co?foo=head%2526shoulders'); + expect(await compile(url, {})).not.toBe(url); + expect(await compile(url, {})).toBe('https://elastic.co?foo=head%2526shoulders'); }); -test('when URI encoding is disabled, should not encode URI', () => { +test('when URI encoding is disabled, should not encode URI', async () => { const url = 'https://xxxxx.service-now.com/nav_to.do?uri=incident.do%3Fsys_id%3D-1%26sysparm_query%3Dshort_description%3DHello'; - expect(compile(url, {}, false)).toBe(url); + expect(await compile(url, {}, false)).toBe(url); }); -test('should fail on unknown syntax', () => { +test('should fail on unknown syntax', async () => { const url = 'https://elastic.co/{{}'; - expect(() => compile(url, {})).toThrowError(); + await expect(() => compile(url, {})).rejects; }); -test('should fail on not existing variable', () => { +test('should fail on not existing variable', async () => { const url = 'https://elastic.co/{{fake}}'; - expect(() => compile(url, {})).toThrowError(); + await expect(() => compile(url, {})).rejects; }); -test('should fail on not existing nested variable', () => { +test('should fail on not existing nested variable', async () => { const url = 'https://elastic.co/{{fake.fake}}'; - expect(() => compile(url, { fake: {} })).toThrowError(); + await expect(() => compile(url, { fake: {} })).rejects; }); -test('should replace existing variable', () => { +test('should replace existing variable', async () => { const url = 'https://elastic.co/{{foo}}'; - expect(compile(url, { foo: 'bar' })).toMatchInlineSnapshot(`"https://elastic.co/bar"`); + expect(await compile(url, { foo: 'bar' })).toMatchInlineSnapshot(`"https://elastic.co/bar"`); }); -test('should fail on unknown helper', () => { +test('should fail on unknown helper', async () => { const url = 'https://elastic.co/{{fake foo}}'; - expect(() => compile(url, { foo: 'bar' })).toThrowError(); + await expect(() => compile(url, { foo: 'bar' })).rejects; }); describe('json helper', () => { - test('should replace with json', () => { + test('should replace with json', async () => { const url = 'https://elastic.co/{{json foo bar}}'; - expect(compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toMatchInlineSnapshot( + expect(await compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toMatchInlineSnapshot( `"https://elastic.co/%5B%7B%22foo%22:%22bar%22%7D,%7B%22bar%22:%22foo%22%7D%5D"` ); }); - test('should replace with json and skip encoding', () => { + test('should replace with json and skip encoding', async () => { const url = 'https://elastic.co/{{{json foo bar}}}'; - expect(compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toMatchInlineSnapshot( + expect(await compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toMatchInlineSnapshot( `"https://elastic.co/%5B%7B%22foo%22:%22bar%22%7D,%7B%22bar%22:%22foo%22%7D%5D"` ); }); - test('should throw on unknown key', () => { + test('should throw on unknown key', async () => { const url = 'https://elastic.co/{{{json fake}}}'; - expect(() => compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toThrowError(); + await expect(() => compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).rejects; }); }); describe('rison helper', () => { - test('should replace with rison', () => { + test('should replace with rison', async () => { const url = 'https://elastic.co/{{rison foo bar}}'; - expect(compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toMatchInlineSnapshot( + expect(await compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toMatchInlineSnapshot( `"https://elastic.co/!((foo:bar),(bar:foo))"` ); }); - test('should replace with rison and skip encoding', () => { + test('should replace with rison and skip encoding', async () => { const url = 'https://elastic.co/{{{rison foo bar}}}'; - expect(compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toMatchInlineSnapshot( + expect(await compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toMatchInlineSnapshot( `"https://elastic.co/!((foo:bar),(bar:foo))"` ); }); - test('should throw on unknown key', () => { + test('should throw on unknown key', async () => { const url = 'https://elastic.co/{{{rison fake}}}'; - expect(() => compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).toThrowError(); + await expect(() => compile(url, { foo: { foo: 'bar' }, bar: { bar: 'foo' } })).rejects; }); }); @@ -100,204 +100,217 @@ describe('date helper', () => { moment.tz.setDefault('Browser'); }); - test('uses datemath', () => { + test('uses datemath', async () => { const url = 'https://elastic.co/{{date time}}'; - expect(compile(url, { time: 'now' })).toMatchInlineSnapshot( + expect(await compile(url, { time: 'now' })).toMatchInlineSnapshot( `"https://elastic.co/2020-08-18T14:45:00.000Z"` ); }); - test('can use format', () => { + test('can use format', async () => { const url = 'https://elastic.co/{{date time "dddd, MMMM Do YYYY, h:mm:ss a"}}'; - expect(compile(url, { time: 'now' })).toMatchInlineSnapshot( + expect(await compile(url, { time: 'now' })).toMatchInlineSnapshot( `"https://elastic.co/Tuesday,%20August%2018th%202020,%202:45:00%20pm"` ); }); - test('throws if missing variable', () => { + test('throws if missing variable', async () => { const url = 'https://elastic.co/{{date time}}'; - expect(() => compile(url, {})).toThrowError(); + await expect(() => compile(url, {})).rejects; }); - test("doesn't throw if non valid date", () => { + test("doesn't throw if non valid date", async () => { const url = 'https://elastic.co/{{date time}}'; - expect(compile(url, { time: 'fake' })).toMatchInlineSnapshot(`"https://elastic.co/fake"`); + expect(await compile(url, { time: 'fake' })).toMatchInlineSnapshot(`"https://elastic.co/fake"`); }); - test("doesn't throw on boolean or number", () => { + test("doesn't throw on boolean or number", async () => { const url = 'https://elastic.co/{{date time}}'; - expect(compile(url, { time: false })).toMatchInlineSnapshot(`"https://elastic.co/false"`); - expect(compile(url, { time: 24 })).toMatchInlineSnapshot( + expect(await compile(url, { time: false })).toMatchInlineSnapshot(`"https://elastic.co/false"`); + expect(await compile(url, { time: 24 })).toMatchInlineSnapshot( `"https://elastic.co/1970-01-01T00:00:00.024Z"` ); }); - test('works with ISO string', () => { + test('works with ISO string', async () => { const url = 'https://elastic.co/{{date time}}'; - expect(compile(url, { time: date.toISOString() })).toMatchInlineSnapshot( + expect(await compile(url, { time: date.toISOString() })).toMatchInlineSnapshot( `"https://elastic.co/2020-08-18T14:45:00.000Z"` ); }); - test('works with ts', () => { + test('works with ts', async () => { const url = 'https://elastic.co/{{date time}}'; - expect(compile(url, { time: date.valueOf() })).toMatchInlineSnapshot( + expect(await compile(url, { time: date.valueOf() })).toMatchInlineSnapshot( `"https://elastic.co/2020-08-18T14:45:00.000Z"` ); }); - test('works with ts string', () => { + test('works with ts string', async () => { const url = 'https://elastic.co/{{date time}}'; - expect(compile(url, { time: String(date.valueOf()) })).toMatchInlineSnapshot( + expect(await compile(url, { time: String(date.valueOf()) })).toMatchInlineSnapshot( `"https://elastic.co/2020-08-18T14:45:00.000Z"` ); }); }); describe('formatNumber helper', () => { - test('formats string numbers', () => { + test('formats string numbers', async () => { const url = 'https://elastic.co/{{formatNumber value "0.0"}}'; - expect(compile(url, { value: '32.9999' })).toMatchInlineSnapshot(`"https://elastic.co/33.0"`); - expect(compile(url, { value: '32.555' })).toMatchInlineSnapshot(`"https://elastic.co/32.6"`); + expect(await compile(url, { value: '32.9999' })).toMatchInlineSnapshot( + `"https://elastic.co/33.0"` + ); + expect(await compile(url, { value: '32.555' })).toMatchInlineSnapshot( + `"https://elastic.co/32.6"` + ); }); - test('formats numbers', () => { + test('formats numbers', async () => { const url = 'https://elastic.co/{{formatNumber value "0.0"}}'; - expect(compile(url, { value: 32.9999 })).toMatchInlineSnapshot(`"https://elastic.co/33.0"`); - expect(compile(url, { value: 32.555 })).toMatchInlineSnapshot(`"https://elastic.co/32.6"`); + expect(await compile(url, { value: 32.9999 })).toMatchInlineSnapshot( + `"https://elastic.co/33.0"` + ); + expect(await compile(url, { value: 32.555 })).toMatchInlineSnapshot( + `"https://elastic.co/32.6"` + ); }); - test("doesn't fail on Nan", () => { + test("doesn't fail on Nan", async () => { const url = 'https://elastic.co/{{formatNumber value "0.0"}}'; - expect(compile(url, { value: null })).toMatchInlineSnapshot(`"https://elastic.co/"`); - expect(compile(url, { value: undefined })).toMatchInlineSnapshot(`"https://elastic.co/"`); - expect(compile(url, { value: 'not a number' })).toMatchInlineSnapshot( + expect(await compile(url, { value: null })).toMatchInlineSnapshot(`"https://elastic.co/"`); + expect(await compile(url, { value: undefined })).toMatchInlineSnapshot(`"https://elastic.co/"`); + expect(await compile(url, { value: 'not a number' })).toMatchInlineSnapshot( `"https://elastic.co/not%20a%20number"` ); }); - test('fails on missing format string', () => { + test('fails on missing format string', async () => { const url = 'https://elastic.co/{{formatNumber value}}'; - expect(() => compile(url, { value: 12 })).toThrowError(); + await expect(() => compile(url, { value: 12 })).rejects; }); // this doesn't work and doesn't seem // possible to validate with our version of numeral - test.skip('fails on malformed format string', () => { + test.skip('fails on malformed format string', async () => { const url = 'https://elastic.co/{{formatNumber value "not a real format string"}}'; - expect(() => compile(url, { value: 12 })).toThrowError(); + await expect(() => compile(url, { value: 12 })).rejects; }); }); describe('replace helper', () => { - test('replaces all occurrences', () => { + test('replaces all occurrences', async () => { const url = 'https://elastic.co/{{replace value "replace-me" "with-me"}}'; - expect(compile(url, { value: 'replace-me test replace-me' })).toMatchInlineSnapshot( + expect(await compile(url, { value: 'replace-me test replace-me' })).toMatchInlineSnapshot( `"https://elastic.co/with-me%20test%20with-me"` ); }); - test('can be used to remove a substring', () => { + test('can be used to remove a substring', async () => { const url = 'https://elastic.co/{{replace value "Label:" ""}}'; - expect(compile(url, { value: 'Label:Feature:Something' })).toMatchInlineSnapshot( + expect(await compile(url, { value: 'Label:Feature:Something' })).toMatchInlineSnapshot( `"https://elastic.co/Feature:Something"` ); }); - test('works if no matches', () => { + test('works if no matches', async () => { const url = 'https://elastic.co/{{replace value "Label:" ""}}'; - expect(compile(url, { value: 'No matches' })).toMatchInlineSnapshot( + expect(await compile(url, { value: 'No matches' })).toMatchInlineSnapshot( `"https://elastic.co/No%20matches"` ); }); - test('throws on incorrect args', () => { - expect(() => + test('throws on incorrect args', async () => { + await expect(() => compile('https://elastic.co/{{replace value "Label:"}}', { value: 'No matches' }) - ).toThrowErrorMatchingInlineSnapshot( + ).rejects.toThrowErrorMatchingInlineSnapshot( `"[replace]: \\"searchString\\" and \\"valueString\\" parameters expected to be strings, but not a string or missing"` ); - expect(() => + await expect(() => compile('https://elastic.co/{{replace value "Label:" 4}}', { value: 'No matches' }) - ).toThrowErrorMatchingInlineSnapshot( + ).rejects.toThrowErrorMatchingInlineSnapshot( `"[replace]: \\"searchString\\" and \\"valueString\\" parameters expected to be strings, but not a string or missing"` ); - expect(() => + await expect(() => compile('https://elastic.co/{{replace value 4 ""}}', { value: 'No matches' }) - ).toThrowErrorMatchingInlineSnapshot( + ).rejects.toThrowErrorMatchingInlineSnapshot( `"[replace]: \\"searchString\\" and \\"valueString\\" parameters expected to be strings, but not a string or missing"` ); - expect(() => + await expect(() => compile('https://elastic.co/{{replace value}}', { value: 'No matches' }) - ).toThrowErrorMatchingInlineSnapshot( + ).rejects.toThrowErrorMatchingInlineSnapshot( `"[replace]: \\"searchString\\" and \\"valueString\\" parameters expected to be strings, but not a string or missing"` ); }); }); describe('basic string formatting helpers', () => { - test('lowercase', () => { + test('lowercase', async () => { const compileUrl = (value: unknown) => compile('https://elastic.co/{{lowercase value}}', { value }); - expect(compileUrl('Some String Value')).toMatchInlineSnapshot( + expect(await compileUrl('Some String Value')).toMatchInlineSnapshot( `"https://elastic.co/some%20string%20value"` ); - expect(compileUrl(4)).toMatchInlineSnapshot(`"https://elastic.co/4"`); - expect(compileUrl(null)).toMatchInlineSnapshot(`"https://elastic.co/null"`); + expect(await compileUrl(4)).toMatchInlineSnapshot(`"https://elastic.co/4"`); + expect(await compileUrl(null)).toMatchInlineSnapshot(`"https://elastic.co/null"`); }); - test('uppercase', () => { + test('uppercase', async () => { const compileUrl = (value: unknown) => compile('https://elastic.co/{{uppercase value}}', { value }); - expect(compileUrl('Some String Value')).toMatchInlineSnapshot( + expect(await compileUrl('Some String Value')).toMatchInlineSnapshot( `"https://elastic.co/SOME%20STRING%20VALUE"` ); - expect(compileUrl(4)).toMatchInlineSnapshot(`"https://elastic.co/4"`); - expect(compileUrl(null)).toMatchInlineSnapshot(`"https://elastic.co/NULL"`); + expect(await compileUrl(4)).toMatchInlineSnapshot(`"https://elastic.co/4"`); + expect(await compileUrl(null)).toMatchInlineSnapshot(`"https://elastic.co/NULL"`); }); - test('trim', () => { + test('trim', async () => { const compileUrl = (fn: 'trim' | 'trimLeft' | 'trimRight', value: unknown) => compile(`https://elastic.co/{{${fn} value}}`, { value }); - expect(compileUrl('trim', ' trim-me ')).toMatchInlineSnapshot(`"https://elastic.co/trim-me"`); - expect(compileUrl('trimRight', ' trim-me ')).toMatchInlineSnapshot( + expect(await compileUrl('trim', ' trim-me ')).toMatchInlineSnapshot( + `"https://elastic.co/trim-me"` + ); + expect(await compileUrl('trimRight', ' trim-me ')).toMatchInlineSnapshot( `"https://elastic.co/%20%20trim-me"` ); - expect(compileUrl('trimLeft', ' trim-me ')).toMatchInlineSnapshot( + expect(await compileUrl('trimLeft', ' trim-me ')).toMatchInlineSnapshot( `"https://elastic.co/trim-me%20%20"` ); }); - test('left,right,mid', () => { + test('left,right,mid', async () => { const compileExpression = (expression: string, value: unknown) => compile(`https://elastic.co/${expression}`, { value }); - expect(compileExpression('{{left value 3}}', '12345')).toMatchInlineSnapshot( + expect(await compileExpression('{{left value 3}}', '12345')).toMatchInlineSnapshot( `"https://elastic.co/123"` ); - expect(compileExpression('{{right value 3}}', '12345')).toMatchInlineSnapshot( + expect(await compileExpression('{{right value 3}}', '12345')).toMatchInlineSnapshot( `"https://elastic.co/345"` ); - expect(compileExpression('{{mid value 1 3}}', '12345')).toMatchInlineSnapshot( + expect(await compileExpression('{{mid value 1 3}}', '12345')).toMatchInlineSnapshot( `"https://elastic.co/234"` ); }); - test('concat', () => { + test('concat', async () => { expect( - compile(`https://elastic.co/{{concat value1 "," value2}}`, { value1: 'v1', value2: 'v2' }) + await compile(`https://elastic.co/{{concat value1 "," value2}}`, { + value1: 'v1', + value2: 'v2', + }) ).toMatchInlineSnapshot(`"https://elastic.co/v1,v2"`); expect( - compile(`https://elastic.co/{{concat valueArray}}`, { valueArray: ['1', '2', '3'] }) + await compile(`https://elastic.co/{{concat valueArray}}`, { valueArray: ['1', '2', '3'] }) ).toMatchInlineSnapshot(`"https://elastic.co/1,2,3"`); }); - test('split', () => { + test('split', async () => { expect( - compile( + await compile( `https://elastic.co/{{lookup (split value ",") 0 }}&{{lookup (split value ",") 1 }}`, { value: '47.766201,-122.257057', @@ -305,8 +318,10 @@ describe('basic string formatting helpers', () => { ) ).toMatchInlineSnapshot(`"https://elastic.co/47.766201&-122.257057"`); - expect(() => + await expect(() => compile(`https://elastic.co/{{split value}}`, { value: '47.766201,-122.257057' }) - ).toThrowErrorMatchingInlineSnapshot(`"[split] \\"splitter\\" expected to be a string"`); + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"[split] \\"splitter\\" expected to be a string"` + ); }); }); diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.ts index b724435a7d992..cccc7ac8b68dd 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_template.ts @@ -5,130 +5,19 @@ * 2.0. */ -import { create as createHandlebars, HelperDelegate, HelperOptions } from 'handlebars'; -import { encode, RisonValue } from 'rison-node'; -import dateMath from '@elastic/datemath'; -import moment, { Moment } from 'moment'; -import numeral from '@elastic/numeral'; -import { url } from '../../../../../../src/plugins/kibana_utils/public'; - -const handlebars = createHandlebars(); - -function createSerializationHelper( - fnName: string, - serializeFn: (value: unknown) => string -): HelperDelegate { - return (...args) => { - const { hash } = args.slice(-1)[0] as HelperOptions; - const hasHash = Object.keys(hash).length > 0; - const hasValues = args.length > 1; - if (hasHash && hasValues) { - throw new Error(`[${fnName}]: both value list and hash are not supported`); - } - if (hasHash) { - if (Object.values(hash).some((v) => typeof v === 'undefined')) - throw new Error(`[${fnName}]: unknown variable`); - return serializeFn(hash); - } else { - const values = args.slice(0, -1) as unknown[]; - if (values.some((value) => typeof value === 'undefined')) - throw new Error(`[${fnName}]: unknown variable`); - if (values.length === 0) throw new Error(`[${fnName}]: unknown variable`); - if (values.length === 1) return serializeFn(values[0]); - return serializeFn(values); - } - }; -} - -handlebars.registerHelper('json', createSerializationHelper('json', JSON.stringify)); -handlebars.registerHelper( - 'rison', - createSerializationHelper('rison', (v) => encode(v as RisonValue)) -); - -handlebars.registerHelper('date', (...args) => { - const values = args.slice(0, -1) as [string | Date, string | undefined]; - // eslint-disable-next-line prefer-const - let [date, format] = values; - if (typeof date === 'undefined') throw new Error(`[date]: unknown variable`); - let momentDate: Moment | undefined; - if (typeof date === 'string') { - momentDate = dateMath.parse(date); - if (!momentDate || !momentDate.isValid()) { - const ts = Number(date); - if (!Number.isNaN(ts)) { - momentDate = moment(ts); - } +export async function compile( + urlTemplate: string, + context: object, + doEncode: boolean = true +): Promise { + const handlebarsTemplate = (await import('./handlebars').then((m) => m.handlebars)).compile( + urlTemplate, + { + strict: true, + noEscape: true, } - } else { - momentDate = moment(date); - } - - if (!momentDate || !momentDate.isValid()) { - // do not throw error here, because it could be that in preview `__testValue__` is not parsable, - // but in runtime it is - return date; - } - return format ? momentDate.format(format) : momentDate.toISOString(); -}); - -handlebars.registerHelper('formatNumber', (rawValue: unknown, pattern: string) => { - if (!pattern || typeof pattern !== 'string') - throw new Error(`[formatNumber]: pattern string is required`); - const value = Number(rawValue); - if (rawValue == null || Number.isNaN(value)) return rawValue; - return numeral(value).format(pattern); -}); - -handlebars.registerHelper('lowercase', (rawValue: unknown) => String(rawValue).toLowerCase()); -handlebars.registerHelper('uppercase', (rawValue: unknown) => String(rawValue).toUpperCase()); -handlebars.registerHelper('trim', (rawValue: unknown) => String(rawValue).trim()); -handlebars.registerHelper('trimLeft', (rawValue: unknown) => String(rawValue).trimLeft()); -handlebars.registerHelper('trimRight', (rawValue: unknown) => String(rawValue).trimRight()); -handlebars.registerHelper('left', (rawValue: unknown, numberOfChars: number) => { - if (typeof numberOfChars !== 'number') - throw new Error('[left]: expected "number of characters to extract" to be a number'); - return String(rawValue).slice(0, numberOfChars); -}); -handlebars.registerHelper('right', (rawValue: unknown, numberOfChars: number) => { - if (typeof numberOfChars !== 'number') - throw new Error('[left]: expected "number of characters to extract" to be a number'); - return String(rawValue).slice(-numberOfChars); -}); -handlebars.registerHelper('mid', (rawValue: unknown, start: number, length: number) => { - if (typeof start !== 'number') throw new Error('[left]: expected "start" to be a number'); - if (typeof length !== 'number') throw new Error('[left]: expected "length" to be a number'); - return String(rawValue).substr(start, length); -}); -handlebars.registerHelper('concat', (...args) => { - const values = args.slice(0, -1) as unknown[]; - return values.join(''); -}); -handlebars.registerHelper('split', (...args) => { - const [str, splitter] = args.slice(0, -1) as [string, string]; - if (typeof splitter !== 'string') throw new Error('[split] "splitter" expected to be a string'); - return String(str).split(splitter); -}); -handlebars.registerHelper('replace', (...args) => { - const [str, searchString, valueString] = args.slice(0, -1) as [string, string, string]; - if (typeof searchString !== 'string' || typeof valueString !== 'string') - throw new Error( - '[replace]: "searchString" and "valueString" parameters expected to be strings, but not a string or missing' - ); - return String(str).split(searchString).join(valueString); -}); - -handlebars.registerHelper('encodeURIComponent', (component: unknown) => { - const str = String(component); - return encodeURIComponent(str); -}); -handlebars.registerHelper('encodeURIQuery', (component: unknown) => { - const str = String(component); - return url.encodeUriQuery(str); -}); + ); -export function compile(urlTemplate: string, context: object, doEncode: boolean = true): string { - const handlebarsTemplate = handlebars.compile(urlTemplate, { strict: true, noEscape: true }); let processedUrl: string = handlebarsTemplate(context); if (doEncode) { diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_validation.test.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_validation.test.ts index c348d763e4174..78379b3495919 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_validation.test.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_validation.test.ts @@ -62,27 +62,37 @@ describe('validateUrl', () => { }); describe('validateUrlTemplate', () => { - test('domain in variable is allowed', () => { + test('domain in variable is allowed', async () => { expect( - validateUrlTemplate( - { template: '{{kibanaUrl}}/test' }, - { kibanaUrl: 'http://localhost:5601/app' } + ( + await validateUrlTemplate( + { template: '{{kibanaUrl}}/test' }, + { kibanaUrl: 'http://localhost:5601/app' } + ) ).isValid ).toBe(true); }); - test('unsafe domain in variable is not allowed', () => { + test('unsafe domain in variable is not allowed', async () => { expect( - // eslint-disable-next-line no-script-url - validateUrlTemplate({ template: '{{kibanaUrl}}/test' }, { kibanaUrl: 'javascript:evil()' }) - .isValid + ( + await validateUrlTemplate( + { template: '{{kibanaUrl}}/test' }, + // eslint-disable-next-line no-script-url + { kibanaUrl: 'javascript:evil()' } + ) + ).isValid ).toBe(false); }); - test('if missing variable then invalid', () => { + test('if missing variable then invalid', async () => { expect( - validateUrlTemplate({ template: '{{url}}/test' }, { kibanaUrl: 'http://localhost:5601/app' }) - .isValid + ( + await validateUrlTemplate( + { template: '{{url}}/test' }, + { kibanaUrl: 'http://localhost:5601/app' } + ) + ).isValid ).toBe(false); }); }); diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_validation.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_validation.ts index 8e2b39862f26a..860e6f96cc782 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_validation.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/url_validation.ts @@ -50,10 +50,10 @@ export function validateUrl(url: string): { isValid: boolean; error?: string } { } } -export function validateUrlTemplate( +export async function validateUrlTemplate( urlTemplate: UrlDrilldownConfig['url'], scope: UrlDrilldownScope -): { isValid: boolean; error?: string } { +): Promise<{ isValid: boolean; error?: string }> { if (!urlTemplate.template) return { isValid: false, @@ -61,7 +61,7 @@ export function validateUrlTemplate( }; try { - const compiledUrl = compile(urlTemplate.template, scope); + const compiledUrl = await compile(urlTemplate.template, scope); return validateUrl(compiledUrl); } catch (e) { return { diff --git a/x-pack/plugins/ui_actions_enhanced/public/index.ts b/x-pack/plugins/ui_actions_enhanced/public/index.ts index 8b4b43d54db89..3135cf44a7aa9 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/index.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/index.ts @@ -5,9 +5,6 @@ * 2.0. */ -// TODO: https://github.com/elastic/kibana/issues/109891 -/* eslint-disable @kbn/eslint/no_export_all */ - import { PluginInitializerContext } from '../../../../src/core/public'; import { AdvancedUiActionsPublicPlugin } from './plugin'; @@ -21,7 +18,6 @@ export { StartContract as AdvancedUiActionsStart, } from './plugin'; -export { ActionWizard } from './components'; export { ActionFactoryDefinition as UiActionsEnhancedActionFactoryDefinition, ActionFactory as UiActionsEnhancedActionFactory, @@ -42,4 +38,13 @@ export { DrilldownDefinition as UiActionsEnhancedDrilldownDefinition, DrilldownTemplate as UiActionsEnhancedDrilldownTemplate, } from './drilldowns'; -export * from './drilldowns/url_drilldown'; +export { + urlDrilldownCompileUrl, + UrlDrilldownCollectConfig, + UrlDrilldownConfig, + UrlDrilldownGlobalScope, + urlDrilldownGlobalScopeProvider, + UrlDrilldownScope, + urlDrilldownValidateUrl, + urlDrilldownValidateUrlTemplate, +} from './drilldowns/url_drilldown'; diff --git a/x-pack/plugins/upgrade_assistant/public/plugin.ts b/x-pack/plugins/upgrade_assistant/public/plugin.ts index 3aa712573f0c2..5edb638e1bc5b 100644 --- a/x-pack/plugins/upgrade_assistant/public/plugin.ts +++ b/x-pack/plugins/upgrade_assistant/public/plugin.ts @@ -17,11 +17,7 @@ export class UpgradeAssistantUIPlugin { constructor(private ctx: PluginInitializerContext) {} setup(coreSetup: CoreSetup, { management, cloud }: SetupDependencies) { - const { enabled, readonly } = this.ctx.config.get(); - - if (!enabled) { - return; - } + const { readonly } = this.ctx.config.get(); const appRegistrar = management.sections.section.stack; const kibanaVersion = new SemVer(this.ctx.env.packageInfo.version); diff --git a/x-pack/plugins/upgrade_assistant/server/index.ts b/x-pack/plugins/upgrade_assistant/server/index.ts index 035a6515de152..5591276b2fa34 100644 --- a/x-pack/plugins/upgrade_assistant/server/index.ts +++ b/x-pack/plugins/upgrade_assistant/server/index.ts @@ -14,9 +14,9 @@ export const plugin = (ctx: PluginInitializerContext) => { }; export const config: PluginConfigDescriptor = { + deprecations: ({ deprecate }) => [deprecate('enabled', '8.0.0')], schema: configSchema, exposeToBrowser: { - enabled: true, readonly: true, }, }; diff --git a/x-pack/plugins/uptime/common/constants/ui.ts b/x-pack/plugins/uptime/common/constants/ui.ts index 29df2614d0617..659d5727abc0c 100644 --- a/x-pack/plugins/uptime/common/constants/ui.ts +++ b/x-pack/plugins/uptime/common/constants/ui.ts @@ -17,6 +17,8 @@ export const STEP_DETAIL_ROUTE = '/journey/:checkGroupId/step/:stepIndex'; export const SYNTHETIC_CHECK_STEPS_ROUTE = '/journey/:checkGroupId/steps'; +export const MAPPING_ERROR_ROUTE = '/mapping-error'; + export enum STATUS { UP = 'up', DOWN = 'down', diff --git a/x-pack/plugins/uptime/public/apps/uptime_page_template.tsx b/x-pack/plugins/uptime/public/apps/uptime_page_template.tsx new file mode 100644 index 0000000000000..829f587e248e7 --- /dev/null +++ b/x-pack/plugins/uptime/public/apps/uptime_page_template.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import styled from 'styled-components'; +import { EuiPageHeaderProps } from '@elastic/eui'; +import { OVERVIEW_ROUTE } from '../../common/constants'; +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { ClientPluginsStart } from './plugin'; +import { useNoDataConfig } from './use_no_data_config'; +import { EmptyStateLoading } from '../components/overview/empty_state/empty_state_loading'; +import { EmptyStateError } from '../components/overview/empty_state/empty_state_error'; +import { useHasData } from '../components/overview/empty_state/use_has_data'; + +interface Props { + path: string; + pageHeader?: EuiPageHeaderProps; +} + +export const UptimePageTemplateComponent: React.FC = ({ path, pageHeader, children }) => { + const { + services: { observability }, + } = useKibana(); + + const PageTemplateComponent = observability.navigation.PageTemplate; + + const StyledPageTemplateComponent = useMemo(() => { + return styled(PageTemplateComponent)` + .euiPageHeaderContent > .euiFlexGroup { + flex-wrap: wrap; + } + `; + }, [PageTemplateComponent]); + + const noDataConfig = useNoDataConfig(); + + const { loading, error } = useHasData(); + + if (error) { + return ; + } + + return ( + <> +
    + + {loading && path === OVERVIEW_ROUTE && } +
    + {children} +
    +
    + + ); +}; diff --git a/x-pack/plugins/uptime/public/apps/use_no_data_config.ts b/x-pack/plugins/uptime/public/apps/use_no_data_config.ts new file mode 100644 index 0000000000000..dc00a25e3a111 --- /dev/null +++ b/x-pack/plugins/uptime/public/apps/use_no_data_config.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { useContext } from 'react'; +import { useSelector } from 'react-redux'; +import { KibanaPageTemplateProps, useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { UptimeSettingsContext } from '../contexts'; +import { ClientPluginsStart } from './plugin'; +import { indexStatusSelector } from '../state/selectors'; + +export function useNoDataConfig(): KibanaPageTemplateProps['noDataConfig'] { + const { basePath } = useContext(UptimeSettingsContext); + + const { + services: { docLinks }, + } = useKibana(); + + const { data } = useSelector(indexStatusSelector); + + // Returns no data config when there is no historical data + if (data && !data.indexExists) { + return { + solution: i18n.translate('xpack.uptime.noDataConfig.solutionName', { + defaultMessage: 'Observability', + }), + actions: { + beats: { + title: i18n.translate('xpack.uptime.noDataConfig.beatsCard.title', { + defaultMessage: 'Add monitors with Heartbeat', + }), + description: i18n.translate('xpack.uptime.noDataConfig.beatsCard.description', { + defaultMessage: + 'Proactively monitor the availability of your sites and services. Receive alerts and resolve issues faster to optimize your users experience.', + }), + href: basePath + `/app/home#/tutorial/uptimeMonitors`, + }, + }, + docsLink: docLinks!.links.observability.guide, + }; + } +} diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.test.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.test.tsx deleted file mode 100644 index caff055ce987c..0000000000000 --- a/x-pack/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { screen } from '@testing-library/react'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { render } from '../../../lib/helper/rtl_helpers'; -import { DataOrIndexMissing } from './data_or_index_missing'; - -describe('DataOrIndexMissing component', () => { - it('renders headingMessage', () => { - const headingMessage = ( - heartbeat-* }} - /> - ); - render(); - expect(screen.getByText(/heartbeat-*/)).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.tsx deleted file mode 100644 index 44e55de990bbf..0000000000000 --- a/x-pack/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.tsx +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiFlexGroup, - EuiEmptyPrompt, - EuiFlexItem, - EuiSpacer, - EuiPanel, - EuiTitle, - EuiButton, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useContext } from 'react'; -import { UptimeSettingsContext } from '../../../contexts'; -import { DynamicSettings } from '../../../../common/runtime_types'; - -interface DataMissingProps { - headingMessage: JSX.Element; - settings?: DynamicSettings; -} - -export const DataOrIndexMissing = ({ headingMessage, settings }: DataMissingProps) => { - const { basePath } = useContext(UptimeSettingsContext); - return ( - - - - - -

    {headingMessage}

    - - } - body={ - <> -

    - -

    -

    - -

    - - } - actions={ - - - - - - - - - - - - - } - /> -
    -
    -
    - ); -}; diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.test.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.test.tsx deleted file mode 100644 index 45b107928d79a..0000000000000 --- a/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.test.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { screen } from '@testing-library/react'; -import { EmptyStateComponent } from './empty_state'; -import { StatesIndexStatus } from '../../../../common/runtime_types'; -import { HttpFetchError, IHttpFetchError } from 'src/core/public'; -import { render } from '../../../lib/helper/rtl_helpers'; - -describe('EmptyState component', () => { - let statesIndexStatus: StatesIndexStatus; - - beforeEach(() => { - statesIndexStatus = { - indexExists: true, - docCount: 1, - indices: 'heartbeat-*,synthetics-*', - }; - }); - - it('renders child components when count is truthy', () => { - render( - -
    Foo
    -
    Bar
    -
    Baz
    -
    - ); - - expect(screen.getByText('Foo')).toBeInTheDocument(); - expect(screen.getByText('Bar')).toBeInTheDocument(); - expect(screen.getByText('Baz')).toBeInTheDocument(); - }); - - it(`doesn't render child components when count is falsy`, () => { - render( - -
    Should not be rendered
    -
    - ); - expect(screen.queryByText('Should not be rendered')).toBeNull(); - }); - - it(`renders error message when an error occurs`, () => { - const errors: IHttpFetchError[] = [ - new HttpFetchError('There was an error fetching your data.', 'error', {} as any, {} as any, { - body: { message: 'There was an error fetching your data.' }, - }), - ]; - render( - -
    Should not appear...
    -
    - ); - expect(screen.queryByText('Should not appear...')).toBeNull(); - }); - - it('renders loading state if no errors or doc count', () => { - render( - -
    Should appear even while loading...
    -
    - ); - expect(screen.queryByText('Should appear even while loading...')).toBeInTheDocument(); - }); - - it('does not render empty state with appropriate base path and no docs', () => { - statesIndexStatus = { - docCount: 0, - indexExists: true, - indices: 'heartbeat-*,synthetics-*', - }; - const text = 'If this is in the snapshot the test should fail'; - render( - -
    {text}
    -
    - ); - expect(screen.queryByText(text)).toBeNull(); - }); - - it('notifies when index does not exist', () => { - statesIndexStatus.indexExists = false; - - const text = 'This text should not render'; - - render( - -
    {text}
    -
    - ); - expect(screen.queryByText(text)).toBeNull(); - }); -}); diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.tsx deleted file mode 100644 index a6fd6579c49fa..0000000000000 --- a/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { Fragment } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { IHttpFetchError } from 'src/core/public'; -import { EmptyStateError } from './empty_state_error'; -import { EmptyStateLoading } from './empty_state_loading'; -import { DataOrIndexMissing } from './data_or_index_missing'; -import { DynamicSettings, StatesIndexStatus } from '../../../../common/runtime_types'; - -interface EmptyStateProps { - children: JSX.Element[] | JSX.Element; - statesIndexStatus: StatesIndexStatus | null; - loading: boolean; - errors?: IHttpFetchError[]; - settings?: DynamicSettings; -} - -export const EmptyStateComponent = ({ - children, - statesIndexStatus, - loading, - errors, - settings, -}: EmptyStateProps) => { - if (errors?.length) { - return ; - } - const { indexExists, docCount } = statesIndexStatus ?? {}; - - const isLoading = loading && (!indexExists || docCount === 0 || !statesIndexStatus); - - const noIndicesMessage = ( - {settings?.heartbeatIndices} }} - /> - ); - - const noUptimeDataMessage = ( - {settings?.heartbeatIndices} }} - /> - ); - - if (!indexExists && !isLoading) { - return ; - } else if (indexExists && docCount === 0 && !isLoading) { - return ; - } - /** - * We choose to render the children any time the count > 0, even if - * the component is loading. If we render the loading state for this component, - * it will blow away the state of child components and trigger an ugly - * jittery UX any time the components refresh. This way we'll keep the stale - * state displayed during the fetching process. - */ - return ( - - {isLoading && } -
    {children}
    -
    - ); - // } -}; diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_container.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_container.tsx deleted file mode 100644 index 562e45727dda7..0000000000000 --- a/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_container.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useContext, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { indexStatusAction } from '../../../state/actions'; -import { indexStatusSelector, selectDynamicSettings } from '../../../state/selectors'; -import { EmptyStateComponent } from './index'; -import { UptimeRefreshContext } from '../../../contexts'; -import { getDynamicSettings } from '../../../state/actions/dynamic_settings'; - -export const EmptyState: React.FC = ({ children }) => { - const { data, loading, error } = useSelector(indexStatusSelector); - const { lastRefresh } = useContext(UptimeRefreshContext); - - const { settings } = useSelector(selectDynamicSettings); - - const heartbeatIndices = settings?.heartbeatIndices || ''; - - const dispatch = useDispatch(); - - const noDataInfo = !data || data?.docCount === 0 || data?.indexExists === false; - - useEffect(() => { - if (noDataInfo) { - // only call when we haven't fetched it already - dispatch(indexStatusAction.get()); - } - }, [dispatch, lastRefresh, noDataInfo]); - - useEffect(() => { - // using separate side effect, we want to call index status, - // every statue indices setting changes - dispatch(indexStatusAction.get()); - }, [dispatch, heartbeatIndices]); - - useEffect(() => { - dispatch(getDynamicSettings()); - }, [dispatch]); - - return ( - - ); -}; diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/use_has_data.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/use_has_data.tsx new file mode 100644 index 0000000000000..66c68834f285f --- /dev/null +++ b/x-pack/plugins/uptime/public/components/overview/empty_state/use_has_data.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useContext, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { indexStatusAction } from '../../../state/actions'; +import { indexStatusSelector, selectDynamicSettings } from '../../../state/selectors'; +import { UptimeRefreshContext } from '../../../contexts'; +import { getDynamicSettings } from '../../../state/actions/dynamic_settings'; + +export const useHasData = () => { + const { loading, error } = useSelector(indexStatusSelector); + const { lastRefresh } = useContext(UptimeRefreshContext); + + const { settings } = useSelector(selectDynamicSettings); + + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(indexStatusAction.get()); + }, [dispatch, lastRefresh]); + + useEffect(() => { + dispatch(getDynamicSettings()); + }, [dispatch]); + + return { + error, + loading, + settings, + }; +}; diff --git a/x-pack/plugins/uptime/public/components/overview/index.ts b/x-pack/plugins/uptime/public/components/overview/index.ts index d647c38cee1ca..6ff4524df5277 100644 --- a/x-pack/plugins/uptime/public/components/overview/index.ts +++ b/x-pack/plugins/uptime/public/components/overview/index.ts @@ -6,6 +6,5 @@ */ export * from './monitor_list'; -export * from './empty_state'; export * from './alerts'; export * from './snapshot'; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx index 835a89e8f7272..726ef59827f9e 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx @@ -13,6 +13,7 @@ import { MonitorListComponent } from './monitor_list'; import { useUrlParams } from '../../../hooks'; import { UptimeRefreshContext } from '../../../contexts'; import { getConnectorsAction, getMonitorAlertsAction } from '../../../state/alerts/alerts'; +import { useMappingCheck } from '../../../hooks/use_mapping_check'; export interface MonitorListProps { filters?: string; @@ -41,6 +42,7 @@ export const MonitorList: React.FC = (props) => { const { lastRefresh } = useContext(UptimeRefreshContext); const monitorList = useSelector(monitorListSelector); + useMappingCheck(monitorList.error); useEffect(() => { dispatch( diff --git a/x-pack/plugins/uptime/public/hooks/use_mapping_check.test.ts b/x-pack/plugins/uptime/public/hooks/use_mapping_check.test.ts new file mode 100644 index 0000000000000..5f17e65d102b4 --- /dev/null +++ b/x-pack/plugins/uptime/public/hooks/use_mapping_check.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { shouldRedirect } from './use_mapping_check'; + +describe('useMappingCheck', () => { + describe('should redirect', () => { + it('returns true for appropriate error', () => { + const error = { + request: {}, + response: {}, + body: { + statusCode: 400, + error: 'Bad Request', + message: + '[search_phase_execution_exception: [illegal_argument_exception] Reason: Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [monitor.id] in order to load field data by uninverting the inverted index. Note that this can use significant memory.]: all shards failed', + }, + name: 'Error', + req: {}, + res: {}, + }; + expect(shouldRedirect(error)).toBe(true); + }); + + it('returns false for undefined', () => { + expect(shouldRedirect(undefined)).toBe(false); + }); + + it('returns false for missing body', () => { + expect(shouldRedirect({})).toBe(false); + }); + + it('returns false for incorrect error string', () => { + expect(shouldRedirect({ body: { error: 'not the right type' } })).toBe(false); + }); + + it('returns false for missing body message', () => { + expect(shouldRedirect({ body: { error: 'Bad Request' } })).toBe(false); + }); + + it('returns false for incorrect error message', () => { + expect( + shouldRedirect({ + body: { error: 'Bad Request', message: 'Not the correct kind of error message' }, + }) + ); + }); + }); +}); diff --git a/x-pack/plugins/uptime/public/hooks/use_mapping_check.ts b/x-pack/plugins/uptime/public/hooks/use_mapping_check.ts new file mode 100644 index 0000000000000..d8a7e0fac4065 --- /dev/null +++ b/x-pack/plugins/uptime/public/hooks/use_mapping_check.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect } from 'react'; +import { useHistory } from 'react-router-dom'; +import { MAPPING_ERROR_ROUTE } from '../../common/constants'; + +interface EsBadRequestError { + body?: { + error?: string; + message?: string; + }; +} + +function contains(message: string, phrase: string) { + return message.indexOf(phrase) !== -1; +} + +export function shouldRedirect(error?: EsBadRequestError) { + if (!error || !error.body || error.body.error !== 'Bad Request' || !error.body.message) { + return false; + } + const { message } = error.body; + return ( + contains(message, 'search_phase_execution_exception') || + contains(message, 'Please use a keyword field instead.') || + contains(message, 'set fielddata=true') + ); +} + +export function useMappingCheck(error?: EsBadRequestError) { + const history = useHistory(); + + useEffect(() => { + if (shouldRedirect(error)) { + history.push(MAPPING_ERROR_ROUTE); + } + }, [error, history]); +} diff --git a/x-pack/plugins/uptime/public/hooks/use_telemetry.ts b/x-pack/plugins/uptime/public/hooks/use_telemetry.ts index 05fbd349b8f0f..f5abdb473fb0d 100644 --- a/x-pack/plugins/uptime/public/hooks/use_telemetry.ts +++ b/x-pack/plugins/uptime/public/hooks/use_telemetry.ts @@ -12,6 +12,7 @@ import { API_URLS } from '../../common/constants'; export enum UptimePage { Overview = 'Overview', + MappingError = 'MappingError', Monitor = 'Monitor', Settings = 'Settings', Certificates = 'Certificates', diff --git a/x-pack/plugins/uptime/public/pages/index.ts b/x-pack/plugins/uptime/public/pages/index.ts index 5624f61c3abb5..352ceb39123e8 100644 --- a/x-pack/plugins/uptime/public/pages/index.ts +++ b/x-pack/plugins/uptime/public/pages/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +export { MappingErrorPage } from './mapping_error'; export { MonitorPage } from './monitor'; export { StepDetailPage } from './synthetics/step_detail_page'; export { SettingsPage } from './settings'; diff --git a/x-pack/plugins/uptime/public/pages/mapping_error.tsx b/x-pack/plugins/uptime/public/pages/mapping_error.tsx new file mode 100644 index 0000000000000..9c234700136b0 --- /dev/null +++ b/x-pack/plugins/uptime/public/pages/mapping_error.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCode, EuiEmptyPrompt, EuiLink, EuiTitle } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import React from 'react'; + +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; +import { useTrackPageview } from '../../../observability/public'; + +export const MappingErrorPage = () => { + useTrackPageview({ app: 'uptime', path: 'mapping-error' }); + useTrackPageview({ app: 'uptime', path: 'mapping-error', delay: 15000 }); + + const docLinks = useKibana().services.docLinks; + + useBreadcrumbs([ + { + text: i18n.translate('xpack.uptime.mappingErrorRoute.breadcrumb', { + defaultMessage: 'Mapping error', + }), + }, + ]); + + return ( + +

    + +

    + + } + body={ +
    +

    + setup }} + /> +

    + {docLinks && ( +

    + + docs + + ), + }} + /> +

    + )} +
    + } + /> + ); +}; diff --git a/x-pack/plugins/uptime/public/pages/overview.tsx b/x-pack/plugins/uptime/public/pages/overview.tsx index c350c8e1c962f..5199eab00f09f 100644 --- a/x-pack/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/plugins/uptime/public/pages/overview.tsx @@ -12,7 +12,6 @@ import styled from 'styled-components'; import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; import { useTrackPageview } from '../../../observability/public'; import { MonitorList } from '../components/overview/monitor_list/monitor_list_container'; -import { EmptyState } from '../components/overview'; import { StatusPanel } from '../components/overview/status_panel'; import { QueryBar } from '../components/overview/query_bar/query_bar'; import { MONITORING_OVERVIEW_LABEL } from '../routes'; @@ -37,7 +36,7 @@ export const OverviewPageComponent = () => { useBreadcrumbs([{ text: MONITORING_OVERVIEW_LABEL }]); // No extra breadcrumbs on overview return ( - + <> @@ -48,6 +47,6 @@ export const OverviewPageComponent = () => { - + ); }; diff --git a/x-pack/plugins/uptime/public/routes.tsx b/x-pack/plugins/uptime/public/routes.tsx index d111d44f08c2d..9f7310b43e556 100644 --- a/x-pack/plugins/uptime/public/routes.tsx +++ b/x-pack/plugins/uptime/public/routes.tsx @@ -6,19 +6,19 @@ */ import React, { FC, useEffect } from 'react'; -import styled from 'styled-components'; import { Route, Switch } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { CERTIFICATES_ROUTE, + MAPPING_ERROR_ROUTE, MONITOR_ROUTE, OVERVIEW_ROUTE, SETTINGS_ROUTE, STEP_DETAIL_ROUTE, SYNTHETIC_CHECK_STEPS_ROUTE, } from '../common/constants'; -import { MonitorPage, StepDetailPage, NotFoundPage, SettingsPage } from './pages'; +import { MappingErrorPage, MonitorPage, StepDetailPage, NotFoundPage, SettingsPage } from './pages'; import { CertificatesPage } from './pages/certificates'; import { UptimePage, useUptimeTelemetry } from './hooks'; import { OverviewPageComponent } from './pages/overview'; @@ -27,10 +27,8 @@ import { SyntheticsCheckStepsPageHeader, SyntheticsCheckStepsPageRightSideItem, } from './pages/synthetics/synthetics_checks'; -import { ClientPluginsStart } from './apps/plugin'; import { MonitorPageTitle, MonitorPageTitleContent } from './components/monitor/monitor_title'; import { UptimeDatePicker } from './components/common/uptime_date_picker'; -import { useKibana } from '../../../../src/plugins/kibana_react/public'; import { CertRefreshBtn } from './components/certificates/cert_refresh_btn'; import { CertificateTitle } from './components/certificates/certificate_title'; import { SyntheticsCallout } from './components/overview/synthetics_callout'; @@ -40,6 +38,7 @@ import { StepDetailPageHeader, StepDetailPageRightSideItem, } from './pages/synthetics/step_detail_page'; +import { UptimePageTemplateComponent } from './apps/uptime_page_template'; interface RouteProps { path: string; @@ -144,6 +143,26 @@ const Routes: RouteProps[] = [ rightSideItems: [], }, }, + { + title: i18n.translate('xpack.uptime.mappingErrorRoute.title', { + defaultMessage: 'Synthetics | mapping error', + }), + path: MAPPING_ERROR_ROUTE, + component: MappingErrorPage, + dataTestSubj: 'uptimeMappingErrorPage', + telemetryId: UptimePage.MappingError, + pageHeader: { + pageTitle: ( +
    + +
    + ), + rightSideItems: [], + }, + }, ]; const RouteInit: React.FC> = ({ @@ -159,17 +178,6 @@ const RouteInit: React.FC> = }; export const PageRouter: FC = () => { - const { - services: { observability }, - } = useKibana(); - const PageTemplateComponent = observability.navigation.PageTemplate; - - const StyledPageTemplateComponent = styled(PageTemplateComponent)` - .euiPageHeaderContent > .euiFlexGroup { - flex-wrap: wrap; - } - `; - return ( {Routes.map( @@ -178,9 +186,9 @@ export const PageRouter: FC = () => {
    - + - +
    ) diff --git a/x-pack/plugins/uptime/server/rest_api/monitors/monitor_list.ts b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_list.ts index d28645bcb21a1..36bc5a80ef47a 100644 --- a/x-pack/plugins/uptime/server/rest_api/monitors/monitor_list.ts +++ b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_list.ts @@ -27,7 +27,7 @@ export const createMonitorListRoute: UMRestApiRouteFactory = (libs) => ({ options: { tags: ['access:uptime-read'], }, - handler: async ({ uptimeEsClient, request }): Promise => { + handler: async ({ uptimeEsClient, request, response }): Promise => { const { dateRangeStart, dateRangeEnd, filters, pagination, statusFilter, pageSize, query } = request.query; @@ -35,20 +35,29 @@ export const createMonitorListRoute: UMRestApiRouteFactory = (libs) => ({ ? JSON.parse(decodeURIComponent(pagination)) : CONTEXT_DEFAULTS.CURSOR_PAGINATION; - const result = await libs.requests.getMonitorStates({ - uptimeEsClient, - dateRangeStart, - dateRangeEnd, - pagination: decodedPagination, - pageSize, - filters, - query, - // this is added to make typescript happy, - // this sort of reassignment used to be further downstream but I've moved it here - // because this code is going to be decomissioned soon - statusFilter: statusFilter || undefined, - }); + try { + const result = await libs.requests.getMonitorStates({ + uptimeEsClient, + dateRangeStart, + dateRangeEnd, + pagination: decodedPagination, + pageSize, + filters, + query, + statusFilter, + }); - return result; + return result; + } catch (e) { + /** + * This particular error is usually indicative of a mapping problem within the user's + * indices. It's relevant for the UI because we will be able to provide the user with a + * tailored message to help them remediate this problem on their own with minimal effort. + */ + if (e.name === 'ResponseError') { + return response.badRequest({ body: e }); + } + throw e; + } }, }); diff --git a/x-pack/test/api_integration/apis/metrics_ui/constants.ts b/x-pack/test/api_integration/apis/metrics_ui/constants.ts index f0ba9b4c368d5..2ca89f2f9ab87 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/constants.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/constants.ts @@ -31,7 +31,8 @@ export const DATES = { 'alert-test-data': { gauge: { min: 1609459200000, // '2022-01-01T00:00:00Z' - max: 1609462800000, // '2021-01-01T01:00:00Z' + max: 1609462800000, // '2021-01-01T01:00:00Z', + midpoint: 1609461000000, // '2021-01-01T00:30:00Z' }, rate: { min: 1609545600000, // '2021-01-02T00:00:00Z' diff --git a/x-pack/test/api_integration/apis/metrics_ui/metric_threshold_alert.ts b/x-pack/test/api_integration/apis/metrics_ui/metric_threshold_alert.ts index 28910bbc6b0c8..66c40e2e6e92d 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/metric_threshold_alert.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/metric_threshold_alert.ts @@ -100,7 +100,7 @@ export default function ({ getService }: FtrProviderContext) { ], }; const timeFrame = { end: gauge.max }; - const results = await evaluateAlert(esClient, params, configuration, timeFrame); + const results = await evaluateAlert(esClient, params, configuration, [], timeFrame); expect(results).to.eql([ { '*': { @@ -123,7 +123,7 @@ export default function ({ getService }: FtrProviderContext) { it('should alert on the last value when the end date is the same as the last event', async () => { const params = { ...baseParams }; const timeFrame = { end: gauge.max }; - const results = await evaluateAlert(esClient, params, configuration, timeFrame); + const results = await evaluateAlert(esClient, params, configuration, [], timeFrame); expect(results).to.eql([ { '*': { @@ -160,7 +160,7 @@ export default function ({ getService }: FtrProviderContext) { ], }; const timeFrame = { end: gauge.max }; - const results = await evaluateAlert(esClient, params, configuration, timeFrame); + const results = await evaluateAlert(esClient, params, configuration, [], timeFrame); expect(results).to.eql([ { dev: { @@ -200,7 +200,7 @@ export default function ({ getService }: FtrProviderContext) { groupBy: ['env'], }; const timeFrame = { end: gauge.max }; - const results = await evaluateAlert(esClient, params, configuration, timeFrame); + const results = await evaluateAlert(esClient, params, configuration, [], timeFrame); expect(results).to.eql([ { dev: { @@ -234,6 +234,53 @@ export default function ({ getService }: FtrProviderContext) { }, ]); }); + + it('should report no data when one of the groups has a data gap', async () => { + const params = { + ...baseParams, + groupBy: ['env'], + }; + const timeFrame = { end: gauge.midpoint }; + const results = await evaluateAlert( + esClient, + params, + configuration, + ['dev', 'prod'], + timeFrame + ); + expect(results).to.eql([ + { + dev: { + timeSize: 5, + timeUnit: 'm', + threshold: [1], + comparator: '>=', + aggType: 'sum', + metric: 'value', + currentValue: null, + timestamp: '2021-01-01T00:25:00.000Z', + shouldFire: [false], + shouldWarn: [false], + isNoData: [true], + isError: false, + }, + prod: { + timeSize: 5, + timeUnit: 'm', + threshold: [1], + comparator: '>=', + aggType: 'sum', + metric: 'value', + currentValue: 0, + timestamp: '2021-01-01T00:25:00.000Z', + shouldFire: [false], + shouldWarn: [false], + isNoData: [false], + isError: false, + }, + }, + ]); + }); }); }); @@ -254,7 +301,7 @@ export default function ({ getService }: FtrProviderContext) { ], }; const timeFrame = { end: rate.max }; - const results = await evaluateAlert(esClient, params, configuration, timeFrame); + const results = await evaluateAlert(esClient, params, configuration, [], timeFrame); expect(results).to.eql([ { '*': { @@ -294,7 +341,7 @@ export default function ({ getService }: FtrProviderContext) { ], }; const timeFrame = { end: rate.max }; - const results = await evaluateAlert(esClient, params, configuration, timeFrame); + const results = await evaluateAlert(esClient, params, configuration, [], timeFrame); expect(results).to.eql([ { dev: { diff --git a/x-pack/test/api_integration/apis/search/search.ts b/x-pack/test/api_integration/apis/search/search.ts index 82b62a61a932d..45e8933bf715f 100644 --- a/x-pack/test/api_integration/apis/search/search.ts +++ b/x-pack/test/api_integration/apis/search/search.ts @@ -14,7 +14,8 @@ export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); describe('search', () => { - describe('post', () => { + // https://github.com/elastic/kibana/issues/113082 + describe.skip('post', () => { it('should return 200 with final response if wait_for_completion_timeout is long enough', async () => { const resp = await supertest .post(`/internal/search/ese`) diff --git a/x-pack/test/api_integration/apis/security_solution/timeline_migrations.ts b/x-pack/test/api_integration/apis/security_solution/timeline_migrations.ts index 9863ebb7ba646..1bfefe04239e2 100644 --- a/x-pack/test/api_integration/apis/security_solution/timeline_migrations.ts +++ b/x-pack/test/api_integration/apis/security_solution/timeline_migrations.ts @@ -6,18 +6,28 @@ */ import expect from '@kbn/expect'; -import { SavedTimeline } from '../../../../plugins/security_solution/common/types/timeline'; -import { SavedNote } from '../../../../plugins/security_solution/common/types/timeline/note'; +import { + noteSavedObjectType, + pinnedEventSavedObjectType, + timelineSavedObjectType, +} from '../../../../plugins/security_solution/server/lib/timeline/saved_object_mappings'; +import { TimelineWithoutExternalRefs } from '../../../../plugins/security_solution/common/types/timeline'; +import { NoteWithoutExternalRefs } from '../../../../plugins/security_solution/common/types/timeline/note'; import { FtrProviderContext } from '../../ftr_provider_context'; import { getSavedObjectFromES } from './utils'; +import { PinnedEventWithoutExternalRefs } from '../../../../plugins/security_solution/common/types/timeline/pinned_event'; interface TimelineWithoutSavedQueryId { - 'siem-ui-timeline': Omit; + [timelineSavedObjectType]: TimelineWithoutExternalRefs; } interface NoteWithoutTimelineId { - 'siem-ui-timeline-note': Omit; + [noteSavedObjectType]: NoteWithoutExternalRefs; +} + +interface PinnedEventWithoutTimelineId { + [pinnedEventSavedObjectType]: PinnedEventWithoutExternalRefs; } export default function ({ getService }: FtrProviderContext) { @@ -28,23 +38,22 @@ export default function ({ getService }: FtrProviderContext) { const es = getService('es'); describe('7.16.0', () => { - describe('notes timelineId', () => { - before(async () => { - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timelines/7.15.0' - ); - }); - - after(async () => { - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timelines/7.15.0' - ); - }); + before(async () => { + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timelines/7.15.0' + ); + }); + after(async () => { + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timelines/7.15.0' + ); + }); + describe('notes timelineId', () => { it('removes the timelineId in the saved object', async () => { const timelines = await getSavedObjectFromES( es, - 'siem-ui-timeline-note', + noteSavedObjectType, { ids: { values: [ @@ -55,13 +64,13 @@ export default function ({ getService }: FtrProviderContext) { } ); - expect( - timelines.body.hits.hits[0]._source?.['siem-ui-timeline-note'] - ).to.not.have.property('timelineId'); + expect(timelines.body.hits.hits[0]._source?.[noteSavedObjectType]).to.not.have.property( + 'timelineId' + ); - expect( - timelines.body.hits.hits[1]._source?.['siem-ui-timeline-note'] - ).to.not.have.property('timelineId'); + expect(timelines.body.hits.hits[1]._source?.[noteSavedObjectType]).to.not.have.property( + 'timelineId' + ); }); it('preserves the eventId in the saved object after migration', async () => { @@ -87,30 +96,18 @@ export default function ({ getService }: FtrProviderContext) { }); describe('savedQueryId', () => { - before(async () => { - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timelines/7.15.0' - ); - }); - - after(async () => { - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timelines/7.15.0' - ); - }); - it('removes the savedQueryId', async () => { const timelines = await getSavedObjectFromES( es, - 'siem-ui-timeline', + timelineSavedObjectType, { ids: { values: ['siem-ui-timeline:8dc70950-1012-11ec-9ad3-2d7c6600c0f7'] }, } ); - expect(timelines.body.hits.hits[0]._source?.['siem-ui-timeline']).to.not.have.property( - 'savedQueryId' - ); + expect( + timelines.body.hits.hits[0]._source?.[timelineSavedObjectType] + ).to.not.have.property('savedQueryId'); }); it('preserves the title in the saved object after migration', async () => { @@ -129,6 +126,57 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.body.data.getOneTimeline.savedQueryId).to.be("It's me"); }); }); + + describe('pinned events timelineId', () => { + it('removes the timelineId in the saved object', async () => { + const timelines = await getSavedObjectFromES( + es, + pinnedEventSavedObjectType, + { + ids: { + values: [ + 'siem-ui-timeline-pinned-event:7a9a5540-126e-11ec-83d2-db1096c73738', + 'siem-ui-timeline-pinned-event:98d919b0-126e-11ec-83d2-db1096c73738', + ], + }, + } + ); + + expect( + timelines.body.hits.hits[0]._source?.[pinnedEventSavedObjectType] + ).to.not.have.property('timelineId'); + + expect( + timelines.body.hits.hits[1]._source?.[pinnedEventSavedObjectType] + ).to.not.have.property('timelineId'); + }); + + it('preserves the eventId in the saved object after migration', async () => { + const resp = await supertest + .get('/api/timeline') + .query({ id: '6484cc90-126e-11ec-83d2-db1096c73738' }); + + expect(resp.body.data.getOneTimeline.pinnedEventsSaveObject[0].eventId).to.be( + 'DNo00XsBEVtyvU-8LGNe' + ); + expect(resp.body.data.getOneTimeline.pinnedEventsSaveObject[1].eventId).to.be( + 'Edo00XsBEVtyvU-8LGNe' + ); + }); + + it('returns the timelineId in the response', async () => { + const resp = await supertest + .get('/api/timeline') + .query({ id: '6484cc90-126e-11ec-83d2-db1096c73738' }); + + expect(resp.body.data.getOneTimeline.pinnedEventsSaveObject[0].timelineId).to.be( + '6484cc90-126e-11ec-83d2-db1096c73738' + ); + expect(resp.body.data.getOneTimeline.pinnedEventsSaveObject[1].timelineId).to.be( + '6484cc90-126e-11ec-83d2-db1096c73738' + ); + }); + }); }); }); } diff --git a/x-pack/test/api_integration/apis/security_solution/tls.ts b/x-pack/test/api_integration/apis/security_solution/tls.ts index 2308ad7a0bf34..9fa251ded4e6b 100644 --- a/x-pack/test/api_integration/apis/security_solution/tls.ts +++ b/x-pack/test/api_integration/apis/security_solution/tls.ts @@ -24,7 +24,7 @@ const expectedResult = { _id: '16989191B1A93ECECD5FE9E63EBD4B5C3B606D26', subjects: ['CN=edgecert.googleapis.com,O=Google LLC,L=Mountain View,ST=California,C=US'], issuers: ['CN=GTS CA 1O1,O=Google Trust Services,C=US'], - ja3: [], + ja3: ['bd12d76eb0b6787e6a78a14d2ff96c2b'], notAfter: ['2020-05-06T11:52:15.000Z'], }; @@ -41,7 +41,7 @@ const expectedOverviewDestinationResult = { 'CN=*.cdn.mozilla.net,OU=Cloud Services,O=Mozilla Corporation,L=Mountain View,ST=California,C=US', ], issuers: ['CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US'], - ja3: [], + ja3: ['b20b44b18b853ef29ab773e921b03422'], notAfter: ['2020-12-09T12:00:00.000Z'], }, }, @@ -67,7 +67,7 @@ const expectedOverviewSourceResult = { 'CN=*.cdn.mozilla.net,OU=Cloud Services,O=Mozilla Corporation,L=Mountain View,ST=California,C=US', ], issuers: ['CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US'], - ja3: [], + ja3: ['b20b44b18b853ef29ab773e921b03422'], notAfter: ['2020-12-09T12:00:00.000Z'], }, }, diff --git a/x-pack/test/api_integration/apis/transform/transforms_nodes.ts b/x-pack/test/api_integration/apis/transform/transforms_nodes.ts index ca9ab8e8a728d..0fc93289195d9 100644 --- a/x-pack/test/api_integration/apis/transform/transforms_nodes.ts +++ b/x-pack/test/api_integration/apis/transform/transforms_nodes.ts @@ -31,7 +31,7 @@ export default ({ getService }: FtrProviderContext) => { } describe('/api/transform/transforms/_nodes', function () { - it('should return the number of available transform nodes', async () => { + it('should return the number of available transform nodes for a power user', async () => { const { body } = await supertest .get('/api/transform/transforms/_nodes') .auth( @@ -44,5 +44,31 @@ export default ({ getService }: FtrProviderContext) => { assertTransformsNodesResponseBody(body); }); + + it('should return the number of available transform nodes for a viewer user', async () => { + const { body } = await supertest + .get('/api/transform/transforms/_nodes') + .auth( + USER.TRANSFORM_VIEWER, + transform.securityCommon.getPasswordForUser(USER.TRANSFORM_VIEWER) + ) + .set(COMMON_REQUEST_HEADERS) + .send() + .expect(200); + + assertTransformsNodesResponseBody(body); + }); + + it('should not return the number of available transform nodes for an unauthorized user', async () => { + await supertest + .get('/api/transform/transforms/_nodes') + .auth( + USER.TRANSFORM_UNAUTHORIZED, + transform.securityCommon.getPasswordForUser(USER.TRANSFORM_UNAUTHORIZED) + ) + .set(COMMON_REQUEST_HEADERS) + .send() + .expect(403); + }); }); }; diff --git a/x-pack/test/apm_api_integration/tests/correlations/errors_failed_transactions.ts b/x-pack/test/apm_api_integration/tests/correlations/errors_failed_transactions.ts deleted file mode 100644 index b3c5302ee2c6b..0000000000000 --- a/x-pack/test/apm_api_integration/tests/correlations/errors_failed_transactions.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { format } from 'url'; -import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; -import archives_metadata from '../../common/fixtures/es_archiver/archives_metadata'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { registry } from '../../common/registry'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const supertest = getService('legacySupertestAsApmReadUser'); - const archiveName = 'apm_8.0.0'; - const range = archives_metadata[archiveName]; - - const url = format({ - pathname: `/api/apm/correlations/errors/failed_transactions`, - query: { - start: range.start, - end: range.end, - fieldNames: 'http.response.status_code,user_agent.name,user_agent.os.name,url.original', - environment: 'ENVIRONMENT_ALL', - kuery: '', - }, - }); - registry.when( - 'correlations errors failed transactions without data', - { config: 'trial', archives: [] }, - () => { - it('handles the empty state', async () => { - const response = await supertest.get(url); - - expect(response.status).to.be(200); - expect(response.body.response).to.be(undefined); - }); - } - ); - - registry.when( - 'correlations errors failed transactions with data and default args', - { config: 'trial', archives: ['apm_8.0.0'] }, - () => { - type ResponseBody = APIReturnType<'GET /api/apm/correlations/errors/failed_transactions'>; - let response: { - status: number; - body: NonNullable; - }; - - before(async () => { - response = await supertest.get(url); - }); - - it('returns successfully', () => { - expect(response.status).to.eql(200); - }); - - it('returns significant terms', () => { - const { significantTerms } = response.body; - expect(significantTerms.length).to.be.greaterThan(0); - - const sortedFieldNames = significantTerms.map(({ fieldName }) => fieldName).sort(); - expectSnapshot(sortedFieldNames).toMatchInline(` - Array [ - "http.response.status_code", - ] - `); - }); - - it('returns a distribution per term', () => { - const { significantTerms } = response.body; - expectSnapshot(significantTerms.map((term) => term.timeseries.length)).toMatchInline(` - Array [ - 31, - ] - `); - }); - } - ); -} diff --git a/x-pack/test/apm_api_integration/tests/correlations/errors_overall.ts b/x-pack/test/apm_api_integration/tests/correlations/errors_overall.ts deleted file mode 100644 index f4e95816a3996..0000000000000 --- a/x-pack/test/apm_api_integration/tests/correlations/errors_overall.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { SupertestReturnType } from '../../common/apm_api_supertest'; -import archives_metadata from '../../common/fixtures/es_archiver/archives_metadata'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { registry } from '../../common/registry'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const apmApiClient = getService('apmApiClient'); - const archiveName = 'apm_8.0.0'; - const range = archives_metadata[archiveName]; - - const urlConfig = { - endpoint: `GET /api/apm/correlations/errors/overall_timeseries` as const, - params: { - query: { - start: range.start, - end: range.end, - environment: 'ENVIRONMENT_ALL', - kuery: '', - }, - }, - }; - - registry.when( - 'correlations errors overall without data', - { config: 'trial', archives: [] }, - () => { - it('handles the empty state', async () => { - const response = await apmApiClient.readUser(urlConfig); - - expect(response.status).to.be(200); - expect(response.body.overall).to.be(null); - }); - } - ); - - registry.when( - 'correlations errors overall with data and default args', - { config: 'trial', archives: ['apm_8.0.0'] }, - () => { - let response: SupertestReturnType<'GET /api/apm/correlations/errors/overall_timeseries'>; - - before(async () => { - response = await apmApiClient.readUser(urlConfig); - }); - - it('returns successfully', () => { - expect(response.status).to.eql(200); - }); - - it('returns overall distribution', () => { - expectSnapshot(response.body?.overall?.timeseries.length).toMatchInline(`31`); - }); - } - ); -} diff --git a/x-pack/test/apm_api_integration/tests/correlations/latency_overall.ts b/x-pack/test/apm_api_integration/tests/correlations/latency_overall.ts deleted file mode 100644 index 722a9a2bc4fb7..0000000000000 --- a/x-pack/test/apm_api_integration/tests/correlations/latency_overall.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { format } from 'url'; -import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; -import archives_metadata from '../../common/fixtures/es_archiver/archives_metadata'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { registry } from '../../common/registry'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const supertest = getService('legacySupertestAsApmReadUser'); - const archiveName = 'apm_8.0.0'; - const range = archives_metadata[archiveName]; - - const url = format({ - pathname: `/api/apm/correlations/latency/overall_distribution`, - query: { - start: range.start, - end: range.end, - environment: 'ENVIRONMENT_ALL', - kuery: '', - }, - }); - - registry.when( - 'correlations latency overall without data', - { config: 'trial', archives: [] }, - () => { - it('handles the empty state', async () => { - const response = await supertest.get(url); - - expect(response.status).to.be(200); - expect(response.body.response).to.be(undefined); - }); - } - ); - - registry.when( - 'correlations latency overall with data and default args', - { config: 'trial', archives: ['apm_8.0.0'] }, - () => { - type ResponseBody = APIReturnType<'GET /api/apm/correlations/latency/overall_distribution'>; - let response: { - status: number; - body: NonNullable; - }; - - before(async () => { - response = await supertest.get(url); - }); - - it('returns successfully', () => { - expect(response.status).to.eql(200); - }); - - it('returns overall distribution', () => { - // less precision for distributionInterval as it is not exact - expectSnapshot(response.body?.distributionInterval?.toPrecision(2)).toMatchInline( - `"3.8e+5"` - ); - expectSnapshot(response.body?.maxLatency?.toPrecision(2)).toMatchInline(`"5.8e+6"`); - expectSnapshot(response.body?.overallDistribution?.length).toMatchInline(`15`); - }); - } - ); -} diff --git a/x-pack/test/apm_api_integration/tests/correlations/latency_slow_transactions.ts b/x-pack/test/apm_api_integration/tests/correlations/latency_slow_transactions.ts deleted file mode 100644 index c72753a86f6a6..0000000000000 --- a/x-pack/test/apm_api_integration/tests/correlations/latency_slow_transactions.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { format } from 'url'; -import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; -import archives_metadata from '../../common/fixtures/es_archiver/archives_metadata'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { registry } from '../../common/registry'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const supertest = getService('legacySupertestAsApmReadUser'); - const archiveName = 'apm_8.0.0'; - const range = archives_metadata[archiveName]; - - const url = format({ - pathname: `/api/apm/correlations/latency/slow_transactions`, - query: { - start: range.start, - end: range.end, - durationPercentile: 95, - fieldNames: 'user_agent.name,user_agent.os.name,url.original', - maxLatency: 3581640.00000003, - distributionInterval: 238776, - environment: 'ENVIRONMENT_ALL', - kuery: '', - }, - }); - registry.when( - 'correlations latency slow transactions without data', - { config: 'trial', archives: [] }, - () => { - it('handles the empty state', async () => { - const response = await supertest.get(url); - - expect(response.status).to.be(200); - expect(response.body.response).to.be(undefined); - }); - } - ); - - registry.when( - 'correlations latency slow transactions with data and default args', - { config: 'trial', archives: ['apm_8.0.0'] }, - () => { - type ResponseBody = APIReturnType<'GET /api/apm/correlations/latency/slow_transactions'>; - let response: { - status: number; - body: NonNullable; - }; - - before(async () => { - response = await supertest.get(url); - }); - - it('returns successfully', () => { - expect(response.status).to.eql(200); - }); - - it('returns significant terms', () => { - const { significantTerms } = response.body; - expect(significantTerms.length).to.be.greaterThan(0); - - const sortedFieldNames = significantTerms.map(({ fieldName }) => fieldName).sort(); - expectSnapshot(sortedFieldNames).toMatchInline(` - Array [ - "url.original", - "url.original", - "url.original", - "user_agent.name", - "user_agent.name", - "user_agent.os.name", - ] - `); - }); - - it('returns a distribution per term', () => { - const { significantTerms } = response.body; - expectSnapshot(significantTerms.map((term) => term.distribution.length)).toMatchInline(` - Array [ - 15, - 15, - 15, - 15, - 15, - 15, - ] - `); - }); - } - ); -} diff --git a/x-pack/test/apm_api_integration/tests/index.ts b/x-pack/test/apm_api_integration/tests/index.ts index 6c989e61bc6bf..5ea5ad78d9479 100644 --- a/x-pack/test/apm_api_integration/tests/index.ts +++ b/x-pack/test/apm_api_integration/tests/index.ts @@ -29,10 +29,6 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte }); // correlations - describe('correlations/latency_slow_transactions', function () { - loadTestFile(require.resolve('./correlations/latency_slow_transactions')); - }); - describe('correlations/failed_transactions', function () { loadTestFile(require.resolve('./correlations/failed_transactions')); }); @@ -41,18 +37,6 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte loadTestFile(require.resolve('./correlations/latency')); }); - describe('correlations/latency_overall', function () { - loadTestFile(require.resolve('./correlations/latency_overall')); - }); - - describe('correlations/errors_overall', function () { - loadTestFile(require.resolve('./correlations/errors_overall')); - }); - - describe('correlations/errors_failed_transactions', function () { - loadTestFile(require.resolve('./correlations/errors_failed_transactions')); - }); - describe('metrics_charts/metrics_charts', function () { loadTestFile(require.resolve('./metrics_charts/metrics_charts')); }); diff --git a/x-pack/test/case_api_integration/common/config.ts b/x-pack/test/case_api_integration/common/config.ts index 887e6e7894f98..514b54982ee42 100644 --- a/x-pack/test/case_api_integration/common/config.ts +++ b/x-pack/test/case_api_integration/common/config.ts @@ -93,6 +93,8 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) .isDirectory() ); + const casesConfig = ['--xpack.cases.enabled=true']; + return { testFiles: testFiles ? testFiles : [require.resolve('../tests/common')], servers, @@ -115,6 +117,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ...xPackApiIntegrationTestsConfig.get('kbnTestServer'), serverArgs: [ ...xPackApiIntegrationTestsConfig.get('kbnTestServer.serverArgs'), + ...casesConfig, `--xpack.actions.allowedHosts=${JSON.stringify(['localhost', 'some.non.existent.com'])}`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, '--xpack.eventLog.logEntries=true', diff --git a/x-pack/test/case_api_integration/common/lib/utils.ts b/x-pack/test/case_api_integration/common/lib/utils.ts index 0021a228ee98b..7367641d71585 100644 --- a/x-pack/test/case_api_integration/common/lib/utils.ts +++ b/x-pack/test/case_api_integration/common/lib/utils.ts @@ -47,6 +47,7 @@ import { AlertResponse, ConnectorMappings, CasesByAlertId, + CaseResolveResponse, } from '../../../../plugins/cases/common/api'; import { getPostCaseRequest, postCollectionReq, postCommentGenAlertReq } from './mock'; import { getCaseUserActionUrl, getSubCasesUrl } from '../../../../plugins/cases/common/api/helpers'; @@ -1066,6 +1067,32 @@ export const getCase = async ({ return theCase; }; +export const resolveCase = async ({ + supertest, + caseId, + includeComments = false, + expectedHttpCode = 200, + auth = { user: superUser, space: null }, +}: { + supertest: SuperTest.SuperTest; + caseId: string; + includeComments?: boolean; + expectedHttpCode?: number; + auth?: { user: User; space: string | null }; +}): Promise => { + const { body: theResolvedCase } = await supertest + .get( + `${getSpaceUrlPrefix( + auth?.space + )}${CASES_URL}/${caseId}/resolve?includeComments=${includeComments}` + ) + .set('kbn-xsrf', 'true') + .auth(auth.user.username, auth.user.password) + .expect(expectedHttpCode); + + return theResolvedCase; +}; + export const findCases = async ({ supertest, query = {}, diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts index 90fbb10637434..3fb7d7a29af39 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/basic/index.ts @@ -12,7 +12,7 @@ import { createSpacesAndUsers, deleteSpacesAndUsers } from '../../../common/lib/ export default ({ loadTestFile, getService }: FtrProviderContext): void => { describe('cases security and spaces enabled: basic', function () { // Fastest ciGroup for the moment. - this.tags('ciGroup5'); + this.tags('ciGroup13'); before(async () => { await createSpacesAndUsers(getService); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/delete_cases.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/delete_cases.ts index 964e9135aba7b..68f0ba43d889b 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/delete_cases.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/delete_cases.ts @@ -85,7 +85,7 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - it('should create a user action when creating a case', async () => { + it('should create a user action when deleting a case', async () => { const postedCase = await createCase(supertest, getPostCaseRequest()); await deleteCases({ supertest, caseIDs: [postedCase.id] }); const userActions = await getCaseUserActions({ supertest, caseID: postedCase.id }); @@ -106,6 +106,8 @@ export default ({ getService }: FtrProviderContext): void => { action_by: defaultUser, old_value: null, new_value: null, + new_val_connector_id: null, + old_val_connector_id: null, case_id: `${postedCase.id}`, comment_id: null, sub_case_id: '', diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/import_export.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/import_export.ts index 4a0979c44359f..dd1c2e810f150 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/import_export.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/import_export.ts @@ -7,6 +7,8 @@ import expect from '@kbn/expect'; import { join } from 'path'; +import { SavedObject } from 'kibana/server'; +import supertest from 'supertest'; import { ObjectRemover as ActionsRemover } from '../../../../../alerting_api_integration/common/lib'; import { deleteAllCaseItems, @@ -22,16 +24,22 @@ import { CommentsResponse, CASES_URL, CaseType, + CASE_SAVED_OBJECT, + CaseAttributes, + CASE_USER_ACTION_SAVED_OBJECT, + CaseUserActionAttributes, + CASE_COMMENT_SAVED_OBJECT, + CasePostRequest, + CaseUserActionResponse, } from '../../../../../../plugins/cases/common'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { - const supertest = getService('supertest'); + const supertestService = getService('supertest'); const es = getService('es'); - // FLAKY: https://github.com/elastic/kibana/issues/112353 - describe.skip('import and export cases', () => { - const actionsRemover = new ActionsRemover(supertest); + describe('import and export cases', () => { + const actionsRemover = new ActionsRemover(supertestService); afterEach(async () => { await deleteAllCaseItems(es); @@ -40,14 +48,14 @@ export default ({ getService }: FtrProviderContext): void => { it('exports a case with its associated user actions and comments', async () => { const caseRequest = getPostCaseRequest(); - const postedCase = await createCase(supertest, caseRequest); + const postedCase = await createCase(supertestService, caseRequest); await createComment({ - supertest, + supertest: supertestService, caseId: postedCase.id, params: postCommentUserReq, }); - const { text } = await supertest + const { text } = await supertestService .post(`/api/saved_objects/_export`) .send({ type: ['cases'], @@ -60,46 +68,13 @@ export default ({ getService }: FtrProviderContext): void => { expect(objects).to.have.length(4); - // should be the case - expect(objects[0].attributes.title).to.eql(caseRequest.title); - expect(objects[0].attributes.description).to.eql(caseRequest.description); - expect(objects[0].attributes.connector.type).to.eql(caseRequest.connector.type); - expect(objects[0].attributes.connector.name).to.eql(caseRequest.connector.name); - expect(objects[0].attributes.connector.fields).to.eql([]); - expect(objects[0].attributes.settings).to.eql(caseRequest.settings); - - // should be two user actions - expect(objects[1].attributes.action).to.eql('create'); - - const parsedCaseNewValue = JSON.parse(objects[1].attributes.new_value); - const { - connector: { id: ignoreParsedId, ...restParsedConnector }, - ...restParsedCreateCase - } = parsedCaseNewValue; - - const { - connector: { id: ignoreConnectorId, ...restConnector }, - ...restCreateCase - } = caseRequest; - - expect(restParsedCreateCase).to.eql({ ...restCreateCase, type: CaseType.individual }); - expect(restParsedConnector).to.eql(restConnector); - - expect(objects[1].attributes.old_value).to.eql(null); - expect(includesAllRequiredFields(objects[1].attributes.action_field)).to.eql(true); - - // should be the comment - expect(objects[2].attributes.comment).to.eql(postCommentUserReq.comment); - expect(objects[2].attributes.type).to.eql(postCommentUserReq.type); - - expect(objects[3].attributes.action).to.eql('create'); - expect(JSON.parse(objects[3].attributes.new_value)).to.eql(postCommentUserReq); - expect(objects[3].attributes.old_value).to.eql(null); - expect(objects[3].attributes.action_field).to.eql(['comment']); + expectExportToHaveCaseSavedObject(objects, caseRequest); + expectExportToHaveUserActions(objects, caseRequest); + expectExportToHaveAComment(objects); }); it('imports a case with a comment and user actions', async () => { - await supertest + await supertestService .post('/api/saved_objects/_import') .query({ overwrite: true }) .attach( @@ -112,12 +87,12 @@ export default ({ getService }: FtrProviderContext): void => { .set('kbn-xsrf', 'true') .expect(200); - const findResponse = await findCases({ supertest, query: {} }); + const findResponse = await findCases({ supertest: supertestService, query: {} }); expect(findResponse.total).to.eql(1); expect(findResponse.cases[0].title).to.eql('A case to export'); expect(findResponse.cases[0].description).to.eql('a description'); - const { body: commentsResponse }: { body: CommentsResponse } = await supertest + const { body: commentsResponse }: { body: CommentsResponse } = await supertestService .get(`${CASES_URL}/${findResponse.cases[0].id}/comments/_find`) .send() .expect(200); @@ -126,13 +101,13 @@ export default ({ getService }: FtrProviderContext): void => { expect(comment.comment).to.eql('A comment for my case'); const userActions = await getCaseUserActions({ - supertest, + supertest: supertestService, caseID: findResponse.cases[0].id, }); expect(userActions).to.have.length(2); expect(userActions[0].action).to.eql('create'); - expect(includesAllRequiredFields(userActions[0].action_field)).to.eql(true); + expect(includesAllCreateCaseActionFields(userActions[0].action_field)).to.eql(true); expect(userActions[1].action).to.eql('create'); expect(userActions[1].action_field).to.eql(['comment']); @@ -145,7 +120,7 @@ export default ({ getService }: FtrProviderContext): void => { }); it('imports a case with a connector', async () => { - await supertest + await supertestService .post('/api/saved_objects/_import') .query({ overwrite: true }) .attach( @@ -160,51 +135,179 @@ export default ({ getService }: FtrProviderContext): void => { actionsRemover.add('default', '1cd34740-06ad-11ec-babc-0b08808e8e01', 'action', 'actions'); - const findResponse = await findCases({ supertest, query: {} }); - expect(findResponse.total).to.eql(1); - expect(findResponse.cases[0].title).to.eql('A case with a connector'); - expect(findResponse.cases[0].description).to.eql('super description'); + await expectImportToHaveOneCase(supertestService); const userActions = await getCaseUserActions({ - supertest, - caseID: findResponse.cases[0].id, + supertest: supertestService, + caseID: '2e85c3f0-06ad-11ec-babc-0b08808e8e01', }); - expect(userActions).to.have.length(3); - expect(userActions[0].action).to.eql('create'); - expect(includesAllRequiredFields(userActions[0].action_field)).to.eql(true); - expect(userActions[1].action).to.eql('push-to-service'); - expect(userActions[1].action_field).to.eql(['pushed']); - expect(userActions[1].old_value).to.eql(null); + expectImportToHaveCreateCaseUserAction(userActions[0]); + expectImportToHavePushUserAction(userActions[1]); + expectImportToHaveUpdateConnector(userActions[2]); + }); + }); +}; - const parsedPushNewValue = JSON.parse(userActions[1].new_value!); - expect(parsedPushNewValue.connector_name).to.eql('A jira connector'); - expect(parsedPushNewValue.connector_id).to.eql('1cd34740-06ad-11ec-babc-0b08808e8e01'); +const expectImportToHaveOneCase = async (supertestService: supertest.SuperTest) => { + const findResponse = await findCases({ supertest: supertestService, query: {} }); + expect(findResponse.total).to.eql(1); + expect(findResponse.cases[0].title).to.eql('A case with a connector'); + expect(findResponse.cases[0].description).to.eql('super description'); +}; - expect(userActions[2].action).to.eql('update'); - expect(userActions[2].action_field).to.eql(['connector']); +const expectImportToHaveCreateCaseUserAction = (userAction: CaseUserActionResponse) => { + expect(userAction.action).to.eql('create'); + expect(includesAllCreateCaseActionFields(userAction.action_field)).to.eql(true); +}; - const parsedUpdateNewValue = JSON.parse(userActions[2].new_value!); - expect(parsedUpdateNewValue.id).to.eql('none'); - }); - }); +const expectImportToHavePushUserAction = (userAction: CaseUserActionResponse) => { + expect(userAction.action).to.eql('push-to-service'); + expect(userAction.action_field).to.eql(['pushed']); + expect(userAction.old_value).to.eql(null); + + const parsedPushNewValue = JSON.parse(userAction.new_value!); + expect(parsedPushNewValue.connector_name).to.eql('A jira connector'); + expect(parsedPushNewValue).to.not.have.property('connector_id'); + expect(userAction.new_val_connector_id).to.eql('1cd34740-06ad-11ec-babc-0b08808e8e01'); +}; + +const expectImportToHaveUpdateConnector = (userAction: CaseUserActionResponse) => { + expect(userAction.action).to.eql('update'); + expect(userAction.action_field).to.eql(['connector']); + + const parsedUpdateNewValue = JSON.parse(userAction.new_value!); + expect(parsedUpdateNewValue).to.not.have.property('id'); + // the new val connector id is null because it is the none connector + expect(userAction.new_val_connector_id).to.eql(null); + + const parsedUpdateOldValue = JSON.parse(userAction.old_value!); + expect(parsedUpdateOldValue).to.not.have.property('id'); + expect(userAction.old_val_connector_id).to.eql('1cd34740-06ad-11ec-babc-0b08808e8e01'); }; const ndjsonToObject = (input: string) => { return input.split('\n').map((str) => JSON.parse(str)); }; -const includesAllRequiredFields = (actionFields: string[]): boolean => { - const requiredFields = [ - 'description', - 'status', - 'tags', - 'title', - 'connector', - 'settings', - 'owner', - ]; - - return requiredFields.every((field) => actionFields.includes(field)); +const expectExportToHaveCaseSavedObject = ( + objects: SavedObject[], + caseRequest: CasePostRequest +) => { + const caseSOs = findSavedObjectsByType(objects, CASE_SAVED_OBJECT); + expect(caseSOs.length).to.eql(1); + + const createdCaseSO = caseSOs[0]; + + // should be the case + expect(createdCaseSO.attributes.title).to.eql(caseRequest.title); + expect(createdCaseSO.attributes.description).to.eql(caseRequest.description); + expect(createdCaseSO.attributes.connector.type).to.eql(caseRequest.connector.type); + expect(createdCaseSO.attributes.connector.name).to.eql(caseRequest.connector.name); + expect(createdCaseSO.attributes.connector.fields).to.eql([]); + expect(createdCaseSO.attributes.settings).to.eql(caseRequest.settings); +}; + +const expectExportToHaveUserActions = (objects: SavedObject[], caseRequest: CasePostRequest) => { + const userActionSOs = findSavedObjectsByType( + objects, + CASE_USER_ACTION_SAVED_OBJECT + ); + + expect(userActionSOs.length).to.eql(2); + + expectCaseCreateUserAction(userActionSOs, caseRequest); + expectCreateCommentUserAction(userActionSOs); +}; + +const expectCaseCreateUserAction = ( + userActions: Array>, + caseRequest: CasePostRequest +) => { + const userActionForCaseCreate = findUserActionSavedObject( + userActions, + 'create', + createCaseActionFields + ); + + expect(userActionForCaseCreate?.attributes.action).to.eql('create'); + + const parsedCaseNewValue = JSON.parse(userActionForCaseCreate?.attributes.new_value as string); + const { + connector: { id: ignoreParsedId, ...restParsedConnector }, + ...restParsedCreateCase + } = parsedCaseNewValue; + + const { + connector: { id: ignoreConnectorId, ...restConnector }, + ...restCreateCase + } = caseRequest; + + expect(restParsedCreateCase).to.eql({ ...restCreateCase, type: CaseType.individual }); + expect(restParsedConnector).to.eql(restConnector); + + expect(userActionForCaseCreate?.attributes.old_value).to.eql(null); + expect( + includesAllCreateCaseActionFields(userActionForCaseCreate?.attributes.action_field) + ).to.eql(true); +}; + +const expectCreateCommentUserAction = ( + userActions: Array> +) => { + const userActionForComment = findUserActionSavedObject(userActions, 'create', ['comment']); + + expect(userActionForComment?.attributes.action).to.eql('create'); + expect(JSON.parse(userActionForComment!.attributes.new_value!)).to.eql(postCommentUserReq); + expect(userActionForComment?.attributes.old_value).to.eql(null); + expect(userActionForComment?.attributes.action_field).to.eql(['comment']); +}; + +const expectExportToHaveAComment = (objects: SavedObject[]) => { + const commentSOs = findSavedObjectsByType(objects, CASE_COMMENT_SAVED_OBJECT); + + expect(commentSOs.length).to.eql(1); + + const commentSO = commentSOs[0]; + expect(commentSO.attributes.comment).to.eql(postCommentUserReq.comment); + expect(commentSO.attributes.type).to.eql(postCommentUserReq.type); +}; + +const createCaseActionFields = [ + 'description', + 'status', + 'tags', + 'title', + 'connector', + 'settings', + 'owner', +]; + +const includesAllCreateCaseActionFields = (actionFields?: string[]): boolean => { + return createCaseActionFields.every( + (field) => actionFields != null && actionFields.includes(field) + ); +}; + +const findSavedObjectsByType = ( + savedObjects: SavedObject[], + type: string +): Array> => { + return (savedObjects.filter((so) => so.type === type) ?? []) as Array>; +}; + +const findUserActionSavedObject = ( + savedObjects: Array>, + action: string, + actionFields: string[] +): SavedObject | undefined => { + return savedObjects.find( + (so) => + so.attributes.action === action && hasAllStrings(so.attributes.action_field, actionFields) + ); +}; + +const hasAllStrings = (collection: string[], stringsToFind: string[]): boolean => { + return stringsToFind.every((str) => collection.includes(str)); }; diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/migrations.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/migrations.ts index f21a0ab460424..af8bf464c198d 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/migrations.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/migrations.ts @@ -11,7 +11,7 @@ import { CASES_URL, SECURITY_SOLUTION_OWNER, } from '../../../../../../plugins/cases/common/constants'; -import { getCase, getCaseSavedObjectsFromES } from '../../../../common/lib/utils'; +import { getCase, getCaseSavedObjectsFromES, resolveCase } from '../../../../common/lib/utils'; // eslint-disable-next-line import/no-default-export export default function createGetTests({ getService }: FtrProviderContext) { @@ -207,5 +207,76 @@ export default function createGetTests({ getService }: FtrProviderContext) { }); }); }); + + describe('7.16.0', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/cases/migrations/7.13.2'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/cases/migrations/7.13.2'); + }); + + describe('resolve', () => { + it('should return exactMatch outcome', async () => { + const { outcome } = await resolveCase({ + supertest, + caseId: 'e49ad6e0-cf9d-11eb-a603-13e7747d215c', + }); + + expect(outcome).to.be('exactMatch'); + }); + + it('should preserve the same case info', async () => { + const { case: theCase } = await resolveCase({ + supertest, + caseId: 'e49ad6e0-cf9d-11eb-a603-13e7747d215c', + }); + + expect(theCase.title).to.be('A case'); + expect(theCase.description).to.be('asdf'); + expect(theCase.owner).to.be(SECURITY_SOLUTION_OWNER); + }); + + it('should preserve the same connector', async () => { + const { case: theCase } = await resolveCase({ + supertest, + caseId: 'e49ad6e0-cf9d-11eb-a603-13e7747d215c', + }); + + expect(theCase.connector).to.eql({ + fields: { + issueType: '10002', + parent: null, + priority: null, + }, + id: 'd68508f0-cf9d-11eb-a603-13e7747d215c', + name: 'Test Jira', + type: '.jira', + }); + }); + + it('should preserve the same external service', async () => { + const { case: theCase } = await resolveCase({ + supertest, + caseId: 'e49ad6e0-cf9d-11eb-a603-13e7747d215c', + }); + + expect(theCase.external_service).to.eql({ + connector_id: 'd68508f0-cf9d-11eb-a603-13e7747d215c', + connector_name: 'Test Jira', + external_id: '10106', + external_title: 'TPN-99', + external_url: 'https://cases-testing.atlassian.net/browse/TPN-99', + pushed_at: '2021-06-17T18:57:45.524Z', + pushed_by: { + email: null, + full_name: 'j@j.com', + username: '711621466', + }, + }); + }); + }); + }); }); } diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts index 63b2f2e9b90ed..d7c506a6b69d2 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts @@ -126,6 +126,8 @@ export default ({ getService }: FtrProviderContext): void => { action: 'update', action_by: defaultUser, new_value: CaseStatuses.closed, + new_val_connector_id: null, + old_val_connector_id: null, old_value: CaseStatuses.open, case_id: `${postedCase.id}`, comment_id: null, @@ -165,6 +167,8 @@ export default ({ getService }: FtrProviderContext): void => { action_by: defaultUser, new_value: CaseStatuses['in-progress'], old_value: CaseStatuses.open, + old_val_connector_id: null, + new_val_connector_id: null, case_id: `${postedCase.id}`, comment_id: null, sub_case_id: '', diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/post_case.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/post_case.ts index 96709ee7c309d..13408c5d309d9 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/post_case.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/post_case.ts @@ -114,6 +114,8 @@ export default ({ getService }: FtrProviderContext): void => { const { new_value, ...rest } = creationUserAction as CaseUserActionResponse; const parsedNewValue = JSON.parse(new_value!); + const { id: connectorId, ...restCaseConnector } = postedCase.connector; + expect(rest).to.eql({ action_field: [ 'description', @@ -127,6 +129,9 @@ export default ({ getService }: FtrProviderContext): void => { action: 'create', action_by: defaultUser, old_value: null, + old_val_connector_id: null, + // the connector id will be null here because it the connector is none + new_val_connector_id: null, case_id: `${postedCase.id}`, comment_id: null, sub_case_id: '', @@ -138,7 +143,7 @@ export default ({ getService }: FtrProviderContext): void => { description: postedCase.description, title: postedCase.title, tags: postedCase.tags, - connector: postedCase.connector, + connector: restCaseConnector, settings: postedCase.settings, owner: postedCase.owner, }); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/resolve_case.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/resolve_case.ts new file mode 100644 index 0000000000000..27eae507b9a84 --- /dev/null +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/cases/resolve_case.ts @@ -0,0 +1,221 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; + +import { AttributesTypeUser } from '../../../../../../plugins/cases/common/api'; +import { CASES_URL } from '../../../../../../plugins/cases/common/constants'; +import { + defaultUser, + postCaseReq, + postCaseResp, + postCommentUserReq, + getPostCaseRequest, +} from '../../../../common/lib/mock'; +import { + deleteCasesByESQuery, + createCase, + resolveCase, + createComment, + removeServerGeneratedPropertiesFromCase, + removeServerGeneratedPropertiesFromSavedObject, +} from '../../../../common/lib/utils'; +import { + secOnly, + obsOnly, + globalRead, + superUser, + secOnlyRead, + obsOnlyRead, + obsSecRead, + noKibanaPrivileges, + obsSec, +} from '../../../../common/lib/authentication/users'; +import { getUserInfo } from '../../../../common/lib/authentication'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const es = getService('es'); + + describe('resolve_case', () => { + afterEach(async () => { + await deleteCasesByESQuery(es); + }); + + it('should resolve a case with no comments', async () => { + const postedCase = await createCase(supertest, getPostCaseRequest()); + const resolvedCase = await resolveCase({ + supertest, + caseId: postedCase.id, + includeComments: true, + }); + + const data = removeServerGeneratedPropertiesFromCase(resolvedCase.case); + expect(data).to.eql(postCaseResp()); + expect(data.comments?.length).to.eql(0); + }); + + it('should resolve a case with comments', async () => { + const postedCase = await createCase(supertest, postCaseReq); + await createComment({ supertest, caseId: postedCase.id, params: postCommentUserReq }); + const resolvedCase = await resolveCase({ + supertest, + caseId: postedCase.id, + includeComments: true, + }); + + const comment = removeServerGeneratedPropertiesFromSavedObject( + resolvedCase.case.comments![0] as AttributesTypeUser + ); + + expect(resolvedCase.case.comments?.length).to.eql(1); + expect(comment).to.eql({ + type: postCommentUserReq.type, + comment: postCommentUserReq.comment, + associationType: 'case', + created_by: defaultUser, + pushed_at: null, + pushed_by: null, + updated_by: null, + owner: 'securitySolutionFixture', + }); + }); + + it('should return a 400 when passing the includeSubCaseComments', async () => { + const { body } = await supertest + .get(`${CASES_URL}/case-id/resolve?includeSubCaseComments=true`) + .set('kbn-xsrf', 'true') + .send() + .expect(400); + + expect(body.message).to.contain('disabled'); + }); + + it('unhappy path - 404s when case is not there', async () => { + await supertest + .get(`${CASES_URL}/fake-id/resolve`) + .set('kbn-xsrf', 'true') + .send() + .expect(404); + }); + + describe('rbac', () => { + it('should resolve a case', async () => { + const newCase = await createCase( + supertestWithoutAuth, + getPostCaseRequest({ owner: 'securitySolutionFixture' }), + 200, + { + user: superUser, + space: 'space1', + } + ); + + for (const user of [globalRead, superUser, secOnly, secOnlyRead, obsSec, obsSecRead]) { + const resolvedCase = await resolveCase({ + supertest: supertestWithoutAuth, + caseId: newCase.id, + auth: { user, space: 'space1' }, + }); + + expect(resolvedCase.case.owner).to.eql('securitySolutionFixture'); + expect(resolvedCase.outcome).to.eql('exactMatch'); + expect(resolvedCase.alias_target_id).to.eql(undefined); + } + }); + + it('should resolve a case with comments', async () => { + const postedCase = await createCase( + supertestWithoutAuth, + getPostCaseRequest({ owner: 'securitySolutionFixture' }), + 200, + { + user: secOnly, + space: 'space1', + } + ); + + await createComment({ + supertest: supertestWithoutAuth, + caseId: postedCase.id, + params: postCommentUserReq, + expectedHttpCode: 200, + auth: { + user: secOnly, + space: 'space1', + }, + }); + + const resolvedCase = await resolveCase({ + supertest: supertestWithoutAuth, + caseId: postedCase.id, + includeComments: true, + auth: { user: secOnly, space: 'space1' }, + }); + + const comment = removeServerGeneratedPropertiesFromSavedObject( + resolvedCase.case.comments![0] as AttributesTypeUser + ); + + expect(resolvedCase.case.comments?.length).to.eql(1); + expect(comment).to.eql({ + type: postCommentUserReq.type, + comment: postCommentUserReq.comment, + associationType: 'case', + created_by: getUserInfo(secOnly), + pushed_at: null, + pushed_by: null, + updated_by: null, + owner: 'securitySolutionFixture', + }); + }); + + it('should not resolve a case when the user does not have access to owner', async () => { + const newCase = await createCase( + supertestWithoutAuth, + getPostCaseRequest({ owner: 'securitySolutionFixture' }), + 200, + { + user: superUser, + space: 'space1', + } + ); + + for (const user of [noKibanaPrivileges, obsOnly, obsOnlyRead]) { + await resolveCase({ + supertest: supertestWithoutAuth, + caseId: newCase.id, + expectedHttpCode: 403, + auth: { user, space: 'space1' }, + }); + } + }); + + it('should NOT resolve a case in a space with no permissions', async () => { + const newCase = await createCase( + supertestWithoutAuth, + getPostCaseRequest({ owner: 'securitySolutionFixture' }), + 200, + { + user: superUser, + space: 'space2', + } + ); + + await resolveCase({ + supertest: supertestWithoutAuth, + caseId: newCase.id, + expectedHttpCode: 403, + auth: { user: secOnly, space: 'space2' }, + }); + }); + }); + }); +}; diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts index f4c31c052cddd..942293437b03f 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/comments/post_comment.ts @@ -148,7 +148,9 @@ export default ({ getService }: FtrProviderContext): void => { action: 'create', action_by: defaultUser, new_value: `{"comment":"${postCommentUserReq.comment}","type":"${postCommentUserReq.type}","owner":"securitySolutionFixture"}`, + new_val_connector_id: null, old_value: null, + old_val_connector_id: null, case_id: `${postedCase.id}`, comment_id: `${patchedCase.comments![0].id}`, sub_case_id: '', diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/index.ts index fba60634cc3d7..0b933582d84a5 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/index.ts @@ -25,6 +25,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./cases/get_case')); loadTestFile(require.resolve('./cases/patch_cases')); loadTestFile(require.resolve('./cases/post_case')); + loadTestFile(require.resolve('./cases/resolve_case')); loadTestFile(require.resolve('./cases/reporters/get_reporters')); loadTestFile(require.resolve('./cases/status/get_status')); loadTestFile(require.resolve('./cases/tags/get_tags')); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/user_actions/get_all_user_actions.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/user_actions/get_all_user_actions.ts index 35ebb1a4bf7b1..4cae10510d28e 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/user_actions/get_all_user_actions.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/user_actions/get_all_user_actions.ts @@ -48,6 +48,15 @@ export default ({ getService }: FtrProviderContext): void => { }); it(`on new case, user action: 'create' should be called with actionFields: ['description', 'status', 'tags', 'title', 'connector', 'settings, owner]`, async () => { + const { id: connectorId, ...restConnector } = userActionPostResp.connector; + + const userActionNewValueNoId = { + ...userActionPostResp, + connector: { + ...restConnector, + }, + }; + const { body: postedCase } = await supertest .post(CASES_URL) .set('kbn-xsrf', 'true') @@ -73,7 +82,10 @@ export default ({ getService }: FtrProviderContext): void => { ]); expect(body[0].action).to.eql('create'); expect(body[0].old_value).to.eql(null); - expect(JSON.parse(body[0].new_value)).to.eql(userActionPostResp); + expect(body[0].old_val_connector_id).to.eql(null); + // this will be null because it is for the none connector + expect(body[0].new_val_connector_id).to.eql(null); + expect(JSON.parse(body[0].new_value)).to.eql(userActionNewValueNoId); }); it(`on close case, user action: 'update' should be called with actionFields: ['status']`, async () => { @@ -147,18 +159,19 @@ export default ({ getService }: FtrProviderContext): void => { expect(body.length).to.eql(2); expect(body[1].action_field).to.eql(['connector']); expect(body[1].action).to.eql('update'); + // this is null because it is the none connector + expect(body[1].old_val_connector_id).to.eql(null); expect(JSON.parse(body[1].old_value)).to.eql({ - id: 'none', name: 'none', type: '.none', fields: null, }); expect(JSON.parse(body[1].new_value)).to.eql({ - id: '123', name: 'Connector', type: '.jira', fields: { issueType: 'Task', priority: 'High', parent: null }, }); + expect(body[1].new_val_connector_id).to.eql('123'); }); it(`on update tags, user action: 'add' and 'delete' should be called with actionFields: ['tags']`, async () => { diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/common/user_actions/migrations.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/common/user_actions/migrations.ts index b4c2dca47bf5f..f9e66880c5230 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/common/user_actions/migrations.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/common/user_actions/migrations.ts @@ -12,6 +12,10 @@ import { SECURITY_SOLUTION_OWNER, } from '../../../../../../plugins/cases/common/constants'; import { getCaseUserActions } from '../../../../common/lib/utils'; +import { + CaseUserActionResponse, + CaseUserActionsResponse, +} from '../../../../../../plugins/cases/common'; // eslint-disable-next-line import/no-default-export export default function createGetTests({ getService }: FtrProviderContext) { @@ -41,14 +45,18 @@ export default function createGetTests({ getService }: FtrProviderContext) { expect(connectorUserAction.action_field.length).eql(1); expect(connectorUserAction.action_field[0]).eql('connector'); + expect(connectorUserAction.old_val_connector_id).to.eql( + 'c1900ac0-017f-11eb-93f8-d161651bf509' + ); expect(oldValue).to.eql({ - id: 'c1900ac0-017f-11eb-93f8-d161651bf509', name: 'none', type: '.none', fields: null, }); + expect(connectorUserAction.new_val_connector_id).to.eql( + 'b1900ac0-017f-11eb-93f8-d161651bf509' + ); expect(newValue).to.eql({ - id: 'b1900ac0-017f-11eb-93f8-d161651bf509', name: 'none', type: '.none', fields: null, @@ -77,5 +85,142 @@ export default function createGetTests({ getService }: FtrProviderContext) { } }); }); + + describe('7.13 connector id extraction', () => { + let userActions: CaseUserActionsResponse; + + before(async () => { + await esArchiver.load( + 'x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions' + ); + }); + + after(async () => { + await esArchiver.unload( + 'x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions' + ); + }); + + describe('none connector case', () => { + it('removes the connector id from the case create user action and sets the ids to null', async () => { + userActions = await getCaseUserActions({ + supertest, + caseID: 'aa8ac630-005e-11ec-91f1-6daf2ab59fb5', + }); + + const userAction = getUserActionById( + userActions, + 'ab43b5f0-005e-11ec-91f1-6daf2ab59fb5' + )!; + + const newValDecoded = JSON.parse(userAction.new_value!); + expect(newValDecoded.description).to.be('a description'); + expect(newValDecoded.title).to.be('a case'); + expect(newValDecoded.connector).not.have.property('id'); + // the connector id should be none so it should be removed + expect(userAction.new_val_connector_id).to.be(null); + expect(userAction.old_val_connector_id).to.be(null); + }); + + it('sets the connector ids to null for a create user action with null new and old values', async () => { + const userAction = getUserActionById( + userActions, + 'b3094de0-005e-11ec-91f1-6daf2ab59fb5' + )!; + + expect(userAction.new_val_connector_id).to.be(null); + expect(userAction.old_val_connector_id).to.be(null); + }); + }); + + describe('case with many user actions', () => { + before(async () => { + userActions = await getCaseUserActions({ + supertest, + caseID: 'e6fa9370-005e-11ec-91f1-6daf2ab59fb5', + }); + }); + + it('removes the connector id field for a created case user action', async () => { + const userAction = getUserActionById( + userActions, + 'e7882d70-005e-11ec-91f1-6daf2ab59fb5' + )!; + + const newValDecoded = JSON.parse(userAction.new_value!); + expect(newValDecoded.description).to.be('a description'); + expect(newValDecoded.title).to.be('a case'); + + expect(newValDecoded.connector).to.not.have.property('id'); + expect(userAction.new_val_connector_id).to.be('d92243b0-005e-11ec-91f1-6daf2ab59fb5'); + expect(userAction.old_val_connector_id).to.be(null); + }); + + it('removes the connector id from the external service new value', async () => { + const userAction = getUserActionById( + userActions, + 'e9471b80-005e-11ec-91f1-6daf2ab59fb5' + )!; + + const newValDecoded = JSON.parse(userAction.new_value!); + expect(newValDecoded.connector_name).to.be('a jira connector'); + expect(newValDecoded).to.not.have.property('connector_id'); + expect(userAction.new_val_connector_id).to.be('d92243b0-005e-11ec-91f1-6daf2ab59fb5'); + expect(userAction.old_val_connector_id).to.be(null); + }); + + it('sets the connector ids to null for a comment user action', async () => { + const userAction = getUserActionById( + userActions, + 'efe9de50-005e-11ec-91f1-6daf2ab59fb5' + )!; + + const newValDecoded = JSON.parse(userAction.new_value!); + expect(newValDecoded.comment).to.be('a comment'); + expect(userAction.new_val_connector_id).to.be(null); + expect(userAction.old_val_connector_id).to.be(null); + }); + + it('removes the connector id for an update connector action', async () => { + const userAction = getUserActionById( + userActions, + '16cd9e30-005f-11ec-91f1-6daf2ab59fb5' + )!; + + const newValDecoded = JSON.parse(userAction.new_value!); + const oldValDecoded = JSON.parse(userAction.old_value!); + + expect(newValDecoded.name).to.be('a different jira connector'); + expect(oldValDecoded.name).to.be('a jira connector'); + + expect(newValDecoded).to.not.have.property('id'); + expect(oldValDecoded).to.not.have.property('id'); + expect(userAction.new_val_connector_id).to.be('0a572860-005f-11ec-91f1-6daf2ab59fb5'); + expect(userAction.old_val_connector_id).to.be('d92243b0-005e-11ec-91f1-6daf2ab59fb5'); + }); + + it('removes the connector id from the external service new value for second push', async () => { + const userAction = getUserActionById( + userActions, + '1ea33bb0-005f-11ec-91f1-6daf2ab59fb5' + )!; + + const newValDecoded = JSON.parse(userAction.new_value!); + + expect(newValDecoded.connector_name).to.be('a different jira connector'); + + expect(newValDecoded).to.not.have.property('connector_id'); + expect(userAction.new_val_connector_id).to.be('0a572860-005f-11ec-91f1-6daf2ab59fb5'); + expect(userAction.old_val_connector_id).to.be(null); + }); + }); + }); }); } + +function getUserActionById( + userActions: CaseUserActionsResponse, + id: string +): CaseUserActionResponse | undefined { + return userActions.find((userAction) => userAction.action_id === id); +} diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/cases/push_case.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/cases/push_case.ts index 94fe494fc7cc4..0ea66d35b63b8 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/cases/push_case.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/cases/push_case.ts @@ -275,6 +275,8 @@ export default ({ getService }: FtrProviderContext): void => { action: 'push-to-service', action_by: defaultUser, old_value: null, + old_val_connector_id: null, + new_val_connector_id: connector.id, case_id: `${postedCase.id}`, comment_id: null, sub_case_id: '', @@ -284,7 +286,6 @@ export default ({ getService }: FtrProviderContext): void => { expect(parsedNewValue).to.eql({ pushed_at: pushedCase.external_service!.pushed_at, pushed_by: defaultUser, - connector_id: connector.id, connector_name: connector.name, external_id: '123', external_title: 'INC01', diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/cases/user_actions/get_all_user_actions.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/cases/user_actions/get_all_user_actions.ts index 79af6bb279a3d..255a2a4ce28b5 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/cases/user_actions/get_all_user_actions.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/cases/user_actions/get_all_user_actions.ts @@ -108,8 +108,10 @@ export default ({ getService }: FtrProviderContext): void => { expect(body[1].action_field).to.eql(['pushed']); expect(body[1].action).to.eql('push-to-service'); expect(body[1].old_value).to.eql(null); + expect(body[1].old_val_connector_id).to.eql(null); + expect(body[1].new_val_connector_id).to.eql(configure.connector.id); const newValue = JSON.parse(body[1].new_value); - expect(newValue.connector_id).to.eql(configure.connector.id); + expect(newValue).to.not.have.property('connector_id'); expect(newValue.pushed_by).to.eql(defaultUser); }); }); diff --git a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts index 26bc6a072450d..cd4b062c065a0 100644 --- a/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts +++ b/x-pack/test/case_api_integration/security_and_spaces/tests/trial/index.ts @@ -12,7 +12,7 @@ import { createSpacesAndUsers, deleteSpacesAndUsers } from '../../../common/lib/ export default ({ loadTestFile, getService }: FtrProviderContext): void => { describe('cases security and spaces enabled: trial', function () { // Fastest ciGroup for the moment. - this.tags('ciGroup5'); + this.tags('ciGroup13'); before(async () => { await createSpacesAndUsers(getService); diff --git a/x-pack/test/case_api_integration/security_only/tests/common/cases/reporters/get_reporters.ts b/x-pack/test/case_api_integration/security_only/tests/common/cases/reporters/get_reporters.ts index f72db1ac1b27e..8266b456ea1f2 100644 --- a/x-pack/test/case_api_integration/security_only/tests/common/cases/reporters/get_reporters.ts +++ b/x-pack/test/case_api_integration/security_only/tests/common/cases/reporters/get_reporters.ts @@ -28,14 +28,17 @@ import { superUserDefaultSpaceAuth, obsSecDefaultSpaceAuth, } from '../../../../utils'; +import { UserInfo } from '../../../../../common/lib/authentication/types'; + +const sortReporters = (reporters: UserInfo[]) => + reporters.sort((a, b) => a.username.localeCompare(b.username)); // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertestWithoutAuth = getService('supertestWithoutAuth'); const es = getService('es'); - // Failing: See https://github.com/elastic/kibana/issues/106658 - describe.skip('get_reporters', () => { + describe('get_reporters', () => { afterEach(async () => { await deleteCasesByESQuery(es); }); @@ -80,7 +83,10 @@ export default ({ getService }: FtrProviderContext): void => { }, }); - expect(reporters).to.eql(scenario.expectedReporters); + // sort reporters to prevent order failure + expect(sortReporters(reporters as unknown as UserInfo[])).to.eql( + sortReporters(scenario.expectedReporters) + ); } }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts index 5adf31aef5a3e..cebd20b698c26 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts @@ -27,11 +27,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./keyword')); loadTestFile(require.resolve('./keyword_array')); loadTestFile(require.resolve('./long')); - }); - - describe('', function () { - this.tags('ciGroup13'); - loadTestFile(require.resolve('./text')); loadTestFile(require.resolve('./text_array')); }); diff --git a/x-pack/test/functional/apps/apm/index.ts b/x-pack/test/functional/apps/apm/index.ts index e4db5a66aa55f..20c2bc264a74f 100644 --- a/x-pack/test/functional/apps/apm/index.ts +++ b/x-pack/test/functional/apps/apm/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('APM specs', function () { - this.tags('ciGroup6'); + this.tags('ciGroup10'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./correlations')); }); diff --git a/x-pack/test/functional/apps/canvas/reports.ts b/x-pack/test/functional/apps/canvas/reports.ts index 468430c390030..e21ec5b404d1f 100644 --- a/x-pack/test/functional/apps/canvas/reports.ts +++ b/x-pack/test/functional/apps/canvas/reports.ts @@ -198,7 +198,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { " `); - expect(res.get('content-length')).to.be('20725'); + const contentLength = parseInt(res.get('content-length'), 10); + expect(contentLength >= 20725 && contentLength <= 20726).to.be(true); // contentLength can be between 20725 and 20726 }); it('downloaded PDF base64 string is correct without borders and logo', async function () { diff --git a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap index 98dc901eaf306..466f41f7d4abf 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap +++ b/x-pack/test/functional/apps/dashboard/reporting/__snapshots__/download_csv.snap @@ -1,5 +1,567 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`dashboard Reporting Download CSV E-Commerce Data Download CSV export of a saved search panel 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,564670,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0531205312, ZO0684706847\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564710,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0263402634, ZO0499404994\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564429,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0260702607, ZO0495804958\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564479,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0409304093, ZO0436904369\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,564513,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0390003900, ZO0287902879\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,6,564885,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303803038, ZO0192501925\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565150,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0624906249, ZO0411604116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,13,565206,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316303163, ZO0401004010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564759,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218802188, ZO0492604926\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,564144,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218602186, ZO0501005010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,563909,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452804528, ZO0453604536\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,28,564869,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0192401924, ZO0366703667\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,564619,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0470304703, ZO0406204062\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,34,564237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0311203112, ZO0395703957\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,564269,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0281102811, ZO0555705557\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,564842,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0432004320, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,564893,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0322403224, ZO0227802278\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564215,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0147201472, ZO0152201522\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564725,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0071700717, ZO0364303643\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,564733,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0384303843, ZO0273702737\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564331,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0229402294, ZO0303303033\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564350,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444104441, ZO0476804768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564398,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0328703287, ZO0351003510\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,564409,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0178501785, ZO0503805038\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,564024,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0619006190\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,564271,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0507905079, ZO0430804308\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564676,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0108401084, ZO0139301393\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,564445,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0701407014\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,50,564241,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0605506055, ZO0547505475\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,564272,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0512105121\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564844,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0553205532, ZO0526205262\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,564883,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0705607056, ZO0334703347\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,564307,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0246602466, ZO0195201952\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564148,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0057900579, ZO0211602116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,564009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0487904879, ZO0027100271\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,564532,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0474704747, ZO0622006220\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565308,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0172401724, ZO0184901849\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,27,564339,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0082900829, ZO0347903479\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,564361,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0422304223, ZO0600506005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564394,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0269902699, ZO0667906679\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564030,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0179901799, ZO0637606376\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564661,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415004150, ZO0125501255\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564706,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0709007090, ZO0362103621\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564460,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0655106551, ZO0349403494\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,564536,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0304603046, ZO0370603706\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,564559,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0015500155, ZO0650806508\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564609,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0162401624, ZO0156001560\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,565138,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0615506155, ZO0445304453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,565025,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0280802808, ZO0549005490\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,564000,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0364603646, ZO0018200182\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,564557,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0664606646, ZO0460404604\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,564604,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0237702377, ZO0304303043\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,564777,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452704527, ZO0122201222\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,564812,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0266002660, ZO0031900319\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,715752,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,563964,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0001200012, ZO0251902519\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564315,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0263702637\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0323303233, ZO0172101721\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,565090,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0690306903, ZO0521005210\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,564649,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0405704057, ZO0411704117\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564510,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093600936, ZO0145301453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,565222,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0102001020, ZO0252402524\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,565233,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0614906149, ZO0430404304\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565084,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0549805498, ZO0541205412\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564796,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0022100221, ZO0172301723\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564627,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0211702117, ZO0499004990\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,564257,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539205392, ZO0577705777\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,564701,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0585205852, ZO0418104181\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,564915,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0286502865, ZO0394703947\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,564954,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0362903629, ZO0048100481\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0225302253, ZO0183101831\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564065,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711207112, ZO0646106461\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,563927,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0009800098, ZO0362803628\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,564937,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0520605206, ZO0432204322\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,564994,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0180601806, ZO0710007100\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,564070,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0234202342, ZO0245102451\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,563928,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0394103941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,727071,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,565284,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0687206872, ZO0422304223\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,564380,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0050400504, ZO0660006600\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,565276,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0131501315, ZO0668806688\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564819,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0374603746, ZO0697106971\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,717243,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,564140,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0268502685\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,564164,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0673506735, ZO0213002130\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564207,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711807118, ZO0073100731\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,564735,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0509705097, ZO0120501205\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565077,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118701187, ZO0123901239\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564274,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0542905429, ZO0423604236\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565161,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0441404414, ZO0430504305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,565039,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0489804898, ZO0695006950\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,723683,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,563967,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0493404934, ZO0640806408\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,564533,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0496704967, ZO0049700497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,49,565266,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0255602556, ZO0468304683\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,564818,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0475004750, ZO0412304123\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,23,564932,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0607806078\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,564968,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0134101341, ZO0062400624\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565002,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0354203542, ZO0338503385\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,564095,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0613806138, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,563924,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539805398, ZO0554205542\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,564770,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0704907049, ZO0024700247\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,563965,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0045800458, ZO0503405034\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564957,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0171601716, ZO0214602146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,41,564032,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0478404784, ZO0521905219\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,37,564075,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0622706227, ZO0525405254\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,563931,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444304443, ZO0596505965\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,564940,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0026800268, ZO0003600036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564987,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0526805268, ZO0478104781\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,564080,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415804158, ZO0460804608\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,8,564106,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0298002980, ZO0313103131\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,563947,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0348103481, ZO0164501645\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,725995,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,564756,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0556805568, ZO0481504815\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565137,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118501185, ZO0561905619\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,565173,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0203802038, ZO0014900149\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565214,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0588705887\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564804,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0259702597, ZO0640606406\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,565052,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697006970, ZO0711407114\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,45,565091,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0324703247, ZO0088600886\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,565231,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0235202352, ZO0135001350\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564190,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0243902439, ZO0208702087\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,564876,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0215502155, ZO0168101681\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,564902,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0698406984, ZO0704207042\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564761,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0665006650, ZO0709407094\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,731788,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,564340,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0565805658\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,564395,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0236702367, ZO0660706607\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,564686,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0373303733, ZO0131201312\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,564446,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093400934, ZO0679406794\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,43,564481,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0321603216, ZO0078000780\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,563953,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0376203762, ZO0303603036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,565061,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0286402864\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565100,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0069000690, ZO0490004900\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565263,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0582705827, ZO0111801118\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,563984,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0294102941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,12,565262,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303503035, ZO0197601976\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,565304,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0017800178, ZO0229602296\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,565123,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316903169, ZO0400504005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,565160,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0693306933, ZO0514605146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565224,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0576805768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564121,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0291902919, ZO0617206172\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,23,564166,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0607106071, ZO0470704707\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,564739,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0335603356, ZO0236502365\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564016,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0436904369, ZO0290402904\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,564576,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681206812, ZO0441904419\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,564605,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0333103331, ZO0694806948\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,17,730663,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,564366,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681906819, ZO0549705497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,564221,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0487404874\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,564174,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0032300323, ZO0236302363\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,562835,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0222302223, ZO0223502235\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,562882,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0460804608, ZO0523905239\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,562629,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0639506395, ZO0083000830\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,562672,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0613406134, ZO0436304363\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,563193,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0636906369, ZO0150301503\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,563440,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0589605896, ZO0257202572\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,41,563485,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0602606026, ZO0522005220\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,562792,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0242602426, ZO0336103361\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,563365,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0646206462, ZO0065200652\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,51,562688,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0394603946, ZO0608406084\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,51,563647,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0690906909, ZO0319003190\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,39,563711,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0254202542, ZO0288202882\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,563763,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0479404794, ZO0525305253\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,20,563825,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0238202382, ZO0237102371\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,562797,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",ZO0442504425 +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,563846,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0244102441, ZO0169301693\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,563887,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0423104231, ZO0438204382\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,563607,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0271002710, ZO0678806788\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,562762,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0162401624, ZO0375203752\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,723905,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0030300303, ZO0360003600, ZO0632906329, ZO0650906509\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,563195,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0231802318, ZO0501805018\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,563436,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0651606516, ZO0078100781\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,29,563489,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0126101261, ZO0483704837\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,727576,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0181201812, ZO0266902669, ZO0231702317, ZO0055800558\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,563167,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0295602956\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,563212,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0043700437, ZO0139001390\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,563460,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0682506825, ZO0594505945\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,563492,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0412004120, ZO0274102741\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,562729,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0456404564, ZO0535605356\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,562978,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0371003710, ZO0150601506\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,563324,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0440004400, ZO0130401304\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,563249,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0181001810, ZO0378903789\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,563286,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0040000400, ZO0503805038\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,563187,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0278702787, ZO0425404254\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,563503,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0649306493, ZO0490704907\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,563275,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0287402874, ZO0453404534\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,24,563737,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0306903069, ZO0320703207\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,563796,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0625806258, ZO0297602976\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,562853,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0564705647, ZO0481004810\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,562900,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0349203492, ZO0173801738\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,562668,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0348503485, ZO0059100591\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,37,562794,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0701707017, ZO0440404404\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,562720,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0585605856, ZO0549505495\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,29,562759,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0310403104, ZO0595005950\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,36,563442,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0394303943, ZO0556305563\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,563775,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0562805628, ZO0622806228\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,563813,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0120001200, ZO0286602866\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,51,563250,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0557805578, ZO0463904639\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,563282,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0100701007, ZO0651106511\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,563392,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0525405254, ZO0310203102\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,563697,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0264702647, ZO0000700007\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,563246,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0515205152, ZO0300803008\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,562934,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0674206742, ZO0326303263\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,21,562994,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0115801158, ZO0701507015\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,24,563317,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0631706317, ZO0192701927\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,563341,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0397303973, ZO0410304103\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,563622,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0328103281, ZO0224602246\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,33,563666,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0390903909, ZO0126801268\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,9,563026,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0703407034, ZO0275102751\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,563084,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0338803388, ZO0334203342\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,562963,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0004900049, ZO0633806338\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,563016,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0539605396, ZO0525505255\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,562598,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0383203832, ZO0642806428\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,563336,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0332903329, ZO0008300083\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,563558,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0622706227, ZO0584505845\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,563150,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0281802818, ZO0130201302\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,17,728845,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0082300823, ZO0306203062, ZO0094600946, ZO0158901589\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,562723,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0109901099, ZO0277802778\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,562745,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0541905419, ZO0628306283\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,562763,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0428604286, ZO0119601196\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,9,563604,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0588005880, ZO0388703887\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,27,563867,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0097300973, ZO0196301963\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,563383,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0369103691, ZO0378603786\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,52,563218,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0120401204, ZO0598605986\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,563554,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0246502465, ZO0032100321\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,563023,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0055100551, ZO0149701497\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,44,563060,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0040600406, ZO0356503565\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,50,563108,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0429604296, ZO0465204652\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,563778,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0656606566, ZO0186001860\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,562705,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0633106331, ZO0495904959\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,563639,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0623006230\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,563698,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0070800708, ZO0084100841\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,52,714638,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0576205762, ZO0602006020, ZO0281502815, ZO0111001110\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,563602,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0508705087, ZO0427804278\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,19,563054,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0701907019, ZO0519405194\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,52,563093,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0435004350, ZO0472104721\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,562875,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0353003530, ZO0637006370\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,12,562914,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0360503605, ZO0194501945\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,562654,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0065400654, ZO0158701587\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,563860,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0344703447, ZO0031000310\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,563907,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0036700367, ZO0054300543\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,31,562833,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0610806108, ZO0316803168\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,562899,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0313403134, ZO0587105871\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,562665,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0569205692, ZO0664006640\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,9,563579,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0548905489, ZO0316803168\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,563119,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0374603746, ZO0041300413\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,10,563152,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0603606036, ZO0608206082\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,17,725079,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0641506415, ZO0086200862, ZO0071500715, ZO0085700857\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,48,563736,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0415604156, ZO0461704617\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,563761,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0087700877, ZO0330603306\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,563800,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0307303073, ZO0161601616\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,563822,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0277402774, ZO0288502885\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,562948,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0282102821, ZO0554405544\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,562993,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0255202552, ZO0560005600\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,562585,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0063800638, ZO0165301653\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,22,563326,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0266702667, ZO0680306803\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,563755,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0710707107, ZO0038300383\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",EUR,52,715450,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0476604766, ZO0462404624, ZO0258302583, ZO0658206582\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,563181,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0274902749, ZO0293902939\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,563131,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0326803268, ZO0059600596\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,563254,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0052100521, ZO0498804988\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,12,563573,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0132601326, ZO0243002430\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,562699,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0558905589\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,25,563644,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0470104701, ZO0600506005\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,563701,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0536305363, ZO0282702827\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,562817,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0254702547, ZO0457804578\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,562881,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0091700917, ZO0635406354\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,562630,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0339803398, ZO0009700097\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,562667,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0664706647, ZO0506005060\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,563342,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0121101211\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,563366,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0388103881, ZO0540005400\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,562919,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0595005950\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,562976,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0426904269, ZO0520305203\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,563371,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0097500975, ZO0017100171\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,562989,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0590905909, ZO0279902799\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,45,562597,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0013200132, ZO0093800938\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,563548,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0021600216, ZO0031600316\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,562715,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0413404134, ZO0437204372\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,20,563657,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0653506535, ZO0322303223\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,563704,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0062700627, ZO0054100541\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,563534,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0014300143, ZO0249202492\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes, Men's Clothing\\",EUR,19,716616,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0601506015, ZO0507505075, ZO0549605496, ZO0114701147\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,563419,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0528605286, ZO0578505785\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,563468,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0324003240, ZO0711107111\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,563496,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0354103541, ZO0196101961\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,563829,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0335103351, ZO0043000430\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,563888,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0090400904, ZO0100501005\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,563037,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0172801728, ZO0115701157\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,563105,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0562205622, ZO0110901109\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,563066,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0373503735, ZO0206902069\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,563113,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0333903339, ZO0151801518\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,562351,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0376403764, ZO0050800508\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,561666,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0042600426, ZO0166401664\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,561236,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0072700727, ZO0101001010\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,8,561290,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0255702557, ZO0577605776\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,561739,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0537805378, ZO0538005380\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,561786,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0064100641, ZO0068600686\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,562400,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0094200942, ZO0376603766\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,562352,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0265302653, ZO0348203482\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,561343,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0620706207, ZO0566705667\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,561543,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0106701067, ZO0175101751\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,11,561577,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0604406044, ZO0296302963\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,561429,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0511405114, ZO0621506215\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,562050,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0322103221, ZO0373903739\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,41,562101,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0468804688, ZO0285502855\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,44,562247,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0666206662, ZO0673206732\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,562285,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0618306183, ZO0563105631\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,561965,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0655806558, ZO0334503345\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,562008,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0657006570, ZO0485604856\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,561472,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0439904399\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,561490,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0681306813, ZO0545705457\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,561317,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0329303293, ZO0074000740\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,562424,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0581705817, ZO0448804488\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,562473,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0289202892, ZO0432304323\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,562488,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0275202752, ZO0574405744\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,562118,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0622406224, ZO0591405914\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,562159,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0485704857, ZO0662006620\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,562198,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0482504825, ZO0481304813\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,44,562523,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0178001780, ZO0078400784\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,561373,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0563905639, ZO0528805288\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,561409,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0254702547, ZO0626306263\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,561858,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0105301053, ZO0364803648\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,11,561904,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0315303153, ZO0441904419\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,561381,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0231202312, ZO0106401064\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,561830,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0591105911, ZO0532805328\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,15,561878,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0562905629, ZO0388303883\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,561916,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0180101801, ZO0157101571\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,10,562324,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0413604136, ZO0509005090\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,28,562367,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0371803718, ZO0195401954\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,729673,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0268202682, ZO0048200482, ZO0134801348, ZO0668406684\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,561953,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0232002320, ZO0231402314\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,561997,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0346203462, ZO0010700107\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,26,561534,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0380303803, ZO0211902119\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,15,561632,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0546605466, ZO0600906009\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,561676,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0512705127, ZO0629406294\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,33,561218,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0409604096, ZO0466904669\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,561256,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0151601516, ZO0162901629\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,561311,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0458604586, ZO0391603916\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,561781,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0235402354, ZO0048700487\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,561375,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0115201152, ZO0420404204\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,561876,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0170301703, ZO0027000270\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,561633,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0165001650, ZO0159001590\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,562323,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0238502385, ZO0650406504\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,562358,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0337303373, ZO0079600796\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Men's Accessories\\",EUR,19,718360,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0291402914, ZO0483804838, ZO0460304603, ZO0443904439\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,41,561969,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0521205212, ZO0316003160\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,20,562011,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0068200682, ZO0245202452\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",EUR,38,719185,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0118601186, ZO0438904389, ZO0468004680, ZO0684106841\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,561669,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0100001000, ZO0642406424\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,561225,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0660906609, ZO0102801028\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,46,561284,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0086300863, ZO0171901719\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,561735,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0006300063, ZO0058400584\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,52,561798,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0684006840, ZO0469104691\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,27,562047,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0203102031, ZO0115701157\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,37,562107,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0624806248, ZO0579405794\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,562290,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0686106861, ZO0403504035\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,720967,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0553005530, ZO0519905199, ZO0528605286\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,11,561564,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0451204512, ZO0463804638\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,561444,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0651806518, ZO0369703697\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,561482,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0184901849, ZO0174301743\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,9,562456,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0276302763, ZO0701407014\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,562499,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0244802448, ZO0105701057\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,562152,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0616606166, ZO0589705897\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,562192,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0079700797, ZO0168201682\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,41,562528,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0522905229, ZO0608606086\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,715286,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0299802998, ZO0278702787, ZO0448104481, ZO0611906119\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,561210,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0407404074, ZO0473704737\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,41,562337,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0513005130, ZO0463704637\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,713242,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0482004820, ZO0577105771, ZO0130201302, ZO0629006290\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,561657,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0111701117, ZO0288002880\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,561254,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0081400814, ZO0022500225\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,561808,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0161401614, ZO0670406704\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,562394,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0116701167, ZO0618106181\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,731424,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0668706687, ZO0494004940, ZO0326003260, ZO0644206442\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,562425,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0377603776, ZO0050500505\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,29,562464,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0462004620, ZO0568005680\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,562516,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0271102711, ZO0081300813\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,51,562161,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0477504775, ZO0694406944\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,562211,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0616806168, ZO0551805518\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,561831,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0225102251, ZO0368803688\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,561864,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0287002870, ZO0692206922\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,561907,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0042300423, ZO0321403214\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,39,561245,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0554305543, ZO0468204682\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,561785,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0048600486, ZO0155201552\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,561505,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0164001640, ZO0179301793\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,30,562403,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0471504715, ZO0524405244\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,561342,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0524505245, ZO0388003880\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,562060,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0067300673, ZO0062100621\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,562094,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0374003740, ZO0146401464\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,562236,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0438304383\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,562304,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0025000250, ZO0232702327\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,562390,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0121701217, ZO0680806808\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,719041,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0117701177, ZO0292902929, ZO0387403874, ZO0286902869\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,561604,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0529605296, ZO0435404354\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,20,561455,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0182001820, ZO0018500185\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,561509,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0438404384, ZO0405504055\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,562439,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0533105331, ZO0384703847\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,562165,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0173701737, ZO0337903379\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,719343,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0299002990, ZO0584005840, ZO0628406284, ZO0694306943\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,718183,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0481004810, ZO0476104761, ZO0284102841, ZO0256102561\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,45,561215,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0196401964, ZO0673906739\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,561377,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0147901479, ZO0185401854\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,726377,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0167001670, ZO0070900709, ZO0636006360, ZO0051900519\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes, Women's Accessories\\",EUR,5,730333,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0065000650, ZO0241802418, ZO0098400984, ZO0262102621\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,561542,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0113701137, ZO0114201142\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,561586,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0540605406, ZO0401104011\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,561442,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0030900309, ZO0212302123\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,561484,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0400304003, ZO0559405594\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,561325,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0234802348, ZO0178001780\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,46,562463,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0700107001, ZO0341303413\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,562513,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0640906409, ZO0660206602\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,562166,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0692406924, ZO0473504735\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,38,714021,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0436904369, ZO0664106641, ZO0514805148, ZO0283302833\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Shoes\\",EUR,49,562041,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0320303203, ZO0252802528\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,5,562116,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0247002470, ZO0322703227\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,29,562281,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0683106831, ZO0317803178\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,32,562442,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0126901269, ZO0563705637\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,562149,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0291402914, ZO0539305393\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,562553,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0525005250, ZO0547205472\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,561677,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0525605256, ZO0126001260\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,561217,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0417904179, ZO0125501255\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,561251,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0502905029, ZO0249102491\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,37,561291,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0701907019, ZO0395203952\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,561316,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0524305243, ZO0290702907\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,561769,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0106601066, ZO0038300383\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,561784,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0644306443, ZO0205102051\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,27,561815,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0091100911, ZO0231102311\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,724573,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0653306533, ZO0261702617, ZO0036800368, ZO0490704907\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,561937,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0638606386, ZO0371503715\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,561966,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0124201242, ZO0413604136\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,561522,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0194601946, ZO0340403404\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,561330,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0691106911, ZO0295902959\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,17,726879,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0020100201, ZO0659406594, ZO0087900879, ZO0032700327\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,27,725944,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0079200792, ZO0263902639, ZO0065900659, ZO0492304923\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,562572,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0649706497, ZO0249202492\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,6,562035,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0334403344, ZO0205002050\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,562112,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0527405274, ZO0547005470\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,562275,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0106301063, ZO0703507035\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,562287,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0473104731, ZO0274302743\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,562404,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0584205842, ZO0299102991\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,8,562099,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0317903179, ZO0443904439\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,562298,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0280002800, ZO0583105831\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,7,562025,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0558205582, ZO0682406824\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,732071,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0655406554, ZO0154001540, ZO0030300303, ZO0061100611\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,23,561383,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0461804618, ZO0481404814\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,561825,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0062500625, ZO0179801798\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,561870,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0450904509, ZO0615906159\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,561569,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0264602646, ZO0265202652\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,561935,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0417404174, ZO0275702757\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,561976,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0392703927, ZO0452004520\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Accessories, Men's Shoes\\",EUR,19,717426,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0606006060, ZO0314703147, ZO0518005180, ZO0702907029\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719082,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0591005910, ZO0116501165, ZO0507505075, ZO0514305143\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,715688,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0585505855, ZO0121001210, ZO0583005830, ZO0279402794\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,729671,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0375303753, ZO0178301783, ZO0226002260, ZO0137601376\\" +" +`; + +exports[`dashboard Reporting Download CSV E-Commerce Data Downloads a filtered CSV export of a saved search panel 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,564670,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0531205312, ZO0684706847\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,564513,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0390003900, ZO0287902879\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,13,565206,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316303163, ZO0401004010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,564619,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0470304703, ZO0406204062\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,34,564237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0311203112, ZO0395703957\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,564842,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0432004320, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,564733,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0384303843, ZO0273702737\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,564271,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0507905079, ZO0430804308\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,564272,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0512105121\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,715752,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,565090,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0690306903, ZO0521005210\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,564649,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0405704057, ZO0411704117\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,564915,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0286502865, ZO0394703947\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,564937,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0520605206, ZO0432204322\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,563928,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0394103941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,565284,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0687206872, ZO0422304223\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,564735,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0509705097, ZO0120501205\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,49,565266,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0255602556, ZO0468304683\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,564095,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0613806138, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,41,564032,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0478404784, ZO0521905219\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,564756,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0556805568, ZO0481504815\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565214,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0588705887\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,564340,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0565805658\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,565061,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0286402864\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,565123,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316903169, ZO0400504005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,565160,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0693306933, ZO0514605146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565224,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0576805768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,564576,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681206812, ZO0441904419\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,564366,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681906819, ZO0549705497\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,563440,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0589605896, ZO0257202572\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,41,563485,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0602606026, ZO0522005220\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,51,562688,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0394603946, ZO0608406084\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,51,563647,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0690906909, ZO0319003190\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,39,563711,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0254202542, ZO0288202882\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,29,563489,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0126101261, ZO0483704837\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,563167,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0295602956\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,563460,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0682506825, ZO0594505945\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,36,563442,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0394303943, ZO0556305563\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,563246,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0515205152, ZO0300803008\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,563341,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0397303973, ZO0410304103\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,33,563666,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0390903909, ZO0126801268\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,9,563604,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0588005880, ZO0388703887\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,563639,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0623006230\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,563602,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0508705087, ZO0427804278\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,19,563054,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0701907019, ZO0519405194\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,562993,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0255202552, ZO0560005600\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",EUR,52,715450,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0476604766, ZO0462404624, ZO0258302583, ZO0658206582\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,562699,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0558905589\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,562817,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0254702547, ZO0457804578\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,562667,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0664706647, ZO0506005060\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,563342,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0121101211\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,563366,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0388103881, ZO0540005400\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,562919,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0595005950\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,562976,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0426904269, ZO0520305203\\" +\\"Jun 21, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes, Men's Clothing\\",EUR,19,716616,5,\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"ZO0601506015, ZO0507505075, ZO0549605496, ZO0114701147\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,8,561290,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0255702557, ZO0577605776\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,561429,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0511405114, ZO0621506215\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,561472,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0439904399\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,561490,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0681306813, ZO0545705457\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,562198,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0482504825, ZO0481304813\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,561409,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0254702547, ZO0626306263\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,15,561878,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0562905629, ZO0388303883\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,10,562324,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0413604136, ZO0509005090\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,561676,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0512705127, ZO0629406294\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,561311,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0458604586, ZO0391603916\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Men's Accessories\\",EUR,19,718360,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0291402914, ZO0483804838, ZO0460304603, ZO0443904439\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,41,561969,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0521205212, ZO0316003160\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",EUR,38,719185,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0118601186, ZO0438904389, ZO0468004680, ZO0684106841\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,52,561798,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0684006840, ZO0469104691\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,562290,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0686106861, ZO0403504035\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,720967,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0553005530, ZO0519905199, ZO0528605286\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,561210,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0407404074, ZO0473704737\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,41,562337,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0513005130, ZO0463704637\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,713242,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0482004820, ZO0577105771, ZO0130201302, ZO0629006290\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,51,562161,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0477504775, ZO0694406944\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,561864,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0287002870, ZO0692206922\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,561342,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0524505245, ZO0388003880\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,562236,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0438304383\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,562390,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0121701217, ZO0680806808\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,719041,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0117701177, ZO0292902929, ZO0387403874, ZO0286902869\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,561509,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0438404384, ZO0405504055\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,562439,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0533105331, ZO0384703847\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,719343,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0299002990, ZO0584005840, ZO0628406284, ZO0694306943\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,718183,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0481004810, ZO0476104761, ZO0284102841, ZO0256102561\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,561586,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0540605406, ZO0401104011\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,561484,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0400304003, ZO0559405594\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,562166,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0692406924, ZO0473504735\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,38,714021,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0436904369, ZO0664106641, ZO0514805148, ZO0283302833\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Shoes\\",EUR,49,562041,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0320303203, ZO0252802528\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,29,562281,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0683106831, ZO0317803178\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,37,561291,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0701907019, ZO0395203952\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,561330,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0691106911, ZO0295902959\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,7,562025,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0558205582, ZO0682406824\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,23,561383,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0461804618, ZO0481404814\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,561976,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0392703927, ZO0452004520\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Accessories, Men's Shoes\\",EUR,19,717426,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0606006060, ZO0314703147, ZO0518005180, ZO0702907029\\" +\\"Jun 20, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719082,4,\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"ZO0591005910, ZO0116501165, ZO0507505075, ZO0514305143\\" +" +`; + exports[`dashboard Reporting Download CSV Field Formatters and Scripted Fields Download CSV export of a saved search panel 1`] = ` "date,\\"_id\\",name,gender,value,year,\\"years_ago\\",\\"date_informal\\" \\"Jan 1, 1982 @ 00:00:00.000\\",\\"1982-Fethany-F\\",Fethany,F,780,1982,\\"37.00000000000000000000\\",\\"Jan 1st 82\\" diff --git a/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts b/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts index df45c3e3ca2ca..79ddaea13dfa5 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts +++ b/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts @@ -22,7 +22,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const find = getService('find'); const retry = getService('retry'); const PageObjects = getPageObjects(['reporting', 'common', 'dashboard', 'timePicker']); + const ecommerceSOPath = 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json'; + const ecommerceDataPath = 'x-pack/test/functional/es_archives/reporting/ecommerce'; + const dashboardAllDataHiddenTitles = 'Ecom Dashboard Hidden Panel Titles'; + const dashboardPeriodOf2DaysData = 'Ecom Dashboard - 3 Day Period'; + const dashboardWithScriptedFieldsSearch = 'names dashboard'; const getCsvPath = (name: string) => path.resolve(REPO_ROOT, `target/functional-tests/downloads/${name}.csv`); @@ -52,8 +57,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.existOrFail('csvDownloadStarted'); // validate toast panel }; - // Failing: See https://github.com/elastic/kibana/issues/103430 - describe.skip('Download CSV', () => { + describe('Download CSV', () => { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); await browser.setWindowSize(1600, 850); @@ -69,59 +73,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('E-Commerce Data', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/reporting/ecommerce'); + await esArchiver.load(ecommerceDataPath); await kibanaServer.importExport.load(ecommerceSOPath); }); + after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/reporting/ecommerce'); + await esArchiver.unload(ecommerceDataPath); await kibanaServer.importExport.unload(ecommerceSOPath); }); it('Download CSV export of a saved search panel', async function () { await PageObjects.common.navigateToApp('dashboard'); - await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard'); + await PageObjects.dashboard.loadSavedDashboard(dashboardPeriodOf2DaysData); await clickActionsMenu('EcommerceData'); await clickDownloadCsv(); const csvFile = await getDownload(getCsvPath('Ecommerce Data')); - const lines = csvFile.trim().split('\n'); - expectSnapshot(csvFile.length).toMatchInline(`782100`); - expectSnapshot(lines.length).toMatchInline(`4676`); - - // instead of matching all 4676 lines of CSV text, this verifies the first 10 and last 10 lines - expectSnapshot(lines.slice(0, 10)).toMatchInline(` - Array [ - "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\"", - ] - `); - expectSnapshot(lines.slice(-10)).toMatchInline(` - Array [ - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,550580,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0144801448, ZO0219602196\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,33,551324,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0316803168, ZO0566905669\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,551355,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0313403134, ZO0561205612\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,28,550957,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0133101331, ZO0189401894\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,39,551154,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0466704667, ZO0617306173\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,551204,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0212602126, ZO0200702007\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,550466,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0260702607, ZO0363203632\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,550503,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0587505875, ZO0566405664\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,550538,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0699406994, ZO0246202462\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,550568,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0388403884, ZO0447604476\\"", - ] - `); + expectSnapshot(csvFile).toMatch(); }); it('Downloads a filtered CSV export of a saved search panel', async function () { await PageObjects.common.navigateToApp('dashboard'); - await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard'); + await PageObjects.dashboard.loadSavedDashboard(dashboardPeriodOf2DaysData); // add a filter await filterBar.addFilter('category', 'is', `Men's Shoes`); @@ -130,44 +103,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await clickDownloadCsv(); const csvFile = await getDownload(getCsvPath('Ecommerce Data')); - const lines = csvFile.trim().split('\n'); - expectSnapshot(csvFile.length).toMatchInline(`165557`); - expectSnapshot(lines.length).toMatchInline(`945`); - - // instead of matching all 4676 lines of CSV text, this verifies the first 10 and last 10 lines - expectSnapshot(lines.slice(0, 10)).toMatchInline(` - Array [ - "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,591148,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0290302903, ZO0513705137\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,591562,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0544305443, ZO0108001080\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,591411,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0693506935, ZO0532405324\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,38,722629,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0424204242, ZO0403504035, ZO0506705067, ZO0395603956\\"", - ] - `); - expectSnapshot(lines.slice(-10)).toMatchInline(` - Array [ - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,550425,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0256602566, ZO0516305163\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719265,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0619506195, ZO0297802978, ZO0125001250, ZO0693306933\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,550990,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0404404044, ZO0570605706\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,7,550663,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0560905609\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,551697,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0387903879, ZO0693206932\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,550784,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0683206832, ZO0687706877\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,15,550412,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0508905089, ZO0681206812\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,551556,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0512405124, ZO0551405514\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,550473,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0688006880, ZO0450504505\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,550568,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0388403884, ZO0447604476\\"", - ] - `); + expectSnapshot(csvFile).toMatch(); }); it('Gets the correct filename if panel titles are hidden', async () => { await PageObjects.common.navigateToApp('dashboard'); - await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard Hidden Panel Titles'); + await PageObjects.dashboard.loadSavedDashboard(dashboardAllDataHiddenTitles); const savedSearchPanel = await find.byCssSelector( '[data-test-embeddable-id="94eab06f-60ac-4a85-b771-3a8ed475c9bb"]' ); // panel title is hidden @@ -191,7 +132,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('Download CSV export of a saved search panel', async () => { await PageObjects.common.navigateToApp('dashboard'); - await PageObjects.dashboard.loadSavedDashboard('names dashboard'); + await PageObjects.dashboard.loadSavedDashboard(dashboardWithScriptedFieldsSearch); await PageObjects.timePicker.setAbsoluteRange( 'Nov 26, 1981 @ 21:54:15.526', 'Mar 5, 1982 @ 18:17:44.821' diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap index 09f4698b51bb8..a230de9fcd6e7 100644 --- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap +++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap @@ -1,421 +1,7901 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: default 1`] = ` -Array [ - "\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user", - "3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,\\"(empty)\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{", - " \\"\\"coordinates\\"\\": [", - " 54.4,", - " 24.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.375, 33, 10.344, 6.109\\",\\"80, 60, 21.984, 11.992\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",174,174,4,4,order,sultan", - "9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Richards\\",\\"Pia Richards\\",FEMALE,45,Richards,Richards,\\"(empty)\\",Saturday,5,\\"pia@richards-family.zzz\\",Cannes,Europe,FR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 7,", - " 43.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.703, 9.867\\",\\"20.984, 20.984\\",\\"14,761, 11,632\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0006400064, ZO0150601506\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0006400064, ZO0150601506\\",\\"41.969\\",\\"41.969\\",2,2,order,pia", - "BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"3.6, 17.484\\",\\"7.988, 33\\",\\"20,734, 7,539\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"1, 1\\",\\"ZO0638206382, ZO0038800388\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0638206382, ZO0038800388\\",\\"40.969\\",\\"40.969\\",2,2,order,brigitte", - "KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mccarthy\\",\\"Abd Mccarthy\\",MALE,52,Mccarthy,Mccarthy,\\"(empty)\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",Cairo,Africa,EG,\\"{", - " \\"\\"coordinates\\"\\": [", - " 31.3,", - " 30.1", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590937,\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"28.984, 12.992\\",\\"28.984, 12.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.344, 6.109\\",\\"28.984, 12.992\\",\\"14,438, 23,607\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0297602976, ZO0565605656\\",\\"0, 0\\",\\"28.984, 12.992\\",\\"28.984, 12.992\\",\\"0, 0\\",\\"ZO0297602976, ZO0565605656\\",\\"41.969\\",\\"41.969\\",2,2,order,abd", - "KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Banks\\",\\"Robert Banks\\",MALE,29,Banks,Banks,\\"(empty)\\",Saturday,5,\\"robert@banks-family.zzz\\",\\"-\\",Asia,SA,\\"{", - " \\"\\"coordinates\\"\\": [", - " 45,", - " 25", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590976,\\"sold_product_590976_21270, sold_product_590976_13220\\",\\"sold_product_590976_21270, sold_product_590976_13220\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"6.23, 12.25\\",\\"11.992, 24.984\\",\\"21,270, 13,220\\",\\"Print T-shirt - white, Chinos - dark grey\\",\\"Print T-shirt - white, Chinos - dark grey\\",\\"1, 1\\",\\"ZO0561405614, ZO0281602816\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0561405614, ZO0281602816\\",\\"36.969\\",\\"36.969\\",2,2,order,robert", - "awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jim,Jim,\\"Jim Hansen\\",\\"Jim Hansen\\",MALE,41,Hansen,Hansen,\\"(empty)\\",Saturday,5,\\"jim@hansen-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591636,\\"sold_product_591636_1295, sold_product_591636_6498\\",\\"sold_product_591636_1295, sold_product_591636_6498\\",\\"50, 50\\",\\"50, 50\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"25, 27.484\\",\\"50, 50\\",\\"1,295, 6,498\\",\\"Smart lace-ups - dark brown, Suit jacket - dark blue\\",\\"Smart lace-ups - dark brown, Suit jacket - dark blue\\",\\"1, 1\\",\\"ZO0385003850, ZO0408604086\\",\\"0, 0\\",\\"50, 50\\",\\"50, 50\\",\\"0, 0\\",\\"ZO0385003850, ZO0408604086\\",100,100,2,2,order,jim", - "eQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Thad,Thad,\\"Thad Lamb\\",\\"Thad Lamb\\",MALE,30,Lamb,Lamb,\\"(empty)\\",Saturday,5,\\"thad@lamb-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jul 12, 2019 @ 00:00:00.000\\",591539,\\"sold_product_591539_15260, sold_product_591539_14221\\",\\"sold_product_591539_15260, sold_product_591539_14221\\",\\"20.984, 18.984\\",\\"20.984, 18.984\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.078, 10.25\\",\\"20.984, 18.984\\",\\"15,260, 14,221\\",\\"Casual lace-ups - dark blue, Trainers - navy\\",\\"Casual lace-ups - dark blue, Trainers - navy\\",\\"1, 1\\",\\"ZO0505605056, ZO0513605136\\",\\"0, 0\\",\\"20.984, 18.984\\",\\"20.984, 18.984\\",\\"0, 0\\",\\"ZO0505605056, ZO0513605136\\",\\"39.969\\",\\"39.969\\",2,2,order,thad", - "egMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Bryant\\",\\"Jim Bryant\\",MALE,41,Bryant,Bryant,\\"(empty)\\",Saturday,5,\\"jim@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",Oceanavigations,Oceanavigations,\\"Jul 12, 2019 @ 00:00:00.000\\",591598,\\"sold_product_591598_20597, sold_product_591598_2774\\",\\"sold_product_591598_20597, sold_product_591598_2774\\",\\"10.992, 85\\",\\"10.992, 85\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"5.93, 45.875\\",\\"10.992, 85\\",\\"20,597, 2,774\\",\\"Tie - brown/black , Classic coat - black\\",\\"Tie - brown/black , Classic coat - black\\",\\"1, 1\\",\\"ZO0276702767, ZO0291702917\\",\\"0, 0\\",\\"10.992, 85\\",\\"10.992, 85\\",\\"0, 0\\",\\"ZO0276702767, ZO0291702917\\",96,96,2,2,order,jim", - "fwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Roberson\\",\\"Betty Roberson\\",FEMALE,44,Roberson,Roberson,\\"(empty)\\",Saturday,5,\\"betty@roberson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.7", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590927,\\"sold_product_590927_15436, sold_product_590927_22598\\",\\"sold_product_590927_15436, sold_product_590927_22598\\",\\"28.984, 28.984\\",\\"28.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"14.781, 14.781\\",\\"28.984, 28.984\\",\\"15,436, 22,598\\",\\"Jersey dress - anthra/black, Shift dress - black\\",\\"Jersey dress - anthra/black, Shift dress - black\\",\\"1, 1\\",\\"ZO0046600466, ZO0050800508\\",\\"0, 0\\",\\"28.984, 28.984\\",\\"28.984, 28.984\\",\\"0, 0\\",\\"ZO0046600466, ZO0050800508\\",\\"57.969\\",\\"57.969\\",2,2,order,betty", - "gAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Hubbard\\",\\"Robbie Hubbard\\",MALE,48,Hubbard,Hubbard,\\"(empty)\\",Saturday,5,\\"robbie@hubbard-family.zzz\\",Dubai,Asia,AE,\\"{", - " \\"\\"coordinates\\"\\": [", - " 55.3,", - " 25.3", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Dubai,\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590970,\\"sold_product_590970_11228, sold_product_590970_12060\\",\\"sold_product_590970_11228, sold_product_590970_12060\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"12, 25.984\\",\\"24.984, 50\\",\\"11,228, 12,060\\",\\"Tracksuit top - offwhite multicolor, Lace-ups - black/red\\",\\"Tracksuit top - offwhite multicolor, Lace-ups - black/red\\",\\"1, 1\\",\\"ZO0455604556, ZO0680806808\\",\\"0, 0\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"0, 0\\",\\"ZO0455604556, ZO0680806808\\",75,75,2,2,order,robbie", - "6AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Willis\\",\\"Abigail Willis\\",FEMALE,46,Willis,Willis,\\"(empty)\\",Saturday,5,\\"abigail@willis-family.zzz\\",Birmingham,Europe,GB,\\"{", - " \\"\\"coordinates\\"\\": [", - " -1.9,", - " 52.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Birmingham,\\"Tigress Enterprises MAMA, Angeldale\\",\\"Tigress Enterprises MAMA, Angeldale\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591299,\\"sold_product_591299_19895, sold_product_591299_5787\\",\\"sold_product_591299_19895, sold_product_591299_5787\\",\\"33, 85\\",\\"33, 85\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Angeldale\\",\\"Tigress Enterprises MAMA, Angeldale\\",\\"17.156, 44.188\\",\\"33, 85\\",\\"19,895, 5,787\\",\\"Summer dress - black/offwhite, Ankle boots - black\\",\\"Summer dress - black/offwhite, Ankle boots - black\\",\\"1, 1\\",\\"ZO0229002290, ZO0674406744\\",\\"0, 0\\",\\"33, 85\\",\\"33, 85\\",\\"0, 0\\",\\"ZO0229002290, ZO0674406744\\",118,118,2,2,order,abigail", - "6QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Greene\\",\\"Boris Greene\\",MALE,36,Greene,Greene,\\"(empty)\\",Saturday,5,\\"boris@greene-family.zzz\\",\\"-\\",Europe,GB,\\"{", - " \\"\\"coordinates\\"\\": [", - " -0.1,", - " 51.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"-\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591133,\\"sold_product_591133_19496, sold_product_591133_20143\\",\\"sold_product_591133_19496, sold_product_591133_20143\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"12.742, 5.711\\",\\"24.984, 10.992\\",\\"19,496, 20,143\\",\\"Tracksuit bottoms - mottled grey, Sports shirt - black\\",\\"Tracksuit bottoms - mottled grey, Sports shirt - black\\",\\"1, 1\\",\\"ZO0529905299, ZO0617006170\\",\\"0, 0\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"0, 0\\",\\"ZO0529905299, ZO0617006170\\",\\"35.969\\",\\"35.969\\",2,2,order,boris", - "6gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Conner\\",\\"Jackson Conner\\",MALE,13,Conner,Conner,\\"(empty)\\",Saturday,5,\\"jackson@conner-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -118.2,", - " 34.1", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591175,\\"sold_product_591175_23703, sold_product_591175_11555\\",\\"sold_product_591175_23703, sold_product_591175_11555\\",\\"28.984, 65\\",\\"28.984, 65\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"13.922, 31.844\\",\\"28.984, 65\\",\\"23,703, 11,555\\",\\"Sweatshirt - grey multicolor, Short coat - dark blue\\",\\"Sweatshirt - grey multicolor, Short coat - dark blue\\",\\"1, 1\\",\\"ZO0299402994, ZO0433504335\\",\\"0, 0\\",\\"28.984, 65\\",\\"28.984, 65\\",\\"0, 0\\",\\"ZO0299402994, ZO0433504335\\",94,94,2,2,order,jackson", - "7QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Cross\\",\\"Yuri Cross\\",MALE,21,Cross,Cross,\\"(empty)\\",Saturday,5,\\"yuri@cross-family.zzz\\",Cannes,Europe,FR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 7,", - " 43.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591297,\\"sold_product_591297_21234, sold_product_591297_17466\\",\\"sold_product_591297_21234, sold_product_591297_17466\\",\\"75, 28.984\\",\\"75, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"36.75, 13.344\\",\\"75, 28.984\\",\\"21,234, 17,466\\",\\"Lace-up boots - brown, Jumper - multicoloured\\",\\"Lace-up boots - brown, Jumper - multicoloured\\",\\"1, 1\\",\\"ZO0257502575, ZO0451704517\\",\\"0, 0\\",\\"75, 28.984\\",\\"75, 28.984\\",\\"0, 0\\",\\"ZO0257502575, ZO0451704517\\",104,104,2,2,order,yuri", - "7gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Ramsey\\",\\"Irwin Ramsey\\",MALE,14,Ramsey,Ramsey,\\"(empty)\\",Saturday,5,\\"irwin@ramsey-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{", -] +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with data 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,12,570552,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0216402164, ZO0666306663\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,570520,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0618906189, ZO0289502895\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,570569,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0643506435, ZO0646406464\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,45,570133,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0320503205, ZO0049500495\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,4,570161,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0606606066, ZO0596305963\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,570200,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0025100251, ZO0101901019\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,732050,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0101201012, ZO0230902309, ZO0325603256, ZO0056400564\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719675,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0686206862, ZO0395403954, ZO0528505285\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,570396,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0495604956, ZO0208802088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,570037,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0321503215, ZO0200102001\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,569311,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0024600246, ZO0660706607\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,29,570632,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0432404324, ZO0313603136\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569674,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0423104231, ZO0408804088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,569716,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0146701467, ZO0212902129\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,569962,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0129901299, ZO0440704407\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,569821,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0066600666, ZO0049000490\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,569898,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0591805918, ZO0474004740\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,570232,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0682006820, ZO0399103991\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,721217,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0567705677, ZO0414204142, ZO0415904159, ZO0119801198\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570111,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0253002530, ZO0117101171\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,569610,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0140001400, ZO0219302193\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,29,570087,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0308403084, ZO0623506235\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,570442,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0175501755, ZO0103601036\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,4,569548,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0587605876, ZO0463904639\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,16,569577,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0464404644, ZO0128401284\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569611,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0450604506, ZO0440304403\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,570480,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0286202862, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,570594,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0111901119, ZO0540605406\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,570077,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0433904339, ZO0627706277\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,24,570056,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0131801318, ZO0215802158\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,725669,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0234102341, ZO0353703537, ZO0265102651, ZO0149501495\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,570694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0376703767, ZO0350603506\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,570542,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0623606236, ZO0565405654\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,570576,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0637906379, ZO0325103251\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Accessories, Men's Clothing\\",EUR,52,716588,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0318303183, ZO0310503105, ZO0584605846, ZO0609706097\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,719459,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0410004100, ZO0513605136, ZO0431404314, ZO0662906629\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,10,569531,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0664106641, ZO0549105491\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569569,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0070600706, ZO0488704887\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569614,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0226202262, ZO0647006470\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,20,570484,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0712407124, ZO0095600956\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,569679,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0433604336, ZO0275702757\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,570250,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0638906389, ZO0148001480\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,570303,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0573305733, ZO0513205132\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,7,569746,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0484004840, ZO0605906059\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,569806,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0558305583\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,570353,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0413704137, ZO0559205592\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570021,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0709807098, ZO0166301663\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,570502,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0280602806, ZO0408504085\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,570477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0299202992, ZO0392403924\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,570263,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0041800418, ZO0194901949\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,570304,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0053000530, ZO0360203602\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,569743,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0610306103\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,569529,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0264102641, ZO0658706587\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,38,714566,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0430204302, ZO0397303973, ZO0686806868, ZO0320403204\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,712856,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0263202632 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing, Men's Accessories\\",EUR,52,713377,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0318803188, ZO0535005350, ZO0445504455, ZO0599605996\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,570472,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0478704787, ZO0591205912\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,570120,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392903929, ZO0254802548\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,570177,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0532905329, ZO0524105241\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,570209,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0658306583, ZO0570705707\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570254,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0495304953, ZO0634906349\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,20,569734,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0348703487, ZO0141401414\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,48,569814,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0602606026, ZO0298402984\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,32,570414,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0481704817, ZO0396503965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,39,569436,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0386103861, ZO0451504515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,41,570079,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0598505985, ZO0449304493\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,569637,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0300103001, ZO0688106881\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,570588,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0092000920, ZO0152001520\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,569567,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0366203662, ZO0361403614\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,569645,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392803928, ZO0277102771\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,570658,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0003600036, ZO0016800168\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,712926,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0263002630 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,570264,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0627206272, ZO0285702857\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,569424,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0175201752, ZO0206202062\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,569468,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0285202852, ZO0448304483\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,14,569505,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0608906089, ZO0478504785\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569337,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0634106341, ZO0066900669\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569362,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0292402924, ZO0681006810\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,569375,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0347603476, ZO0668806688\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,569387,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0125201252\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,52,713556,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0592105921, ZO0421204212, ZO0400604006, ZO0319403194\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,569919,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0051200512, ZO0232602326\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569768,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0231502315, ZO0131401314\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570334,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0520205202, ZO0545205452\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,570374,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0674906749, ZO0073200732\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,570024,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0631506315, ZO0426804268\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,570143,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0482904829\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,730736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0074200742, ZO0266602666, ZO0364503645, ZO0134601346\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,570075,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0621706217, ZO0114301143\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,43,569623,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0208302083, ZO0307603076\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,569546,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0559105591, ZO0563205632\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,570532,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0557405574, ZO0118601186\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,570586,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0596505965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,569452,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0159301593, ZO0250502505\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569496,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0659006590, ZO0103801038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,569336,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0384103841\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,569370,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0358603586, ZO0641106411\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,45,569411,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0094200942, ZO0003700037\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570663,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0152501525, ZO0104201042\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,570491,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0198901989, ZO0104701047\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,570608,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0478504785, ZO0663306633\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,20,569371,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0225702257, ZO0186601866\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,46,570065,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0027300273, ZO0698606986\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569624,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0333803338, ZO0138901389\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,569953,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0021100211, ZO0193601936\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,569984,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0537205372, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,569822,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0271402714, ZO0047200472\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,20,569880,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0325303253, ZO0244002440\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,570234,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0707007070, ZO0016200162\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,46,570512,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0332003320, ZO0357103571\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,569422,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0102501025, ZO0063500635\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,30,569958,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0311903119, ZO0563305633\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,34,570003,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0298902989, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,22,569868,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0200702007, ZO0106501065\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569710,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0053600536, ZO0239702397\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,570151,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0589105891, ZO0587705877\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,725499,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0678306783, ZO0305503055, ZO0369203692, ZO0006700067\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,31,569338,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0702507025, ZO0528105281\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,569392,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0516405164, ZO0532705327\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,712590,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0262202622 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,31,569312,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0425104251, ZO0107901079\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,570643,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0618806188, ZO0119701197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,44,570687,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0135501355, ZO0675806758\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,13,569939,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0471304713, ZO0528905289\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,569968,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0047300473, ZO0142401424\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,569995,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0125701257, ZO0664706647\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,570009,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0510705107, ZO0594605946\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,569834,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0076900769, ZO0151501515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,569869,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0362803628, ZO0237802378\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,569900,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0644506445, ZO0104901049\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,570164,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0210002100, ZO0068200682\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569761,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0166101661, ZO0337203372\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,570335,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0337703377, ZO0048500485\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,570372,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0124001240, ZO0560205602\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,570040,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0146901469, ZO0673806738\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569985,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0554005540, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,569835,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0077800778, ZO0177301773\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569873,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0165701657, ZO0485004850\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,569905,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0599605996, ZO0403804038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,6,570508,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0002600026, ZO0328703287\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569699,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398603986, ZO0521305213\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,570280,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0341703417, ZO0168701687\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,29,569736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0517305173, ZO0319703197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569777,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0254302543, ZO0289102891\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,569815,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0269602696, ZO0067400674\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,8,570350,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0460004600, ZO0569705697\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,569925,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0437004370, ZO0475204752\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,570061,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0604606046, ZO0416004160\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0533305333, ZO0565105651\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,14,569510,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0312203122, ZO0115101151\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,570309,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0496504965, ZO0269202692\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569787,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0055900559, ZO0224002240\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,36,570388,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0405604056, ZO0604506045\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,569309,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0364103641, ZO0708807088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,51,570620,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0422204222, ZO0256502565\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,570671,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0240702407, ZO0099400994\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,43,569652,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0665906659, ZO0240002400\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,569694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398703987, ZO0687806878\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,51,569469,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0434204342, ZO0600206002\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,569513,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0135701357, ZO0097600976\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,569356,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0010500105, ZO0172201722\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,568397,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0112101121, ZO0530405304\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,568044,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0630406304, ZO0120201202\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,44,568229,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0192201922, ZO0192801928\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,10,568292,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0534205342, ZO0599605996\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,568386,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0422404224, ZO0291702917\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,568023,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0075900759, ZO0489304893\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,42,568789,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0197501975, ZO0079300793\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,568331,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0385903859, ZO0516605166\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,568524,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0694706947\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,10,568589,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0114401144, ZO0564705647\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,568640,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0125901259, ZO0443204432\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,568682,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680706807, ZO0392603926\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,569259,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0335503355, ZO0381003810\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,8,568793,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0312503125, ZO0545505455\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,31,568350,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0317303173, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,31,568531,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0482104821, ZO0447104471\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,29,568578,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0520005200, ZO0421104211\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,568609,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0570405704, ZO0256102561\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,568652,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0403304033, ZO0125901259\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,568068,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0583005830, ZO0602706027\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,568070,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0575605756, ZO0293302933\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,568106,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0068700687, ZO0101301013\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,568439,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0170601706, ZO0251502515\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568507,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0431304313, ZO0523605236\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,568236,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0416604166, ZO0581605816\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,568275,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0330903309, ZO0214802148\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568434,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0362203622, ZO0000300003\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,568458,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0164501645, ZO0195501955\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,568503,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0643306433, ZO0376203762\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",EUR,25,714149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,568232,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0282902829, ZO0566605666\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,48,568269,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0318603186, ZO0407904079\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,568301,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0146401464, ZO0014700147\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,568469,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0659806598, ZO0070100701\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,568499,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0474604746, ZO0113801138\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,17,568083,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0200902009, ZO0092300923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569163,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0682706827\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,569214,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0490104901, ZO0087200872\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,11,568875,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0613606136, ZO0463804638\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,15,568943,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0445804458, ZO0686106861\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,569046,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0393103931, ZO0619906199\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,569103,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0636506365, ZO0345503455\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,33,568993,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482604826\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,720661,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0423004230, ZO0471604716, ZO0315303153, ZO0445604456\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,569144,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0108101081, ZO0501105011\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,569198,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0464304643, ZO0581905819\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,568845,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0657906579, ZO0258102581\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,24,568894,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0141801418, ZO0206302063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,568938,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0642806428, ZO0632506325\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,11,569045,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315903159, ZO0461104611\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,569097,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0511605116, ZO0483004830\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,727370,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680206802, ZO0321703217, ZO0049900499, ZO0029400294\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,49,568751,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0308703087, ZO0613106131\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,569010,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0090700907, ZO0265002650\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,25,568745,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0528305283, ZO0309203092\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories, Women's Clothing\\",EUR,5,728962,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0019800198, ZO0089200892, ZO0069700697, ZO0332303323\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,568069,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0530305303, ZO0528405284\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,732546,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0228602286, ZO0502605026, ZO0108901089, ZO0362503625\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,17,568218,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0227402274, ZO0079000790\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,568278,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536705367, ZO0449804498\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,568428,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0408404084, ZO0422304223\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,568492,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0346103461, ZO0054100541\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,569262,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0609906099, ZO0614806148\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,569306,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0412004120, ZO0625406254\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,21,569223,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0444004440, ZO0596805968\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,568039,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0599705997, ZO0416704167\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,568117,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315203152, ZO0406304063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,568165,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0065600656, ZO0337003370\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568393,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0374103741, ZO0242102421\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,567996,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0105401054, ZO0046200462\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,569173,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0452204522, ZO0631206312\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,49,569209,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0472304723, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,568865,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0294502945, ZO0560605606\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,568926,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0298302983, ZO0300003000\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,568955,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0068900689, ZO0076200762\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,569056,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0494804948, ZO0096000960\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,569083,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0099000990, ZO0631606316\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,717726,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,568149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0342503425, ZO0675206752\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,568192,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0485504855, ZO0355603556\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569183,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0641206412, ZO0165301653\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,568818,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0294802948, ZO0451404514\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568854,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616706167, ZO0255402554\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,4,568901,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0466704667, ZO0427104271\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,568954,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0399603996, ZO0685906859\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,569033,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0015700157, ZO0362503625\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,11,569091,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0258602586, ZO0552205522\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,569003,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0414704147, ZO0387503875\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,41,568707,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0513305133, ZO0253302533\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,568019,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0530805308, ZO0563905639\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,568182,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0338603386, ZO0641006410\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569299,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519605196, ZO0630806308\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,13,569123,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0609006090, ZO0441504415\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,728335,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0134701347, ZO0026200262, ZO0223102231, ZO0022900229\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,726874,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0362303623, ZO0035400354, ZO0705207052, ZO0504005040\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,569218,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0633206332, ZO0488604886\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,722613,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0618806188, ZO0442804428, ZO0530705307, ZO0410804108\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,568152,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0349303493, ZO0043900439\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,568212,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536405364, ZO0688306883\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,568228,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0580005800\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568455,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0413104131, ZO0392303923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,567994,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0430904309, ZO0288402884\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,568045,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0160501605, ZO0069500695\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568308,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0138701387, ZO0024600246\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,568515,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0159901599, ZO0238702387\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,721706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,569250,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0228902289, ZO0005400054\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568776,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616906169, ZO0296902969\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,568014,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0523905239, ZO0556605566\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,568702,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0142801428, ZO0182801828\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,568128,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0087500875, ZO0007100071\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568177,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0584505845, ZO0403804038\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,569178,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0177001770, ZO0260502605\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,568877,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0132401324, ZO0058200582\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,33,568898,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0542205422, ZO0517805178\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,568941,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0076600766, ZO0068800688\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,12,569027,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0245402454, ZO0060100601\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,569055,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0375903759, ZO0269402694\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,569107,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0339603396, ZO0504705047\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,714385,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0586805868, ZO0609106091, ZO0310903109, ZO0420104201\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,723213,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0297802978, ZO0456704567, ZO0572105721, ZO0280502805\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,568325,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0288202882, ZO0391803918\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,568360,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0480304803, ZO0274402744\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,569278,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0271802718, ZO0057100571\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,568816,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0146601466, ZO0108601086\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,21,568375,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0623606236, ZO0605306053\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,38,568559,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0599005990, ZO0626506265\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,45,568611,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0174701747, ZO0305103051\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,568638,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0388003880, ZO0478304783\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,568706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0672206722, ZO0331903319\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",EUR,25,716889,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,728580,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0156601566, ZO0498004980, ZO0070700707, ZO0086700867\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,568762,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0052200522, ZO0265602656\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,568571,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0034100341, ZO0343103431\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,568671,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0637406374, ZO0219002190\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,568774,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0037200372, ZO0369303693\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568319,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0535105351, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,568363,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0629806298, ZO0467104671\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568541,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0428904289, ZO0588205882\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,568586,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0232202322, ZO0208402084\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,568636,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0503905039, ZO0631806318\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,568674,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0192301923, ZO0011400114\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,9,567868,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0310403104, ZO0416604166\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,567446,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0322803228, ZO0002700027\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,7,567340,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0615606156, ZO0514905149\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,567736,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0663706637, ZO0620906209\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567755,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0571405714, ZO0255402554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,715455,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0477504775, ZO0613206132, ZO0585405854, ZO0110701107\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566768,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0217702177, ZO0331703317\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,566812,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0266902669, ZO0244202442\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,9,566680,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0316703167, ZO0393303933\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,566944,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0497004970, ZO0054900549\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566979,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0071900719, ZO0493404934\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,11,566734,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0691006910, ZO0314203142\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,567094,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0442904429, ZO0629706297\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,566892,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589505895, ZO0575405754\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,567950,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0273002730, ZO0541105411\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,566826,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0575305753, ZO0540605406\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567240,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421004210, ZO0689006890\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,567290,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0442704427\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,24,567669,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0148301483, ZO0202902029\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,567365,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0008600086, ZO0266002660\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,566845,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0547905479, ZO0583305833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567048,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0566905669, ZO0564005640\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,567281,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0221402214, ZO0632806328\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,567119,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0711507115, ZO0350903509\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,567169,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0558805588, ZO0622206222\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567869,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0565105651, ZO0443804438\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,567909,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0609606096, ZO0588905889\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,567524,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0096300963, ZO0377403774\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,567565,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0015600156, ZO0323603236\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,567019,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0151301513, ZO0204902049\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,567069,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0503805038, ZO0047500475\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,567935,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0116101161, ZO0574305743\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,566831,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0341103411, ZO0648406484\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,567543,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0608106081, ZO0296502965\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,567598,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0039400394, ZO0672906729\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,567876,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0705707057, ZO0047700477\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,567684,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0201202012, ZO0035000350\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,7,567790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0522405224, ZO0405104051\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,567465,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0274502745, ZO0686006860\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,50,567256,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0461004610, ZO0702707027\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,13,716462,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0549505495, ZO0458504585, ZO0602506025, ZO0617506175\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,566775,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0671006710, ZO0708007080\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,567926,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0113301133, ZO0562105621\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566829,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0100901009, ZO0235102351\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,567666,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0311403114, ZO0282002820\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,567383,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0647406474, ZO0330703307\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567381,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278402784, ZO0458304583\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,567437,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0275902759, ZO0545005450\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,567324,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0426604266, ZO0629406294\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,21,567504,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0606506065, ZO0277702777\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,42,567623,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0239802398, ZO0645406454\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,567400,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0605606056, ZO0588105881\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,566757,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0196201962, ZO0168601686\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,566884,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0490204902, ZO0025000250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,567815,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0263602636, ZO0241002410\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,567177,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0197301973, ZO0180401804\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,733060,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0155601556, ZO0013600136, ZO0235702357, ZO0383203832\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,567486,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0058200582, ZO0365503655\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,567625,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0328603286, ZO0328803288\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,10,567224,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0128501285, ZO0606306063\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,567252,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0369803698, ZO0220502205\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,567735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0129701297, ZO0518705187\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,567822,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0244802448, ZO0346303463\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,31,567852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0523805238, ZO0596505965\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,566861,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0520305203, ZO0462204622\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,567042,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0243002430, ZO0103901039\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,731037,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0148801488, ZO0335003350, ZO0155301553, ZO0074300743\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,567729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0395103951, ZO0296102961\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567384,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0426704267, ZO0612006120\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,566690,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0449004490, ZO0118501185\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,49,566951,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0517405174\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,566982,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0149301493, ZO0099800998\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,566725,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0444404444, ZO0584205842\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,566856,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0216502165, ZO0327503275\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,567039,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0184101841, ZO0711207112\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,567068,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0038000380, ZO0711007110\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,5,732229,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0175701757, ZO0163801638, ZO0697506975, ZO0245602456\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,724806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0643106431, ZO0033300333, ZO0696206962, ZO0651206512\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567769,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0414004140, ZO0630106301\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,566772,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0152901529, ZO0019100191\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567318,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421104211, ZO0256202562\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,6,567615,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0013500135, ZO0174501745\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,567316,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0403004030\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,566896,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0242702427, ZO0090000900\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,567418,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400404004, ZO0625006250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,567462,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0644406444, ZO0709307093\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,567667,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0273802738, ZO0300303003\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,567703,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0037900379, ZO0134901349\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,567260,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0068100681, ZO0674106741\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,724844,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0707507075, ZO0246402464, ZO0226802268, ZO0343503435\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,567308,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0181601816, ZO0011000110\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,567404,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0107101071, ZO0537905379\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,31,567538,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0596905969, ZO0450804508\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,46,567593,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0655306553, ZO0208902089\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,15,567294,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0317403174, ZO0457204572\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,728256,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0371903719, ZO0352803528, ZO0137501375, ZO0229202292\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,567544,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0585005850, ZO0120301203\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567592,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0535405354, ZO0291302913\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,566942,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0084000840, ZO0636606366\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,567015,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0558605586, ZO0527805278\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,28,567081,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0209702097, ZO0186301863\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567475,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0578805788, ZO0520405204\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,567631,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0101101011, ZO0667406674\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,567454,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0645406454, ZO0166001660\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,567855,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0657106571, ZO0084800848\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567835,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589405894, ZO0483304833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,567889,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0282202822, ZO0393003930\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,566852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0257002570, ZO0455404554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,5,567037,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0206402064, ZO0365903659\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,721778,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,38,567143,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0573005730, ZO0313203132\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,567191,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0113901139, ZO0478904789\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,567135,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0528305283, ZO0549305493\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,727730,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0050600506, ZO0710907109, ZO0023300233, ZO0334603346\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,567939,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0127201272, ZO0425504255\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567970,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0441504415, ZO0691606916\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,567301,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0577605776, ZO0438104381\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566801,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0279702797, ZO0573705737\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566685,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0296902969, ZO0530205302\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,566924,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0673606736, ZO0161801618\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,11,567662,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0308903089, ZO0614306143\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,20,567708,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0090500905, ZO0466204662\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,567573,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0215602156, ZO0336803368\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,717603,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,566986,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0360903609, ZO0030100301\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0632406324, ZO0060300603\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,9,567082,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278802788, ZO0515605156\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,566881,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0419604196, ZO0559705597\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,20,566790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0699206992, ZO0641306413\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,566706,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0521505215, ZO0130501305\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,566935,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0473704737, ZO0121501215\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,566985,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0044700447, ZO0502105021\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,566729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0110401104\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,567095,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0339803398, ZO0098200982\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,724326,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0499404994, ZO0641606416, ZO0334303343, ZO0676706767\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,567806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0517705177, ZO0569305693\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,567973,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0495104951, ZO0305903059\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,567341,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0674506745, ZO0219202192\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,567492,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0277302773, ZO0443004430\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567654,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0399403994\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,567403,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0138601386, ZO0259202592\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,567207,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0033600336, ZO0109401094\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,13,567356,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0319503195, ZO0409904099\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565855,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0417504175, ZO0535205352\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,565915,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0515005150, ZO0509805098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566343,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0185101851, ZO0052800528\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,26,566400,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0204702047, ZO0009600096\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565776,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0343103431, ZO0345803458\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566607,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0572205722, ZO0585205852\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565452,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0133601336, ZO0643906439\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,566051,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0025600256, ZO0270202702\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565466,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0285402854, ZO0538605386\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566553,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0435004350, ZO0544005440\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,565446,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0643206432, ZO0140101401\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,566053,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0284702847, ZO0299202992\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,565605,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0113301133\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,566170,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0324803248, ZO0703907039\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,566187,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0548905489, ZO0459404594\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,566125,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0433104331, ZO0549505495\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566156,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0117901179\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,6,566100,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0013400134, ZO0667306673\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,566280,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0573205732, ZO0116701167\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,31,565708,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0253302533, ZO0605706057\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,565809,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0557905579, ZO0513705137\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,566256,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0227302273, ZO0668706687\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,27,565639,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0193901939, ZO0080400804\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,565684,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0507705077, ZO0409804098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565945,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0270602706, ZO0269502695\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,18,565988,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0074700747, ZO0645206452\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,15,565732,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0291402914, ZO0603006030\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,29,566042,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0451804518, ZO0127901279\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,566456,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0597105971, ZO0283702837\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,565542,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0224302243, ZO0359103591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,566121,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0227202272, ZO0357003570\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,36,566101,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0691406914, ZO0617806178\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,566653,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0666506665, ZO0216602166\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,565838,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0343703437, ZO0207102071\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,565804,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0306803068, ZO0174601746\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,31,566247,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0403504035\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,566036,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0583605836, ZO0510605106\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,565459,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0242302423, ZO0676006760\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565819,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0031700317, ZO0157701577\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,731352,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0018200182, ZO0016100161, ZO0329703297, ZO0057800578\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,565667,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0618706187, ZO0388503885\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565900,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0266102661, ZO0169701697\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,566360,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0285102851, ZO0658306583\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,33,566416,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0396903969, ZO0607906079\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,46,565796,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0081500815, ZO0342603426\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,566261,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0577105771, ZO0289302893\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,565567,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0437604376, ZO0618906189\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,565596,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0332903329, ZO0159401594\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,52,717206,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,715081,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,566428,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0136501365, ZO0339103391\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,566334,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0010800108, ZO0635706357\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566391,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0228302283, ZO0167501675\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,715133,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,717057,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,566315,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0703707037, ZO0139601396\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565698,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0336503365, ZO0637006370\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,566167,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623006230, ZO0419304193\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,566215,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0579305793\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,566070,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0046100461, ZO0151201512\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,16,566621,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0579605796, ZO0315803158\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,566284,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0541405414, ZO0588205882\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,566518,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0554605546, ZO0569005690\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,25,565580,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0395303953, ZO0386703867\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,565830,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0215702157, ZO0638806388\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,16,566454,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0547405474, ZO0401104011\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,30,566506,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0680806808, ZO0609306093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,22,565948,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0190701907, ZO0654806548\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,565998,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0238802388, ZO0066600666\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565401,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0014800148, ZO0154501545\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,565728,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0486404864, ZO0248602486\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,565489,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0077200772, ZO0643006430\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565366,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0684906849, ZO0575905759\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,25,720445,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0423004230, ZO0292702927, ZO0320003200, ZO0318303183\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565768,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0458004580, ZO0273402734\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,565538,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0486804868, ZO0371603716\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,565404,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0048900489, ZO0228702287\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,715961,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0444904449, ZO0292502925, ZO0434604346, ZO0461804618\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,566382,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0503505035, ZO0240302403\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,565877,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0125401254, ZO0123701237\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,566364,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0525005250\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,48,565479,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0588805888, ZO0314903149\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565360,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0450704507\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,565734,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0513205132, ZO0258202582\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,566514,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0539305393, ZO0522305223\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,565970,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0673406734, ZO0165601656\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,27,723242,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0643306433, ZO0088900889, ZO0634406344\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,720399,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,566580,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0417304173, ZO0123001230\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,566671,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0427604276, ZO0113801138\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,566176,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0607206072, ZO0431404314\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,566146,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0646206462, ZO0146201462\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565760,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0504505045, ZO0223802238\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,565521,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0660406604, ZO0484504845\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,566320,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0105001050, ZO0652306523\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,566357,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0061600616, ZO0180701807\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,566415,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0261102611, ZO0667106671\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566044,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0552605526, ZO0292702927\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,565473,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0365303653, ZO0235802358\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,565339,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0346503465, ZO0678406784\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565591,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0683806838, ZO0429204292\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,5,730725,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0501605016, ZO0189601896, ZO0363003630, ZO0699306993\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,566443,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0160201602, ZO0261502615\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,566498,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0550005500\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,565985,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0436604366, ZO0280302803\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565640,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0631606316, ZO0045300453\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,49,565683,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0573205732, ZO0310303103\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565767,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0414304143, ZO0425204252\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,566452,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0706307063, ZO0011300113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,13,565982,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0410804108, ZO0309303093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,726754,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0138001380, ZO0648006480, ZO0193501935, ZO0228402284\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,24,565723,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0302303023, ZO0246602466\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,31,565896,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0466104661, ZO0444104441\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,52,718085,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0129001290, ZO0310103101, ZO0547805478, ZO0560805608\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,566248,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0678806788, ZO0186101861\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,565560,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0567505675, ZO0442104421\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,8,566186,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0522105221, ZO0459104591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,566155,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0501005010, ZO0214002140\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,28,566628,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0195601956, ZO0098900989\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,9,566519,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0700907009, ZO0115801158\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,565697,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0498904989, ZO0641706417\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,45,566417,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0084900849, ZO0194701947\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,565722,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0656406564, ZO0495504955\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,565330,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0621606216, ZO0628806288\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,44,565381,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0060200602, ZO0076300763\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,565564,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0576305763, ZO0116801168\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565392,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0616606166, ZO0592205922\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,6,565410,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0023600236, ZO0704307043\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565504,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0653406534, ZO0049300493\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,565334,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0641706417, ZO0382303823\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,566079,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0663306633, ZO0687306873\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,566622,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0228402284, ZO0082300823\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,566650,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0049100491, ZO0194801948\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,566295,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0635606356, ZO0043100431\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566538,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0224402244, ZO0342403424\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,565918,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0155001550, ZO0072100721\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,565678,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0081800818, ZO0485604856\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,566564,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0107301073, ZO0293002930\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,565498,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0503305033\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,565793,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0712807128, ZO0007500075\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,566232,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0545205452, ZO0437304373\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,25,566259,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0553805538\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,566591,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0502405024, ZO0366003660\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,564670,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0531205312, ZO0684706847\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564710,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0263402634, ZO0499404994\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564429,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0260702607, ZO0495804958\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564479,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0409304093, ZO0436904369\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,564513,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0390003900, ZO0287902879\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,6,564885,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303803038, ZO0192501925\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565150,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0624906249, ZO0411604116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,13,565206,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316303163, ZO0401004010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564759,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218802188, ZO0492604926\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,564144,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218602186, ZO0501005010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,563909,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452804528, ZO0453604536\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,28,564869,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0192401924, ZO0366703667\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,564619,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0470304703, ZO0406204062\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,34,564237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0311203112, ZO0395703957\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,564269,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0281102811, ZO0555705557\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,564842,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0432004320, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,564893,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0322403224, ZO0227802278\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564215,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0147201472, ZO0152201522\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564725,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0071700717, ZO0364303643\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,564733,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0384303843, ZO0273702737\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564331,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0229402294, ZO0303303033\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564350,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444104441, ZO0476804768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564398,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0328703287, ZO0351003510\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,564409,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0178501785, ZO0503805038\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,564024,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0619006190\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,564271,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0507905079, ZO0430804308\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564676,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0108401084, ZO0139301393\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,564445,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0701407014\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,50,564241,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0605506055, ZO0547505475\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,564272,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0512105121\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564844,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0553205532, ZO0526205262\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,564883,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0705607056, ZO0334703347\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,564307,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0246602466, ZO0195201952\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564148,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0057900579, ZO0211602116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,564009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0487904879, ZO0027100271\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,564532,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0474704747, ZO0622006220\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565308,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0172401724, ZO0184901849\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,27,564339,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0082900829, ZO0347903479\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,564361,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0422304223, ZO0600506005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564394,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0269902699, ZO0667906679\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564030,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0179901799, ZO0637606376\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564661,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415004150, ZO0125501255\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564706,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0709007090, ZO0362103621\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564460,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0655106551, ZO0349403494\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,564536,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0304603046, ZO0370603706\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,564559,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0015500155, ZO0650806508\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564609,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0162401624, ZO0156001560\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,565138,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0615506155, ZO0445304453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,565025,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0280802808, ZO0549005490\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,564000,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0364603646, ZO0018200182\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,564557,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0664606646, ZO0460404604\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,564604,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0237702377, ZO0304303043\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,564777,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452704527, ZO0122201222\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,564812,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0266002660, ZO0031900319\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,715752,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,563964,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0001200012, ZO0251902519\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564315,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0263702637\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0323303233, ZO0172101721\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,565090,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0690306903, ZO0521005210\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,564649,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0405704057, ZO0411704117\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564510,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093600936, ZO0145301453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,565222,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0102001020, ZO0252402524\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,565233,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0614906149, ZO0430404304\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565084,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0549805498, ZO0541205412\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564796,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0022100221, ZO0172301723\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564627,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0211702117, ZO0499004990\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,564257,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539205392, ZO0577705777\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,564701,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0585205852, ZO0418104181\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,564915,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0286502865, ZO0394703947\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,564954,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0362903629, ZO0048100481\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0225302253, ZO0183101831\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564065,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711207112, ZO0646106461\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,563927,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0009800098, ZO0362803628\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,564937,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0520605206, ZO0432204322\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,564994,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0180601806, ZO0710007100\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,564070,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0234202342, ZO0245102451\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,563928,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0394103941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,727071,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,565284,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0687206872, ZO0422304223\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,564380,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0050400504, ZO0660006600\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,565276,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0131501315, ZO0668806688\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564819,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0374603746, ZO0697106971\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,717243,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,564140,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0268502685\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,564164,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0673506735, ZO0213002130\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564207,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711807118, ZO0073100731\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,564735,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0509705097, ZO0120501205\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565077,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118701187, ZO0123901239\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564274,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0542905429, ZO0423604236\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565161,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0441404414, ZO0430504305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,565039,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0489804898, ZO0695006950\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,723683,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,563967,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0493404934, ZO0640806408\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,564533,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0496704967, ZO0049700497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,49,565266,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0255602556, ZO0468304683\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,564818,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0475004750, ZO0412304123\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,23,564932,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0607806078\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,564968,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0134101341, ZO0062400624\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565002,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0354203542, ZO0338503385\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,564095,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0613806138, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,563924,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539805398, ZO0554205542\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,564770,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0704907049, ZO0024700247\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,563965,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0045800458, ZO0503405034\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564957,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0171601716, ZO0214602146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,41,564032,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0478404784, ZO0521905219\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,37,564075,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0622706227, ZO0525405254\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,563931,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444304443, ZO0596505965\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,564940,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0026800268, ZO0003600036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564987,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0526805268, ZO0478104781\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,564080,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415804158, ZO0460804608\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,8,564106,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0298002980, ZO0313103131\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,563947,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0348103481, ZO0164501645\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,725995,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,564756,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0556805568, ZO0481504815\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565137,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118501185, ZO0561905619\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,565173,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0203802038, ZO0014900149\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565214,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0588705887\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564804,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0259702597, ZO0640606406\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,565052,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697006970, ZO0711407114\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,45,565091,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0324703247, ZO0088600886\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,565231,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0235202352, ZO0135001350\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564190,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0243902439, ZO0208702087\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,564876,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0215502155, ZO0168101681\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,564902,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0698406984, ZO0704207042\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564761,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0665006650, ZO0709407094\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,731788,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,564340,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0565805658\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,564395,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0236702367, ZO0660706607\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,564686,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0373303733, ZO0131201312\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,564446,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093400934, ZO0679406794\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,43,564481,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0321603216, ZO0078000780\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,563953,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0376203762, ZO0303603036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,565061,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0286402864\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565100,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0069000690, ZO0490004900\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565263,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0582705827, ZO0111801118\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,563984,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0294102941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,12,565262,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303503035, ZO0197601976\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,565304,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0017800178, ZO0229602296\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,565123,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316903169, ZO0400504005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,565160,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0693306933, ZO0514605146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565224,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0576805768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564121,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0291902919, ZO0617206172\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,23,564166,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0607106071, ZO0470704707\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,564739,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0335603356, ZO0236502365\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564016,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0436904369, ZO0290402904\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,564576,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681206812, ZO0441904419\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,564605,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0333103331, ZO0694806948\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,17,730663,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,564366,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681906819, ZO0549705497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,564221,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0487404874\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,564174,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0032300323, ZO0236302363\\" +" +`; + +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,12,570552,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0216402164, ZO0666306663\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,570520,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0618906189, ZO0289502895\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,570569,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0643506435, ZO0646406464\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,45,570133,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0320503205, ZO0049500495\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,4,570161,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0606606066, ZO0596305963\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,570200,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0025100251, ZO0101901019\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,732050,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0101201012, ZO0230902309, ZO0325603256, ZO0056400564\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719675,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0686206862, ZO0395403954, ZO0528505285\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,570396,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0495604956, ZO0208802088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,570037,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0321503215, ZO0200102001\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,569311,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0024600246, ZO0660706607\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,29,570632,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0432404324, ZO0313603136\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569674,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0423104231, ZO0408804088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,569716,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0146701467, ZO0212902129\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,569962,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0129901299, ZO0440704407\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,569821,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0066600666, ZO0049000490\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,569898,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0591805918, ZO0474004740\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,570232,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0682006820, ZO0399103991\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,721217,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0567705677, ZO0414204142, ZO0415904159, ZO0119801198\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570111,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0253002530, ZO0117101171\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,569610,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0140001400, ZO0219302193\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,29,570087,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0308403084, ZO0623506235\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,570442,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0175501755, ZO0103601036\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,4,569548,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0587605876, ZO0463904639\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,16,569577,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0464404644, ZO0128401284\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569611,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0450604506, ZO0440304403\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,570480,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0286202862, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,570594,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0111901119, ZO0540605406\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,570077,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0433904339, ZO0627706277\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,24,570056,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0131801318, ZO0215802158\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,725669,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0234102341, ZO0353703537, ZO0265102651, ZO0149501495\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,570694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0376703767, ZO0350603506\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,570542,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0623606236, ZO0565405654\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,570576,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0637906379, ZO0325103251\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Accessories, Men's Clothing\\",EUR,52,716588,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0318303183, ZO0310503105, ZO0584605846, ZO0609706097\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,719459,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0410004100, ZO0513605136, ZO0431404314, ZO0662906629\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,10,569531,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0664106641, ZO0549105491\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569569,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0070600706, ZO0488704887\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569614,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0226202262, ZO0647006470\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,20,570484,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0712407124, ZO0095600956\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,569679,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0433604336, ZO0275702757\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,570250,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0638906389, ZO0148001480\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,570303,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0573305733, ZO0513205132\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,7,569746,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0484004840, ZO0605906059\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,569806,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0558305583\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,570353,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0413704137, ZO0559205592\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570021,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0709807098, ZO0166301663\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,570502,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0280602806, ZO0408504085\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,570477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0299202992, ZO0392403924\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,570263,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0041800418, ZO0194901949\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,570304,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0053000530, ZO0360203602\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,569743,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0610306103\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,569529,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0264102641, ZO0658706587\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,38,714566,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0430204302, ZO0397303973, ZO0686806868, ZO0320403204\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,712856,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0263202632 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing, Men's Accessories\\",EUR,52,713377,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0318803188, ZO0535005350, ZO0445504455, ZO0599605996\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,570472,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0478704787, ZO0591205912\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,570120,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392903929, ZO0254802548\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,570177,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0532905329, ZO0524105241\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,570209,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0658306583, ZO0570705707\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570254,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0495304953, ZO0634906349\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,20,569734,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0348703487, ZO0141401414\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,48,569814,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0602606026, ZO0298402984\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,32,570414,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0481704817, ZO0396503965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,39,569436,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0386103861, ZO0451504515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,41,570079,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0598505985, ZO0449304493\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,569637,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0300103001, ZO0688106881\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,570588,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0092000920, ZO0152001520\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,569567,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0366203662, ZO0361403614\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,569645,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392803928, ZO0277102771\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,570658,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0003600036, ZO0016800168\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,712926,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0263002630 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,570264,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0627206272, ZO0285702857\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,569424,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0175201752, ZO0206202062\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,569468,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0285202852, ZO0448304483\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,14,569505,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0608906089, ZO0478504785\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569337,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0634106341, ZO0066900669\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569362,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0292402924, ZO0681006810\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,569375,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0347603476, ZO0668806688\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,569387,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0125201252\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,52,713556,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0592105921, ZO0421204212, ZO0400604006, ZO0319403194\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,569919,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0051200512, ZO0232602326\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569768,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0231502315, ZO0131401314\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570334,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0520205202, ZO0545205452\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,570374,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0674906749, ZO0073200732\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,570024,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0631506315, ZO0426804268\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,570143,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0482904829\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,730736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0074200742, ZO0266602666, ZO0364503645, ZO0134601346\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,570075,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0621706217, ZO0114301143\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,43,569623,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0208302083, ZO0307603076\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,569546,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0559105591, ZO0563205632\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,570532,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0557405574, ZO0118601186\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,570586,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0596505965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,569452,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0159301593, ZO0250502505\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569496,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0659006590, ZO0103801038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,569336,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0384103841\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,569370,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0358603586, ZO0641106411\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,45,569411,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0094200942, ZO0003700037\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570663,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0152501525, ZO0104201042\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,570491,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0198901989, ZO0104701047\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,570608,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0478504785, ZO0663306633\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,20,569371,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0225702257, ZO0186601866\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,46,570065,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0027300273, ZO0698606986\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569624,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0333803338, ZO0138901389\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,569953,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0021100211, ZO0193601936\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,569984,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0537205372, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,569822,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0271402714, ZO0047200472\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,20,569880,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0325303253, ZO0244002440\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,570234,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0707007070, ZO0016200162\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,46,570512,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0332003320, ZO0357103571\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,569422,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0102501025, ZO0063500635\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,30,569958,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0311903119, ZO0563305633\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,34,570003,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0298902989, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,22,569868,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0200702007, ZO0106501065\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569710,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0053600536, ZO0239702397\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,570151,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0589105891, ZO0587705877\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,725499,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0678306783, ZO0305503055, ZO0369203692, ZO0006700067\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,31,569338,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0702507025, ZO0528105281\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,569392,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0516405164, ZO0532705327\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,712590,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0262202622 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,31,569312,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0425104251, ZO0107901079\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,570643,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0618806188, ZO0119701197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,44,570687,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0135501355, ZO0675806758\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,13,569939,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0471304713, ZO0528905289\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,569968,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0047300473, ZO0142401424\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,569995,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0125701257, ZO0664706647\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,570009,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0510705107, ZO0594605946\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,569834,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0076900769, ZO0151501515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,569869,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0362803628, ZO0237802378\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,569900,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0644506445, ZO0104901049\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,570164,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0210002100, ZO0068200682\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569761,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0166101661, ZO0337203372\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,570335,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0337703377, ZO0048500485\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,570372,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0124001240, ZO0560205602\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,570040,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0146901469, ZO0673806738\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569985,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0554005540, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,569835,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0077800778, ZO0177301773\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569873,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0165701657, ZO0485004850\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,569905,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0599605996, ZO0403804038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,6,570508,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0002600026, ZO0328703287\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569699,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398603986, ZO0521305213\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,570280,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0341703417, ZO0168701687\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,29,569736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0517305173, ZO0319703197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569777,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0254302543, ZO0289102891\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,569815,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0269602696, ZO0067400674\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,8,570350,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0460004600, ZO0569705697\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,569925,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0437004370, ZO0475204752\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,570061,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0604606046, ZO0416004160\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0533305333, ZO0565105651\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,14,569510,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0312203122, ZO0115101151\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,570309,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0496504965, ZO0269202692\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569787,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0055900559, ZO0224002240\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,36,570388,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0405604056, ZO0604506045\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,569309,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0364103641, ZO0708807088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,51,570620,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0422204222, ZO0256502565\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,570671,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0240702407, ZO0099400994\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,43,569652,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0665906659, ZO0240002400\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,569694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398703987, ZO0687806878\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,51,569469,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0434204342, ZO0600206002\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,569513,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0135701357, ZO0097600976\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,569356,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0010500105, ZO0172201722\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,568397,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0112101121, ZO0530405304\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,568044,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0630406304, ZO0120201202\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,44,568229,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0192201922, ZO0192801928\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,10,568292,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0534205342, ZO0599605996\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,568386,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0422404224, ZO0291702917\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,568023,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0075900759, ZO0489304893\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,42,568789,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0197501975, ZO0079300793\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,568331,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0385903859, ZO0516605166\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,568524,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0694706947\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,10,568589,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0114401144, ZO0564705647\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,568640,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0125901259, ZO0443204432\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,568682,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680706807, ZO0392603926\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,569259,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0335503355, ZO0381003810\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,8,568793,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0312503125, ZO0545505455\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,31,568350,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0317303173, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,31,568531,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0482104821, ZO0447104471\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,29,568578,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0520005200, ZO0421104211\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,568609,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0570405704, ZO0256102561\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,568652,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0403304033, ZO0125901259\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,568068,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0583005830, ZO0602706027\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,568070,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0575605756, ZO0293302933\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,568106,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0068700687, ZO0101301013\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,568439,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0170601706, ZO0251502515\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568507,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0431304313, ZO0523605236\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,568236,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0416604166, ZO0581605816\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,568275,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0330903309, ZO0214802148\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568434,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0362203622, ZO0000300003\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,568458,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0164501645, ZO0195501955\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,568503,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0643306433, ZO0376203762\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",EUR,25,714149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,568232,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0282902829, ZO0566605666\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,48,568269,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0318603186, ZO0407904079\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,568301,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0146401464, ZO0014700147\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,568469,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0659806598, ZO0070100701\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,568499,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0474604746, ZO0113801138\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,17,568083,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0200902009, ZO0092300923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569163,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0682706827\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,569214,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0490104901, ZO0087200872\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,11,568875,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0613606136, ZO0463804638\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,15,568943,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0445804458, ZO0686106861\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,569046,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0393103931, ZO0619906199\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,569103,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0636506365, ZO0345503455\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,33,568993,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482604826\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,720661,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0423004230, ZO0471604716, ZO0315303153, ZO0445604456\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,569144,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0108101081, ZO0501105011\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,569198,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0464304643, ZO0581905819\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,568845,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0657906579, ZO0258102581\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,24,568894,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0141801418, ZO0206302063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,568938,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0642806428, ZO0632506325\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,11,569045,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315903159, ZO0461104611\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,569097,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0511605116, ZO0483004830\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,727370,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680206802, ZO0321703217, ZO0049900499, ZO0029400294\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,49,568751,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0308703087, ZO0613106131\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,569010,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0090700907, ZO0265002650\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,25,568745,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0528305283, ZO0309203092\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories, Women's Clothing\\",EUR,5,728962,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0019800198, ZO0089200892, ZO0069700697, ZO0332303323\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,568069,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0530305303, ZO0528405284\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,732546,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0228602286, ZO0502605026, ZO0108901089, ZO0362503625\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,17,568218,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0227402274, ZO0079000790\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,568278,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536705367, ZO0449804498\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,568428,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0408404084, ZO0422304223\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,568492,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0346103461, ZO0054100541\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,569262,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0609906099, ZO0614806148\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,569306,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0412004120, ZO0625406254\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,21,569223,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0444004440, ZO0596805968\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,568039,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0599705997, ZO0416704167\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,568117,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315203152, ZO0406304063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,568165,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0065600656, ZO0337003370\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568393,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0374103741, ZO0242102421\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,567996,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0105401054, ZO0046200462\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,569173,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0452204522, ZO0631206312\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,49,569209,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0472304723, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,568865,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0294502945, ZO0560605606\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,568926,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0298302983, ZO0300003000\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,568955,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0068900689, ZO0076200762\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,569056,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0494804948, ZO0096000960\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,569083,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0099000990, ZO0631606316\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,717726,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,568149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0342503425, ZO0675206752\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,568192,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0485504855, ZO0355603556\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569183,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0641206412, ZO0165301653\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,568818,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0294802948, ZO0451404514\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568854,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616706167, ZO0255402554\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,4,568901,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0466704667, ZO0427104271\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,568954,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0399603996, ZO0685906859\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,569033,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0015700157, ZO0362503625\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,11,569091,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0258602586, ZO0552205522\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,569003,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0414704147, ZO0387503875\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,41,568707,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0513305133, ZO0253302533\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,568019,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0530805308, ZO0563905639\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,568182,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0338603386, ZO0641006410\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569299,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519605196, ZO0630806308\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,13,569123,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0609006090, ZO0441504415\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,728335,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0134701347, ZO0026200262, ZO0223102231, ZO0022900229\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,726874,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0362303623, ZO0035400354, ZO0705207052, ZO0504005040\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,569218,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0633206332, ZO0488604886\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,722613,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0618806188, ZO0442804428, ZO0530705307, ZO0410804108\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,568152,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0349303493, ZO0043900439\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,568212,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536405364, ZO0688306883\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,568228,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0580005800\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568455,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0413104131, ZO0392303923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,567994,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0430904309, ZO0288402884\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,568045,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0160501605, ZO0069500695\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568308,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0138701387, ZO0024600246\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,568515,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0159901599, ZO0238702387\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,721706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,569250,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0228902289, ZO0005400054\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568776,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616906169, ZO0296902969\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,568014,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0523905239, ZO0556605566\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,568702,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0142801428, ZO0182801828\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,568128,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0087500875, ZO0007100071\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568177,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0584505845, ZO0403804038\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,569178,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0177001770, ZO0260502605\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,568877,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0132401324, ZO0058200582\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,33,568898,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0542205422, ZO0517805178\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,568941,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0076600766, ZO0068800688\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,12,569027,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0245402454, ZO0060100601\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,569055,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0375903759, ZO0269402694\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,569107,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0339603396, ZO0504705047\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,714385,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0586805868, ZO0609106091, ZO0310903109, ZO0420104201\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,723213,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0297802978, ZO0456704567, ZO0572105721, ZO0280502805\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,568325,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0288202882, ZO0391803918\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,568360,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0480304803, ZO0274402744\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,569278,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0271802718, ZO0057100571\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,568816,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0146601466, ZO0108601086\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,21,568375,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0623606236, ZO0605306053\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,38,568559,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0599005990, ZO0626506265\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,45,568611,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0174701747, ZO0305103051\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,568638,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0388003880, ZO0478304783\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,568706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0672206722, ZO0331903319\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",EUR,25,716889,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,728580,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0156601566, ZO0498004980, ZO0070700707, ZO0086700867\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,568762,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0052200522, ZO0265602656\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,568571,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0034100341, ZO0343103431\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,568671,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0637406374, ZO0219002190\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,568774,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0037200372, ZO0369303693\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568319,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0535105351, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,568363,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0629806298, ZO0467104671\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568541,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0428904289, ZO0588205882\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,568586,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0232202322, ZO0208402084\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,568636,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0503905039, ZO0631806318\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,568674,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0192301923, ZO0011400114\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,9,567868,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0310403104, ZO0416604166\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,567446,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0322803228, ZO0002700027\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,7,567340,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0615606156, ZO0514905149\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,567736,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0663706637, ZO0620906209\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567755,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0571405714, ZO0255402554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,715455,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0477504775, ZO0613206132, ZO0585405854, ZO0110701107\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566768,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0217702177, ZO0331703317\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,566812,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0266902669, ZO0244202442\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,9,566680,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0316703167, ZO0393303933\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,566944,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0497004970, ZO0054900549\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566979,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0071900719, ZO0493404934\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,11,566734,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0691006910, ZO0314203142\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,567094,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0442904429, ZO0629706297\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,566892,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589505895, ZO0575405754\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,567950,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0273002730, ZO0541105411\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,566826,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0575305753, ZO0540605406\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567240,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421004210, ZO0689006890\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,567290,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0442704427\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,24,567669,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0148301483, ZO0202902029\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,567365,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0008600086, ZO0266002660\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,566845,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0547905479, ZO0583305833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567048,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0566905669, ZO0564005640\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,567281,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0221402214, ZO0632806328\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,567119,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0711507115, ZO0350903509\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,567169,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0558805588, ZO0622206222\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567869,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0565105651, ZO0443804438\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,567909,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0609606096, ZO0588905889\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,567524,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0096300963, ZO0377403774\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,567565,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0015600156, ZO0323603236\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,567019,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0151301513, ZO0204902049\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,567069,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0503805038, ZO0047500475\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,567935,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0116101161, ZO0574305743\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,566831,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0341103411, ZO0648406484\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,567543,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0608106081, ZO0296502965\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,567598,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0039400394, ZO0672906729\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,567876,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0705707057, ZO0047700477\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,567684,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0201202012, ZO0035000350\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,7,567790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0522405224, ZO0405104051\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,567465,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0274502745, ZO0686006860\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,50,567256,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0461004610, ZO0702707027\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,13,716462,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0549505495, ZO0458504585, ZO0602506025, ZO0617506175\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,566775,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0671006710, ZO0708007080\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,567926,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0113301133, ZO0562105621\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566829,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0100901009, ZO0235102351\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,567666,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0311403114, ZO0282002820\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,567383,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0647406474, ZO0330703307\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567381,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278402784, ZO0458304583\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,567437,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0275902759, ZO0545005450\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,567324,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0426604266, ZO0629406294\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,21,567504,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0606506065, ZO0277702777\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,42,567623,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0239802398, ZO0645406454\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,567400,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0605606056, ZO0588105881\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,566757,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0196201962, ZO0168601686\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,566884,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0490204902, ZO0025000250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,567815,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0263602636, ZO0241002410\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,567177,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0197301973, ZO0180401804\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,733060,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0155601556, ZO0013600136, ZO0235702357, ZO0383203832\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,567486,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0058200582, ZO0365503655\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,567625,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0328603286, ZO0328803288\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,10,567224,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0128501285, ZO0606306063\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,567252,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0369803698, ZO0220502205\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,567735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0129701297, ZO0518705187\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,567822,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0244802448, ZO0346303463\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,31,567852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0523805238, ZO0596505965\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,566861,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0520305203, ZO0462204622\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,567042,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0243002430, ZO0103901039\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,731037,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0148801488, ZO0335003350, ZO0155301553, ZO0074300743\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,567729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0395103951, ZO0296102961\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567384,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0426704267, ZO0612006120\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,566690,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0449004490, ZO0118501185\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,49,566951,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0517405174\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,566982,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0149301493, ZO0099800998\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,566725,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0444404444, ZO0584205842\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,566856,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0216502165, ZO0327503275\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,567039,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0184101841, ZO0711207112\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,567068,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0038000380, ZO0711007110\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,5,732229,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0175701757, ZO0163801638, ZO0697506975, ZO0245602456\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,724806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0643106431, ZO0033300333, ZO0696206962, ZO0651206512\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567769,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0414004140, ZO0630106301\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,566772,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0152901529, ZO0019100191\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567318,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421104211, ZO0256202562\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,6,567615,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0013500135, ZO0174501745\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,567316,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0403004030\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,566896,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0242702427, ZO0090000900\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,567418,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400404004, ZO0625006250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,567462,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0644406444, ZO0709307093\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,567667,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0273802738, ZO0300303003\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,567703,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0037900379, ZO0134901349\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,567260,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0068100681, ZO0674106741\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,724844,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0707507075, ZO0246402464, ZO0226802268, ZO0343503435\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,567308,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0181601816, ZO0011000110\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,567404,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0107101071, ZO0537905379\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,31,567538,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0596905969, ZO0450804508\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,46,567593,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0655306553, ZO0208902089\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,15,567294,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0317403174, ZO0457204572\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,728256,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0371903719, ZO0352803528, ZO0137501375, ZO0229202292\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,567544,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0585005850, ZO0120301203\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567592,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0535405354, ZO0291302913\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,566942,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0084000840, ZO0636606366\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,567015,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0558605586, ZO0527805278\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,28,567081,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0209702097, ZO0186301863\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567475,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0578805788, ZO0520405204\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,567631,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0101101011, ZO0667406674\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,567454,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0645406454, ZO0166001660\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,567855,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0657106571, ZO0084800848\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567835,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589405894, ZO0483304833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,567889,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0282202822, ZO0393003930\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,566852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0257002570, ZO0455404554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,5,567037,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0206402064, ZO0365903659\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,721778,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,38,567143,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0573005730, ZO0313203132\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,567191,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0113901139, ZO0478904789\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,567135,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0528305283, ZO0549305493\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,727730,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0050600506, ZO0710907109, ZO0023300233, ZO0334603346\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,567939,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0127201272, ZO0425504255\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567970,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0441504415, ZO0691606916\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,567301,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0577605776, ZO0438104381\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566801,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0279702797, ZO0573705737\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566685,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0296902969, ZO0530205302\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,566924,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0673606736, ZO0161801618\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,11,567662,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0308903089, ZO0614306143\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,20,567708,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0090500905, ZO0466204662\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,567573,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0215602156, ZO0336803368\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,717603,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,566986,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0360903609, ZO0030100301\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0632406324, ZO0060300603\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,9,567082,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278802788, ZO0515605156\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,566881,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0419604196, ZO0559705597\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,20,566790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0699206992, ZO0641306413\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,566706,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0521505215, ZO0130501305\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,566935,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0473704737, ZO0121501215\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,566985,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0044700447, ZO0502105021\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,566729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0110401104\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,567095,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0339803398, ZO0098200982\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,724326,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0499404994, ZO0641606416, ZO0334303343, ZO0676706767\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,567806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0517705177, ZO0569305693\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,567973,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0495104951, ZO0305903059\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,567341,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0674506745, ZO0219202192\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,567492,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0277302773, ZO0443004430\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567654,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0399403994\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,567403,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0138601386, ZO0259202592\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,567207,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0033600336, ZO0109401094\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,13,567356,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0319503195, ZO0409904099\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565855,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0417504175, ZO0535205352\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,565915,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0515005150, ZO0509805098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566343,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0185101851, ZO0052800528\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,26,566400,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0204702047, ZO0009600096\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565776,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0343103431, ZO0345803458\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566607,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0572205722, ZO0585205852\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565452,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0133601336, ZO0643906439\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,566051,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0025600256, ZO0270202702\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565466,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0285402854, ZO0538605386\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566553,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0435004350, ZO0544005440\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,565446,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0643206432, ZO0140101401\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,566053,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0284702847, ZO0299202992\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,565605,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0113301133\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,566170,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0324803248, ZO0703907039\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,566187,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0548905489, ZO0459404594\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,566125,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0433104331, ZO0549505495\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566156,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0117901179\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,6,566100,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0013400134, ZO0667306673\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,566280,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0573205732, ZO0116701167\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,31,565708,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0253302533, ZO0605706057\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,565809,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0557905579, ZO0513705137\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,566256,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0227302273, ZO0668706687\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,27,565639,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0193901939, ZO0080400804\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,565684,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0507705077, ZO0409804098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565945,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0270602706, ZO0269502695\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,18,565988,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0074700747, ZO0645206452\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,15,565732,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0291402914, ZO0603006030\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,29,566042,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0451804518, ZO0127901279\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,566456,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0597105971, ZO0283702837\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,565542,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0224302243, ZO0359103591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,566121,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0227202272, ZO0357003570\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,36,566101,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0691406914, ZO0617806178\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,566653,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0666506665, ZO0216602166\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,565838,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0343703437, ZO0207102071\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,565804,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0306803068, ZO0174601746\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,31,566247,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0403504035\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,566036,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0583605836, ZO0510605106\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,565459,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0242302423, ZO0676006760\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565819,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0031700317, ZO0157701577\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,731352,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0018200182, ZO0016100161, ZO0329703297, ZO0057800578\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,565667,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0618706187, ZO0388503885\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565900,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0266102661, ZO0169701697\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,566360,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0285102851, ZO0658306583\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,33,566416,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0396903969, ZO0607906079\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,46,565796,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0081500815, ZO0342603426\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,566261,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0577105771, ZO0289302893\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,565567,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0437604376, ZO0618906189\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,565596,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0332903329, ZO0159401594\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,52,717206,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,715081,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,566428,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0136501365, ZO0339103391\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,566334,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0010800108, ZO0635706357\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566391,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0228302283, ZO0167501675\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,715133,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,717057,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,566315,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0703707037, ZO0139601396\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565698,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0336503365, ZO0637006370\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,566167,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623006230, ZO0419304193\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,566215,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0579305793\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,566070,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0046100461, ZO0151201512\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,16,566621,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0579605796, ZO0315803158\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,566284,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0541405414, ZO0588205882\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,566518,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0554605546, ZO0569005690\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,25,565580,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0395303953, ZO0386703867\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,565830,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0215702157, ZO0638806388\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,16,566454,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0547405474, ZO0401104011\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,30,566506,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0680806808, ZO0609306093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,22,565948,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0190701907, ZO0654806548\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,565998,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0238802388, ZO0066600666\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565401,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0014800148, ZO0154501545\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,565728,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0486404864, ZO0248602486\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,565489,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0077200772, ZO0643006430\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565366,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0684906849, ZO0575905759\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,25,720445,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0423004230, ZO0292702927, ZO0320003200, ZO0318303183\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565768,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0458004580, ZO0273402734\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,565538,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0486804868, ZO0371603716\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,565404,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0048900489, ZO0228702287\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,715961,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0444904449, ZO0292502925, ZO0434604346, ZO0461804618\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,566382,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0503505035, ZO0240302403\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,565877,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0125401254, ZO0123701237\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,566364,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0525005250\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,48,565479,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0588805888, ZO0314903149\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565360,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0450704507\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,565734,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0513205132, ZO0258202582\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,566514,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0539305393, ZO0522305223\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,565970,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0673406734, ZO0165601656\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,27,723242,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0643306433, ZO0088900889, ZO0634406344\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,720399,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,566580,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0417304173, ZO0123001230\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,566671,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0427604276, ZO0113801138\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,566176,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0607206072, ZO0431404314\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,566146,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0646206462, ZO0146201462\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565760,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0504505045, ZO0223802238\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,565521,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0660406604, ZO0484504845\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,566320,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0105001050, ZO0652306523\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,566357,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0061600616, ZO0180701807\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,566415,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0261102611, ZO0667106671\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566044,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0552605526, ZO0292702927\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,565473,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0365303653, ZO0235802358\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,565339,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0346503465, ZO0678406784\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565591,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0683806838, ZO0429204292\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,5,730725,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0501605016, ZO0189601896, ZO0363003630, ZO0699306993\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,566443,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0160201602, ZO0261502615\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,566498,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0550005500\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,565985,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0436604366, ZO0280302803\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565640,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0631606316, ZO0045300453\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,49,565683,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0573205732, ZO0310303103\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565767,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0414304143, ZO0425204252\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,566452,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0706307063, ZO0011300113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,13,565982,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0410804108, ZO0309303093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,726754,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0138001380, ZO0648006480, ZO0193501935, ZO0228402284\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,24,565723,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0302303023, ZO0246602466\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,31,565896,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0466104661, ZO0444104441\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,52,718085,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0129001290, ZO0310103101, ZO0547805478, ZO0560805608\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,566248,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0678806788, ZO0186101861\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,565560,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0567505675, ZO0442104421\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,8,566186,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0522105221, ZO0459104591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,566155,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0501005010, ZO0214002140\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,28,566628,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0195601956, ZO0098900989\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,9,566519,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0700907009, ZO0115801158\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,565697,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0498904989, ZO0641706417\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,45,566417,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0084900849, ZO0194701947\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,565722,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0656406564, ZO0495504955\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,565330,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0621606216, ZO0628806288\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,44,565381,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0060200602, ZO0076300763\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,565564,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0576305763, ZO0116801168\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565392,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0616606166, ZO0592205922\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,6,565410,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0023600236, ZO0704307043\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565504,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0653406534, ZO0049300493\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,565334,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0641706417, ZO0382303823\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,566079,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0663306633, ZO0687306873\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,566622,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0228402284, ZO0082300823\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,566650,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0049100491, ZO0194801948\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,566295,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0635606356, ZO0043100431\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566538,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0224402244, ZO0342403424\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,565918,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0155001550, ZO0072100721\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,565678,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0081800818, ZO0485604856\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,566564,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0107301073, ZO0293002930\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,565498,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0503305033\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,565793,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0712807128, ZO0007500075\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,566232,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0545205452, ZO0437304373\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,25,566259,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0553805538\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,566591,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0502405024, ZO0366003660\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,564670,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0531205312, ZO0684706847\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564710,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0263402634, ZO0499404994\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564429,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0260702607, ZO0495804958\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564479,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0409304093, ZO0436904369\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,564513,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0390003900, ZO0287902879\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,6,564885,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303803038, ZO0192501925\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565150,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0624906249, ZO0411604116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,13,565206,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316303163, ZO0401004010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564759,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218802188, ZO0492604926\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,564144,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218602186, ZO0501005010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,563909,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452804528, ZO0453604536\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,28,564869,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0192401924, ZO0366703667\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,564619,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0470304703, ZO0406204062\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,34,564237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0311203112, ZO0395703957\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,564269,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0281102811, ZO0555705557\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,564842,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0432004320, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,564893,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0322403224, ZO0227802278\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564215,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0147201472, ZO0152201522\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564725,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0071700717, ZO0364303643\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,564733,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0384303843, ZO0273702737\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564331,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0229402294, ZO0303303033\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564350,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444104441, ZO0476804768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564398,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0328703287, ZO0351003510\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,564409,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0178501785, ZO0503805038\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,564024,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0619006190\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,564271,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0507905079, ZO0430804308\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564676,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0108401084, ZO0139301393\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,564445,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0701407014\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,50,564241,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0605506055, ZO0547505475\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,564272,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0512105121\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564844,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0553205532, ZO0526205262\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,564883,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0705607056, ZO0334703347\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,564307,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0246602466, ZO0195201952\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564148,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0057900579, ZO0211602116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,564009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0487904879, ZO0027100271\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,564532,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0474704747, ZO0622006220\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565308,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0172401724, ZO0184901849\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,27,564339,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0082900829, ZO0347903479\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,564361,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0422304223, ZO0600506005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564394,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0269902699, ZO0667906679\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564030,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0179901799, ZO0637606376\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564661,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415004150, ZO0125501255\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564706,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0709007090, ZO0362103621\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564460,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0655106551, ZO0349403494\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,564536,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0304603046, ZO0370603706\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,564559,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0015500155, ZO0650806508\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564609,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0162401624, ZO0156001560\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,565138,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0615506155, ZO0445304453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,565025,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0280802808, ZO0549005490\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,564000,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0364603646, ZO0018200182\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,564557,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0664606646, ZO0460404604\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,564604,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0237702377, ZO0304303043\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,564777,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452704527, ZO0122201222\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,564812,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0266002660, ZO0031900319\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,715752,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,563964,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0001200012, ZO0251902519\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564315,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0263702637\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0323303233, ZO0172101721\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,565090,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0690306903, ZO0521005210\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,564649,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0405704057, ZO0411704117\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564510,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093600936, ZO0145301453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,565222,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0102001020, ZO0252402524\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,565233,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0614906149, ZO0430404304\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565084,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0549805498, ZO0541205412\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564796,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0022100221, ZO0172301723\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564627,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0211702117, ZO0499004990\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,564257,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539205392, ZO0577705777\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,564701,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0585205852, ZO0418104181\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,564915,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0286502865, ZO0394703947\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,564954,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0362903629, ZO0048100481\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0225302253, ZO0183101831\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564065,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711207112, ZO0646106461\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,563927,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0009800098, ZO0362803628\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,564937,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0520605206, ZO0432204322\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,564994,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0180601806, ZO0710007100\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,564070,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0234202342, ZO0245102451\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,563928,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0394103941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,727071,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,565284,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0687206872, ZO0422304223\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,564380,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0050400504, ZO0660006600\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,565276,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0131501315, ZO0668806688\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564819,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0374603746, ZO0697106971\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,717243,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,564140,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0268502685\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,564164,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0673506735, ZO0213002130\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564207,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711807118, ZO0073100731\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,564735,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0509705097, ZO0120501205\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565077,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118701187, ZO0123901239\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564274,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0542905429, ZO0423604236\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565161,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0441404414, ZO0430504305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,565039,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0489804898, ZO0695006950\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,723683,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,563967,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0493404934, ZO0640806408\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,564533,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0496704967, ZO0049700497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,49,565266,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0255602556, ZO0468304683\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,564818,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0475004750, ZO0412304123\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,23,564932,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0607806078\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,564968,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0134101341, ZO0062400624\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565002,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0354203542, ZO0338503385\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,564095,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0613806138, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,563924,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539805398, ZO0554205542\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,564770,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0704907049, ZO0024700247\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,563965,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0045800458, ZO0503405034\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564957,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0171601716, ZO0214602146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,41,564032,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0478404784, ZO0521905219\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,37,564075,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0622706227, ZO0525405254\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,563931,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444304443, ZO0596505965\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,564940,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0026800268, ZO0003600036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564987,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0526805268, ZO0478104781\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,564080,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415804158, ZO0460804608\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,8,564106,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0298002980, ZO0313103131\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,563947,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0348103481, ZO0164501645\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,725995,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,564756,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0556805568, ZO0481504815\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565137,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118501185, ZO0561905619\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,565173,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0203802038, ZO0014900149\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565214,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0588705887\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564804,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0259702597, ZO0640606406\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,565052,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697006970, ZO0711407114\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,45,565091,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0324703247, ZO0088600886\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,565231,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0235202352, ZO0135001350\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564190,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0243902439, ZO0208702087\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,564876,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0215502155, ZO0168101681\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,564902,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0698406984, ZO0704207042\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564761,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0665006650, ZO0709407094\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,731788,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,564340,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0565805658\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,564395,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0236702367, ZO0660706607\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,564686,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0373303733, ZO0131201312\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,564446,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093400934, ZO0679406794\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,43,564481,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0321603216, ZO0078000780\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,563953,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0376203762, ZO0303603036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,565061,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0286402864\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565100,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0069000690, ZO0490004900\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565263,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0582705827, ZO0111801118\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,563984,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0294102941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,12,565262,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303503035, ZO0197601976\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,565304,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0017800178, ZO0229602296\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,565123,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316903169, ZO0400504005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,565160,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0693306933, ZO0514605146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565224,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0576805768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564121,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0291902919, ZO0617206172\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,23,564166,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0607106071, ZO0470704707\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,564739,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0335603356, ZO0236502365\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564016,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0436904369, ZO0290402904\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,564576,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681206812, ZO0441904419\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,564605,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0333103331, ZO0694806948\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,17,730663,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,564366,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681906819, ZO0549705497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,564221,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0487404874\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,564174,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0032300323, ZO0236302363\\" +" `; -exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: default 2`] = ` -Array [ - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Dubai,\\"Tigress Enterprises MAMA, Pyramidustries, Angeldale\\",\\"Tigress Enterprises MAMA, Pyramidustries, Angeldale\\",\\"Jun 12, 2019 @ 00:00:00.000\\",731056,\\"sold_product_731056_22440, sold_product_731056_13969, sold_product_731056_20215, sold_product_731056_23401\\",\\"sold_product_731056_22440, sold_product_731056_13969, sold_product_731056_20215, sold_product_731056_23401\\",\\"33, 20.984, 75, 13.992\\",\\"33, 20.984, 75, 13.992\\",\\"Women's Clothing, Women's Accessories, Women's Shoes, Women's Accessories\\",\\"Women's Clothing, Women's Accessories, Women's Shoes, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises MAMA, Pyramidustries, Angeldale, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries, Angeldale, Pyramidustries\\",\\"15.18, 10.289, 39, 6.719\\",\\"33, 20.984, 75, 13.992\\",\\"22,440, 13,969, 20,215, 23,401\\",\\"Jersey dress - fan/black, Across body bag - Blue Violety, Boots - black, Hat - nude\\",\\"Jersey dress - fan/black, Across body bag - Blue Violety, Boots - black, Hat - nude\\",\\"1, 1, 1, 1\\",\\"ZO0230102301, ZO0210602106, ZO0679006790, ZO0187301873\\",\\"0, 0, 0, 0\\",\\"33, 20.984, 75, 13.992\\",\\"33, 20.984, 75, 13.992\\",\\"0, 0, 0, 0\\",\\"ZO0230102301, ZO0210602106, ZO0679006790, ZO0187301873\\",143,143,4,4,order,rabbia", - "4AMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Pope\\",\\"Yahya Pope\\",MALE,23,Pope,Pope,\\"(empty)\\",Thursday,3,\\"yahya@pope-family.zzz\\",Marrakesh,Africa,MA,\\"{", - " \\"\\"coordinates\\"\\": [", - " -8,", - " 31.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 12, 2019 @ 00:00:00.000\\",551556,\\"sold_product_551556_1583, sold_product_551556_11991\\",\\"sold_product_551556_1583, sold_product_551556_11991\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"17.813, 3.76\\",\\"33, 7.988\\",\\"1,583, 11,991\\",\\"High-top trainers - black, Basic T-shirt - black\\",\\"High-top trainers - black, Basic T-shirt - black\\",\\"1, 1\\",\\"ZO0512405124, ZO0551405514\\",\\"0, 0\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"0, 0\\",\\"ZO0512405124, ZO0551405514\\",\\"40.969\\",\\"40.969\\",2,2,order,yahya", - "4QMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Morrison\\",\\"George Morrison\\",MALE,32,Morrison,Morrison,\\"(empty)\\",Thursday,3,\\"george@morrison-family.zzz\\",Birmingham,Europe,GB,\\"{", - " \\"\\"coordinates\\"\\": [", - " -1.9,", - " 52.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Birmingham,\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 12, 2019 @ 00:00:00.000\\",551609,\\"sold_product_551609_3728, sold_product_551609_23435\\",\\"sold_product_551609_3728, sold_product_551609_23435\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"10.703, 10.289\\",\\"20.984, 20.984\\",\\"3,728, 23,435\\",\\"Base layer - khaki, Shirt - red\\",\\"Base layer - khaki, Shirt - red\\",\\"1, 1\\",\\"ZO0630606306, ZO0524705247\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0630606306, ZO0524705247\\",\\"41.969\\",\\"41.969\\",2,2,order,george", - "\\"_wMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Morris\\",\\"Yuri Morris\\",MALE,21,Morris,Morris,\\"(empty)\\",Thursday,3,\\"yuri@morris-family.zzz\\",Cannes,Europe,FR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 7,", - " 43.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Alpes-Maritimes\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550473,\\"sold_product_550473_20161, sold_product_550473_6991\\",\\"sold_product_550473_20161, sold_product_550473_6991\\",\\"65, 38\\",\\"65, 38\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"30.547, 20.125\\",\\"65, 38\\",\\"20,161, 6,991\\",\\"Lace-up boots - dark tan, Jumper - dark blue\\",\\"Lace-up boots - dark tan, Jumper - dark blue\\",\\"1, 1\\",\\"ZO0688006880, ZO0450504505\\",\\"0, 0\\",\\"65, 38\\",\\"65, 38\\",\\"0, 0\\",\\"ZO0688006880, ZO0450504505\\",103,103,2,2,order,yuri", - "AAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Brigitte,Brigitte,\\"Brigitte Long\\",\\"Brigitte Long\\",FEMALE,12,Long,Long,\\"(empty)\\",Thursday,3,\\"brigitte@long-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 12, 2019 @ 00:00:00.000\\",550542,\\"sold_product_550542_11839, sold_product_550542_21052\\",\\"sold_product_550542_11839, sold_product_550542_21052\\",\\"24.984, 9.992\\",\\"24.984, 9.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"12.992, 4.898\\",\\"24.984, 9.992\\",\\"11,839, 21,052\\",\\"High heeled sandals - cognac, Snood - black/red/green/yellow\\",\\"High heeled sandals - cognac, Snood - black/red/green/yellow\\",\\"1, 1\\",\\"ZO0137301373, ZO0192601926\\",\\"0, 0\\",\\"24.984, 9.992\\",\\"24.984, 9.992\\",\\"0, 0\\",\\"ZO0137301373, ZO0192601926\\",\\"34.969\\",\\"34.969\\",2,2,order,brigitte", - "AQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,rania,rania,\\"rania Barnes\\",\\"rania Barnes\\",FEMALE,24,Barnes,Barnes,\\"(empty)\\",Thursday,3,\\"rania@barnes-family.zzz\\",Cairo,Africa,EG,\\"{", - " \\"\\"coordinates\\"\\": [", - " 31.3,", - " 30.1", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Cairo Governorate\\",\\"Pyramidustries, Pyramidustries active\\",\\"Pyramidustries, Pyramidustries active\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550580,\\"sold_product_550580_20312, sold_product_550580_10155\\",\\"sold_product_550580_20312, sold_product_550580_10155\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries active\\",\\"Pyramidustries, Pyramidustries active\\",\\"24, 8.656\\",\\"50, 16.984\\",\\"20,312, 10,155\\",\\"Lace-up boots - cognac, Sports shirt - black\\",\\"Lace-up boots - cognac, Sports shirt - black\\",\\"1, 1\\",\\"ZO0144801448, ZO0219602196\\",\\"0, 0\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"0, 0\\",\\"ZO0144801448, ZO0219602196\\",67,67,2,2,order,rani", - "BwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Tyler\\",\\"Abdulraheem Al Tyler\\",MALE,33,Tyler,Tyler,\\"(empty)\\",Thursday,3,\\"abdulraheem al@tyler-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{", - " \\"\\"coordinates\\"\\": [", - " 54.4,", - " 24.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Abu Dhabi\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 12, 2019 @ 00:00:00.000\\",551324,\\"sold_product_551324_14742, sold_product_551324_19089\\",\\"sold_product_551324_14742, sold_product_551324_19089\\",\\"33, 12.992\\",\\"33, 12.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"15.18, 7.012\\",\\"33, 12.992\\",\\"14,742, 19,089\\",\\"Laptop bag - brown, Vest - white/dark blue\\",\\"Laptop bag - brown, Vest - white/dark blue\\",\\"1, 1\\",\\"ZO0316803168, ZO0566905669\\",\\"0, 0\\",\\"33, 12.992\\",\\"33, 12.992\\",\\"0, 0\\",\\"ZO0316803168, ZO0566905669\\",\\"45.969\\",\\"45.969\\",2,2,order,abdulraheem", - "mwMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan James\\",\\"Marwan James\\",MALE,51,James,James,\\"(empty)\\",Thursday,3,\\"marwan@james-family.zzz\\",Marrakesh,Africa,MA,\\"{", - " \\"\\"coordinates\\"\\": [", - " -8,", - " 31.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 12, 2019 @ 00:00:00.000\\",551355,\\"sold_product_551355_21057, sold_product_551355_23405\\",\\"sold_product_551355_21057, sold_product_551355_23405\\",\\"13.992, 11.992\\",\\"13.992, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"6.859, 5.762\\",\\"13.992, 11.992\\",\\"21,057, 23,405\\",\\"Scarf - navy/grey, Basic T-shirt - blue\\",\\"Scarf - navy/grey, Basic T-shirt - blue\\",\\"1, 1\\",\\"ZO0313403134, ZO0561205612\\",\\"0, 0\\",\\"13.992, 11.992\\",\\"13.992, 11.992\\",\\"0, 0\\",\\"ZO0313403134, ZO0561205612\\",\\"25.984\\",\\"25.984\\",2,2,order,marwan", - "twMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Mccormick\\",\\"Sonya Mccormick\\",FEMALE,28,Mccormick,Mccormick,\\"(empty)\\",Thursday,3,\\"sonya@mccormick-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74.1,", - " 4.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Bogota D.C.\\",Pyramidustries,Pyramidustries,\\"Jun 12, 2019 @ 00:00:00.000\\",550957,\\"sold_product_550957_22980, sold_product_550957_19828\\",\\"sold_product_550957_22980, sold_product_550957_19828\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"11.5, 9.172\\",\\"24.984, 16.984\\",\\"22,980, 19,828\\",\\"Classic heels - petrol, Watch - nude\\",\\"Classic heels - petrol, Watch - nude\\",\\"1, 1\\",\\"ZO0133101331, ZO0189401894\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0133101331, ZO0189401894\\",\\"41.969\\",\\"41.969\\",2,2,order,sonya", - "7AMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Hansen\\",\\"Kamal Hansen\\",MALE,39,Hansen,Hansen,\\"(empty)\\",Thursday,3,\\"kamal@hansen-family.zzz\\",Istanbul,Asia,TR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 29,", - " 41", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Istanbul,\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 12, 2019 @ 00:00:00.000\\",551154,\\"sold_product_551154_13181, sold_product_551154_23660\\",\\"sold_product_551154_13181, sold_product_551154_23660\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"21, 6.109\\",\\"42, 11.992\\",\\"13,181, 23,660\\",\\"Briefcase - navy, Sports shirt - Seashell\\",\\"Briefcase - navy, Sports shirt - Seashell\\",\\"1, 1\\",\\"ZO0466704667, ZO0617306173\\",\\"0, 0\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"0, 0\\",\\"ZO0466704667, ZO0617306173\\",\\"53.969\\",\\"53.969\\",2,2,order,kamal", - "7QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Graves\\",\\"Elyssa Graves\\",FEMALE,27,Graves,Graves,\\"(empty)\\",Thursday,3,\\"elyssa@graves-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 12, 2019 @ 00:00:00.000\\",551204,\\"sold_product_551204_16805, sold_product_551204_12896\\",\\"sold_product_551204_16805, sold_product_551204_12896\\",\\"13.992, 20.984\\",\\"13.992, 20.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"7.129, 9.656\\",\\"13.992, 20.984\\",\\"16,805, 12,896\\",\\"Bustier - white, Across body bag - cognac\\",\\"Bustier - white, Across body bag - cognac\\",\\"1, 1\\",\\"ZO0212602126, ZO0200702007\\",\\"0, 0\\",\\"13.992, 20.984\\",\\"13.992, 20.984\\",\\"0, 0\\",\\"ZO0212602126, ZO0200702007\\",\\"34.969\\",\\"34.969\\",2,2,order,elyssa", - "7gMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Rose\\",\\"Pia Rose\\",FEMALE,45,Rose,Rose,\\"(empty)\\",Thursday,3,\\"pia@rose-family.zzz\\",Cannes,Europe,FR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 7,", - " 43.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Primemaster\\",\\"Oceanavigations, Primemaster\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550466,\\"sold_product_550466_19198, sold_product_550466_16409\\",\\"sold_product_550466_19198, sold_product_550466_16409\\",\\"50, 100\\",\\"50, 100\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Primemaster\\",\\"Oceanavigations, Primemaster\\",\\"24, 52\\",\\"50, 100\\",\\"19,198, 16,409\\",\\"Summer dress - grey, Boots - passion\\",\\"Summer dress - grey, Boots - passion\\",\\"1, 1\\",\\"ZO0260702607, ZO0363203632\\",\\"0, 0\\",\\"50, 100\\",\\"50, 100\\",\\"0, 0\\",\\"ZO0260702607, ZO0363203632\\",150,150,2,2,order,pia", - "7wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Boone\\",\\"Wagdi Boone\\",MALE,15,Boone,Boone,\\"(empty)\\",Thursday,3,\\"wagdi@boone-family.zzz\\",\\"-\\",Asia,SA,\\"{", - " \\"\\"coordinates\\"\\": [", - " 45,", - " 25", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 12, 2019 @ 00:00:00.000\\",550503,\\"sold_product_550503_13211, sold_product_550503_24369\\",\\"sold_product_550503_13211, sold_product_550503_24369\\",\\"34, 11.992\\",\\"34, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"15.641, 6.109\\",\\"34, 11.992\\",\\"13,211, 24,369\\",\\"Tracksuit top - black, Print T-shirt - khaki\\",\\"Tracksuit top - black, Print T-shirt - khaki\\",\\"1, 1\\",\\"ZO0587505875, ZO0566405664\\",\\"0, 0\\",\\"34, 11.992\\",\\"34, 11.992\\",\\"0, 0\\",\\"ZO0587505875, ZO0566405664\\",\\"45.969\\",\\"45.969\\",2,2,order,wagdi", - "8AMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Hale\\",\\"Elyssa Hale\\",FEMALE,27,Hale,Hale,\\"(empty)\\",Thursday,3,\\"elyssa@hale-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550538,\\"sold_product_550538_15047, sold_product_550538_18189\\",\\"sold_product_550538_15047, sold_product_550538_18189\\",\\"75, 60\\",\\"75, 60\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"34.5, 28.797\\",\\"75, 60\\",\\"15,047, 18,189\\",\\"Handbag - black, Ankle boots - grey\\",\\"Handbag - black, Ankle boots - grey\\",\\"1, 1\\",\\"ZO0699406994, ZO0246202462\\",\\"0, 0\\",\\"75, 60\\",\\"75, 60\\",\\"0, 0\\",\\"ZO0699406994, ZO0246202462\\",135,135,2,2,order,elyssa", - "8QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Love\\",\\"Jackson Love\\",MALE,13,Love,Love,\\"(empty)\\",Thursday,3,\\"jackson@love-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -118.2,", - " 34.1", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550568,\\"sold_product_550568_17210, sold_product_550568_12524\\",\\"sold_product_550568_17210, sold_product_550568_12524\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"25, 12.492\\",\\"50, 24.984\\",\\"17,210, 12,524\\",\\"Casual lace-ups - navy, Jumper - dark grey multicolor\\",\\"Casual lace-ups - navy, Jumper - dark grey multicolor\\",\\"1, 1\\",\\"ZO0388403884, ZO0447604476\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0388403884, ZO0447604476\\",75,75,2,2,order,jackson", -] +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with filtered data 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719675,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0686206862, ZO0395403954, ZO0528505285\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,570232,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0682006820, ZO0399103991\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570111,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0253002530, ZO0117101171\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,570480,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0286202862, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,719459,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0410004100, ZO0513605136, ZO0431404314, ZO0662906629\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,570303,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0573305733, ZO0513205132\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,569806,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0558305583\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,570477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0299202992, ZO0392403924\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,569743,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0610306103\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,38,714566,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0430204302, ZO0397303973, ZO0686806868, ZO0320403204\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,570120,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392903929, ZO0254802548\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,32,570414,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0481704817, ZO0396503965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,39,569436,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0386103861, ZO0451504515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,569637,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0300103001, ZO0688106881\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,569645,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392803928, ZO0277102771\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569362,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0292402924, ZO0681006810\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,52,713556,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0592105921, ZO0421204212, ZO0400604006, ZO0319403194\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570334,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0520205202, ZO0545205452\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,570143,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0482904829\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,570586,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0596505965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,569336,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0384103841\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,569984,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0537205372, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,34,570003,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0298902989, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,569392,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0516405164, ZO0532705327\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,31,569312,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0425104251, ZO0107901079\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,570009,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0510705107, ZO0594605946\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569985,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0554005540, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,569905,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0599605996, ZO0403804038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569699,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398603986, ZO0521305213\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,29,569736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0517305173, ZO0319703197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569777,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0254302543, ZO0289102891\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,36,570388,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0405604056, ZO0604506045\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,51,570620,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0422204222, ZO0256502565\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,569694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398703987, ZO0687806878\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,568331,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0385903859, ZO0516605166\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,568524,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0694706947\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,568682,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680706807, ZO0392603926\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,31,568350,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0317303173, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,31,568531,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0482104821, ZO0447104471\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,29,568578,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0520005200, ZO0421104211\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,568609,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0570405704, ZO0256102561\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,568652,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0403304033, ZO0125901259\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",EUR,25,714149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569163,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0682706827\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,15,568943,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0445804458, ZO0686106861\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,569046,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0393103931, ZO0619906199\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,33,568993,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482604826\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,568845,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0657906579, ZO0258102581\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,569097,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0511605116, ZO0483004830\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,568117,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315203152, ZO0406304063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,49,569209,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0472304723, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,717726,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568854,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616706167, ZO0255402554\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,568954,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0399603996, ZO0685906859\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,11,569091,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0258602586, ZO0552205522\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,569003,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0414704147, ZO0387503875\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,41,568707,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0513305133, ZO0253302533\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569299,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519605196, ZO0630806308\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,568212,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536405364, ZO0688306883\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,568228,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0580005800\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568455,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0413104131, ZO0392303923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,721706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568177,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0584505845, ZO0403804038\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,33,568898,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0542205422, ZO0517805178\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,568325,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0288202882, ZO0391803918\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,568638,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0388003880, ZO0478304783\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",EUR,25,716889,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568319,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0535105351, ZO0403504035\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,7,567340,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0615606156, ZO0514905149\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567755,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0571405714, ZO0255402554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,9,566680,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0316703167, ZO0393303933\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,11,566734,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0691006910, ZO0314203142\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567240,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421004210, ZO0689006890\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,567290,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0442704427\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,7,567790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0522405224, ZO0405104051\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,567465,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0274502745, ZO0686006860\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,567735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0129701297, ZO0518705187\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,566861,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0520305203, ZO0462204622\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,567729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0395103951, ZO0296102961\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,49,566951,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0517405174\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567318,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421104211, ZO0256202562\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,567316,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0403004030\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,567418,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400404004, ZO0625006250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,567404,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0107101071, ZO0537905379\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567475,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0578805788, ZO0520405204\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567835,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589405894, ZO0483304833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,567889,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0282202822, ZO0393003930\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,566852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0257002570, ZO0455404554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,721778,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567970,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0441504415, ZO0691606916\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,11,567662,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0308903089, ZO0614306143\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,717603,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,9,567082,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278802788, ZO0515605156\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,566706,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0521505215, ZO0130501305\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,567806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0517705177, ZO0569305693\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567654,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0399403994\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,565915,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0515005150, ZO0509805098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,565605,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0113301133\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,31,565708,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0253302533, ZO0605706057\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,565809,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0557905579, ZO0513705137\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,565684,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0507705077, ZO0409804098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,36,566101,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0691406914, ZO0617806178\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,31,566247,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0403504035\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,566036,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0583605836, ZO0510605106\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,565667,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0618706187, ZO0388503885\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,33,566416,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0396903969, ZO0607906079\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,52,717206,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,715081,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,715133,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,717057,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,566215,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0579305793\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,25,565580,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0395303953, ZO0386703867\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,16,566454,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0547405474, ZO0401104011\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,30,566506,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0680806808, ZO0609306093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565366,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0684906849, ZO0575905759\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,566364,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0525005250\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,565734,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0513205132, ZO0258202582\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,566514,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0539305393, ZO0522305223\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,720399,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565591,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0683806838, ZO0429204292\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,566498,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0550005500\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,8,566186,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0522105221, ZO0459104591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,566079,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0663306633, ZO0687306873\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,566564,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0107301073, ZO0293002930\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,25,566259,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0553805538\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,564670,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0531205312, ZO0684706847\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,564513,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0390003900, ZO0287902879\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,13,565206,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316303163, ZO0401004010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,564619,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0470304703, ZO0406204062\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,34,564237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0311203112, ZO0395703957\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,564842,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0432004320, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,564733,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0384303843, ZO0273702737\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,564271,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0507905079, ZO0430804308\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,564272,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0512105121\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,715752,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,565090,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0690306903, ZO0521005210\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,564649,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0405704057, ZO0411704117\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,564915,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0286502865, ZO0394703947\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,564937,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0520605206, ZO0432204322\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,563928,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0394103941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,565284,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0687206872, ZO0422304223\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,564735,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0509705097, ZO0120501205\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,49,565266,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0255602556, ZO0468304683\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,564095,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0613806138, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,41,564032,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0478404784, ZO0521905219\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,564756,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0556805568, ZO0481504815\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565214,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0588705887\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,564340,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0565805658\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,565061,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0286402864\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,565123,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316903169, ZO0400504005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,565160,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0693306933, ZO0514605146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565224,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0576805768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,564576,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681206812, ZO0441904419\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,564366,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681906819, ZO0549705497\\" +" `; -exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 1`] = ` -Array [ - "\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user", - "3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,\\"(empty)\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{", - " \\"\\"coordinates\\"\\": [", - " 54.4,", - " 24.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.375, 33, 10.344, 6.109\\",\\"80, 60, 21.984, 11.992\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",174,174,4,4,order,sultan", - "9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Richards\\",\\"Pia Richards\\",FEMALE,45,Richards,Richards,\\"(empty)\\",Saturday,5,\\"pia@richards-family.zzz\\",Cannes,Europe,FR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 7,", - " 43.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.703, 9.867\\",\\"20.984, 20.984\\",\\"14,761, 11,632\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0006400064, ZO0150601506\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0006400064, ZO0150601506\\",\\"41.969\\",\\"41.969\\",2,2,order,pia", - "BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"3.6, 17.484\\",\\"7.988, 33\\",\\"20,734, 7,539\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"1, 1\\",\\"ZO0638206382, ZO0038800388\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0638206382, ZO0038800388\\",\\"40.969\\",\\"40.969\\",2,2,order,brigitte", - "KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mccarthy\\",\\"Abd Mccarthy\\",MALE,52,Mccarthy,Mccarthy,\\"(empty)\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",Cairo,Africa,EG,\\"{", - " \\"\\"coordinates\\"\\": [", - " 31.3,", - " 30.1", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590937,\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"28.984, 12.992\\",\\"28.984, 12.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.344, 6.109\\",\\"28.984, 12.992\\",\\"14,438, 23,607\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0297602976, ZO0565605656\\",\\"0, 0\\",\\"28.984, 12.992\\",\\"28.984, 12.992\\",\\"0, 0\\",\\"ZO0297602976, ZO0565605656\\",\\"41.969\\",\\"41.969\\",2,2,order,abd", - "KgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Banks\\",\\"Robert Banks\\",MALE,29,Banks,Banks,\\"(empty)\\",Saturday,5,\\"robert@banks-family.zzz\\",\\"-\\",Asia,SA,\\"{", - " \\"\\"coordinates\\"\\": [", - " 45,", - " 25", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590976,\\"sold_product_590976_21270, sold_product_590976_13220\\",\\"sold_product_590976_21270, sold_product_590976_13220\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"6.23, 12.25\\",\\"11.992, 24.984\\",\\"21,270, 13,220\\",\\"Print T-shirt - white, Chinos - dark grey\\",\\"Print T-shirt - white, Chinos - dark grey\\",\\"1, 1\\",\\"ZO0561405614, ZO0281602816\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0561405614, ZO0281602816\\",\\"36.969\\",\\"36.969\\",2,2,order,robert", - "awMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jim,Jim,\\"Jim Hansen\\",\\"Jim Hansen\\",MALE,41,Hansen,Hansen,\\"(empty)\\",Saturday,5,\\"jim@hansen-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591636,\\"sold_product_591636_1295, sold_product_591636_6498\\",\\"sold_product_591636_1295, sold_product_591636_6498\\",\\"50, 50\\",\\"50, 50\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"25, 27.484\\",\\"50, 50\\",\\"1,295, 6,498\\",\\"Smart lace-ups - dark brown, Suit jacket - dark blue\\",\\"Smart lace-ups - dark brown, Suit jacket - dark blue\\",\\"1, 1\\",\\"ZO0385003850, ZO0408604086\\",\\"0, 0\\",\\"50, 50\\",\\"50, 50\\",\\"0, 0\\",\\"ZO0385003850, ZO0408604086\\",100,100,2,2,order,jim", - "eQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Thad,Thad,\\"Thad Lamb\\",\\"Thad Lamb\\",MALE,30,Lamb,Lamb,\\"(empty)\\",Saturday,5,\\"thad@lamb-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jul 12, 2019 @ 00:00:00.000\\",591539,\\"sold_product_591539_15260, sold_product_591539_14221\\",\\"sold_product_591539_15260, sold_product_591539_14221\\",\\"20.984, 18.984\\",\\"20.984, 18.984\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.078, 10.25\\",\\"20.984, 18.984\\",\\"15,260, 14,221\\",\\"Casual lace-ups - dark blue, Trainers - navy\\",\\"Casual lace-ups - dark blue, Trainers - navy\\",\\"1, 1\\",\\"ZO0505605056, ZO0513605136\\",\\"0, 0\\",\\"20.984, 18.984\\",\\"20.984, 18.984\\",\\"0, 0\\",\\"ZO0505605056, ZO0513605136\\",\\"39.969\\",\\"39.969\\",2,2,order,thad", - "egMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Bryant\\",\\"Jim Bryant\\",MALE,41,Bryant,Bryant,\\"(empty)\\",Saturday,5,\\"jim@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",Oceanavigations,Oceanavigations,\\"Jul 12, 2019 @ 00:00:00.000\\",591598,\\"sold_product_591598_20597, sold_product_591598_2774\\",\\"sold_product_591598_20597, sold_product_591598_2774\\",\\"10.992, 85\\",\\"10.992, 85\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"5.93, 45.875\\",\\"10.992, 85\\",\\"20,597, 2,774\\",\\"Tie - brown/black , Classic coat - black\\",\\"Tie - brown/black , Classic coat - black\\",\\"1, 1\\",\\"ZO0276702767, ZO0291702917\\",\\"0, 0\\",\\"10.992, 85\\",\\"10.992, 85\\",\\"0, 0\\",\\"ZO0276702767, ZO0291702917\\",96,96,2,2,order,jim", - "fwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Roberson\\",\\"Betty Roberson\\",FEMALE,44,Roberson,Roberson,\\"(empty)\\",Saturday,5,\\"betty@roberson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.7", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590927,\\"sold_product_590927_15436, sold_product_590927_22598\\",\\"sold_product_590927_15436, sold_product_590927_22598\\",\\"28.984, 28.984\\",\\"28.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"14.781, 14.781\\",\\"28.984, 28.984\\",\\"15,436, 22,598\\",\\"Jersey dress - anthra/black, Shift dress - black\\",\\"Jersey dress - anthra/black, Shift dress - black\\",\\"1, 1\\",\\"ZO0046600466, ZO0050800508\\",\\"0, 0\\",\\"28.984, 28.984\\",\\"28.984, 28.984\\",\\"0, 0\\",\\"ZO0046600466, ZO0050800508\\",\\"57.969\\",\\"57.969\\",2,2,order,betty", - "gAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Hubbard\\",\\"Robbie Hubbard\\",MALE,48,Hubbard,Hubbard,\\"(empty)\\",Saturday,5,\\"robbie@hubbard-family.zzz\\",Dubai,Asia,AE,\\"{", - " \\"\\"coordinates\\"\\": [", - " 55.3,", - " 25.3", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Dubai,\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590970,\\"sold_product_590970_11228, sold_product_590970_12060\\",\\"sold_product_590970_11228, sold_product_590970_12060\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"12, 25.984\\",\\"24.984, 50\\",\\"11,228, 12,060\\",\\"Tracksuit top - offwhite multicolor, Lace-ups - black/red\\",\\"Tracksuit top - offwhite multicolor, Lace-ups - black/red\\",\\"1, 1\\",\\"ZO0455604556, ZO0680806808\\",\\"0, 0\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"0, 0\\",\\"ZO0455604556, ZO0680806808\\",75,75,2,2,order,robbie", - "6AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Willis\\",\\"Abigail Willis\\",FEMALE,46,Willis,Willis,\\"(empty)\\",Saturday,5,\\"abigail@willis-family.zzz\\",Birmingham,Europe,GB,\\"{", - " \\"\\"coordinates\\"\\": [", - " -1.9,", - " 52.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Birmingham,\\"Tigress Enterprises MAMA, Angeldale\\",\\"Tigress Enterprises MAMA, Angeldale\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591299,\\"sold_product_591299_19895, sold_product_591299_5787\\",\\"sold_product_591299_19895, sold_product_591299_5787\\",\\"33, 85\\",\\"33, 85\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Angeldale\\",\\"Tigress Enterprises MAMA, Angeldale\\",\\"17.156, 44.188\\",\\"33, 85\\",\\"19,895, 5,787\\",\\"Summer dress - black/offwhite, Ankle boots - black\\",\\"Summer dress - black/offwhite, Ankle boots - black\\",\\"1, 1\\",\\"ZO0229002290, ZO0674406744\\",\\"0, 0\\",\\"33, 85\\",\\"33, 85\\",\\"0, 0\\",\\"ZO0229002290, ZO0674406744\\",118,118,2,2,order,abigail", - "6QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Greene\\",\\"Boris Greene\\",MALE,36,Greene,Greene,\\"(empty)\\",Saturday,5,\\"boris@greene-family.zzz\\",\\"-\\",Europe,GB,\\"{", - " \\"\\"coordinates\\"\\": [", - " -0.1,", - " 51.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"-\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591133,\\"sold_product_591133_19496, sold_product_591133_20143\\",\\"sold_product_591133_19496, sold_product_591133_20143\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"12.742, 5.711\\",\\"24.984, 10.992\\",\\"19,496, 20,143\\",\\"Tracksuit bottoms - mottled grey, Sports shirt - black\\",\\"Tracksuit bottoms - mottled grey, Sports shirt - black\\",\\"1, 1\\",\\"ZO0529905299, ZO0617006170\\",\\"0, 0\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"0, 0\\",\\"ZO0529905299, ZO0617006170\\",\\"35.969\\",\\"35.969\\",2,2,order,boris", - "6gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Conner\\",\\"Jackson Conner\\",MALE,13,Conner,Conner,\\"(empty)\\",Saturday,5,\\"jackson@conner-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -118.2,", - " 34.1", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591175,\\"sold_product_591175_23703, sold_product_591175_11555\\",\\"sold_product_591175_23703, sold_product_591175_11555\\",\\"28.984, 65\\",\\"28.984, 65\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"13.922, 31.844\\",\\"28.984, 65\\",\\"23,703, 11,555\\",\\"Sweatshirt - grey multicolor, Short coat - dark blue\\",\\"Sweatshirt - grey multicolor, Short coat - dark blue\\",\\"1, 1\\",\\"ZO0299402994, ZO0433504335\\",\\"0, 0\\",\\"28.984, 65\\",\\"28.984, 65\\",\\"0, 0\\",\\"ZO0299402994, ZO0433504335\\",94,94,2,2,order,jackson", - "7QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Cross\\",\\"Yuri Cross\\",MALE,21,Cross,Cross,\\"(empty)\\",Saturday,5,\\"yuri@cross-family.zzz\\",Cannes,Europe,FR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 7,", - " 43.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591297,\\"sold_product_591297_21234, sold_product_591297_17466\\",\\"sold_product_591297_21234, sold_product_591297_17466\\",\\"75, 28.984\\",\\"75, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"36.75, 13.344\\",\\"75, 28.984\\",\\"21,234, 17,466\\",\\"Lace-up boots - brown, Jumper - multicoloured\\",\\"Lace-up boots - brown, Jumper - multicoloured\\",\\"1, 1\\",\\"ZO0257502575, ZO0451704517\\",\\"0, 0\\",\\"75, 28.984\\",\\"75, 28.984\\",\\"0, 0\\",\\"ZO0257502575, ZO0451704517\\",104,104,2,2,order,yuri", - "7gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Ramsey\\",\\"Irwin Ramsey\\",MALE,14,Ramsey,Ramsey,\\"(empty)\\",Saturday,5,\\"irwin@ramsey-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{", -] +exports[`discover Discover CSV Export Generate CSV: new search generates a large export 1`] = ` +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,\\"(empty)\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.375, 33, 10.344, 6.109\\",\\"80, 60, 21.984, 11.992\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",174,174,4,4,order,sultan +9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Richards\\",\\"Pia Richards\\",FEMALE,45,Richards,Richards,\\"(empty)\\",Saturday,5,\\"pia@richards-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.703, 9.867\\",\\"20.984, 20.984\\",\\"14,761, 11,632\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0006400064, ZO0150601506\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0006400064, ZO0150601506\\",\\"41.969\\",\\"41.969\\",2,2,order,pia +BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"3.6, 17.484\\",\\"7.988, 33\\",\\"20,734, 7,539\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"1, 1\\",\\"ZO0638206382, ZO0038800388\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0638206382, ZO0038800388\\",\\"40.969\\",\\"40.969\\",2,2,order,brigitte +KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing" `; -exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: discover:searchFieldsFromSource 2`] = ` -Array [ - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Dubai,\\"Tigress Enterprises MAMA, Pyramidustries, Angeldale\\",\\"Tigress Enterprises MAMA, Pyramidustries, Angeldale\\",\\"Jun 12, 2019 @ 00:00:00.000\\",731056,\\"sold_product_731056_22440, sold_product_731056_13969, sold_product_731056_20215, sold_product_731056_23401\\",\\"sold_product_731056_22440, sold_product_731056_13969, sold_product_731056_20215, sold_product_731056_23401\\",\\"33, 20.984, 75, 13.992\\",\\"33, 20.984, 75, 13.992\\",\\"Women's Clothing, Women's Accessories, Women's Shoes, Women's Accessories\\",\\"Women's Clothing, Women's Accessories, Women's Shoes, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises MAMA, Pyramidustries, Angeldale, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries, Angeldale, Pyramidustries\\",\\"15.18, 10.289, 39, 6.719\\",\\"33, 20.984, 75, 13.992\\",\\"22,440, 13,969, 20,215, 23,401\\",\\"Jersey dress - fan/black, Across body bag - Blue Violety, Boots - black, Hat - nude\\",\\"Jersey dress - fan/black, Across body bag - Blue Violety, Boots - black, Hat - nude\\",\\"1, 1, 1, 1\\",\\"ZO0230102301, ZO0210602106, ZO0679006790, ZO0187301873\\",\\"0, 0, 0, 0\\",\\"33, 20.984, 75, 13.992\\",\\"33, 20.984, 75, 13.992\\",\\"0, 0, 0, 0\\",\\"ZO0230102301, ZO0210602106, ZO0679006790, ZO0187301873\\",143,143,4,4,order,rabbia", - "4AMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Pope\\",\\"Yahya Pope\\",MALE,23,Pope,Pope,\\"(empty)\\",Thursday,3,\\"yahya@pope-family.zzz\\",Marrakesh,Africa,MA,\\"{", - " \\"\\"coordinates\\"\\": [", - " -8,", - " 31.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 12, 2019 @ 00:00:00.000\\",551556,\\"sold_product_551556_1583, sold_product_551556_11991\\",\\"sold_product_551556_1583, sold_product_551556_11991\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"17.813, 3.76\\",\\"33, 7.988\\",\\"1,583, 11,991\\",\\"High-top trainers - black, Basic T-shirt - black\\",\\"High-top trainers - black, Basic T-shirt - black\\",\\"1, 1\\",\\"ZO0512405124, ZO0551405514\\",\\"0, 0\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"0, 0\\",\\"ZO0512405124, ZO0551405514\\",\\"40.969\\",\\"40.969\\",2,2,order,yahya", - "4QMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Morrison\\",\\"George Morrison\\",MALE,32,Morrison,Morrison,\\"(empty)\\",Thursday,3,\\"george@morrison-family.zzz\\",Birmingham,Europe,GB,\\"{", - " \\"\\"coordinates\\"\\": [", - " -1.9,", - " 52.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Birmingham,\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 12, 2019 @ 00:00:00.000\\",551609,\\"sold_product_551609_3728, sold_product_551609_23435\\",\\"sold_product_551609_3728, sold_product_551609_23435\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"10.703, 10.289\\",\\"20.984, 20.984\\",\\"3,728, 23,435\\",\\"Base layer - khaki, Shirt - red\\",\\"Base layer - khaki, Shirt - red\\",\\"1, 1\\",\\"ZO0630606306, ZO0524705247\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0630606306, ZO0524705247\\",\\"41.969\\",\\"41.969\\",2,2,order,george", - "\\"_wMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Morris\\",\\"Yuri Morris\\",MALE,21,Morris,Morris,\\"(empty)\\",Thursday,3,\\"yuri@morris-family.zzz\\",Cannes,Europe,FR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 7,", - " 43.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Alpes-Maritimes\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550473,\\"sold_product_550473_20161, sold_product_550473_6991\\",\\"sold_product_550473_20161, sold_product_550473_6991\\",\\"65, 38\\",\\"65, 38\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"30.547, 20.125\\",\\"65, 38\\",\\"20,161, 6,991\\",\\"Lace-up boots - dark tan, Jumper - dark blue\\",\\"Lace-up boots - dark tan, Jumper - dark blue\\",\\"1, 1\\",\\"ZO0688006880, ZO0450504505\\",\\"0, 0\\",\\"65, 38\\",\\"65, 38\\",\\"0, 0\\",\\"ZO0688006880, ZO0450504505\\",103,103,2,2,order,yuri", - "AAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Brigitte,Brigitte,\\"Brigitte Long\\",\\"Brigitte Long\\",FEMALE,12,Long,Long,\\"(empty)\\",Thursday,3,\\"brigitte@long-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 12, 2019 @ 00:00:00.000\\",550542,\\"sold_product_550542_11839, sold_product_550542_21052\\",\\"sold_product_550542_11839, sold_product_550542_21052\\",\\"24.984, 9.992\\",\\"24.984, 9.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"12.992, 4.898\\",\\"24.984, 9.992\\",\\"11,839, 21,052\\",\\"High heeled sandals - cognac, Snood - black/red/green/yellow\\",\\"High heeled sandals - cognac, Snood - black/red/green/yellow\\",\\"1, 1\\",\\"ZO0137301373, ZO0192601926\\",\\"0, 0\\",\\"24.984, 9.992\\",\\"24.984, 9.992\\",\\"0, 0\\",\\"ZO0137301373, ZO0192601926\\",\\"34.969\\",\\"34.969\\",2,2,order,brigitte", - "AQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,rania,rania,\\"rania Barnes\\",\\"rania Barnes\\",FEMALE,24,Barnes,Barnes,\\"(empty)\\",Thursday,3,\\"rania@barnes-family.zzz\\",Cairo,Africa,EG,\\"{", - " \\"\\"coordinates\\"\\": [", - " 31.3,", - " 30.1", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Cairo Governorate\\",\\"Pyramidustries, Pyramidustries active\\",\\"Pyramidustries, Pyramidustries active\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550580,\\"sold_product_550580_20312, sold_product_550580_10155\\",\\"sold_product_550580_20312, sold_product_550580_10155\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries active\\",\\"Pyramidustries, Pyramidustries active\\",\\"24, 8.656\\",\\"50, 16.984\\",\\"20,312, 10,155\\",\\"Lace-up boots - cognac, Sports shirt - black\\",\\"Lace-up boots - cognac, Sports shirt - black\\",\\"1, 1\\",\\"ZO0144801448, ZO0219602196\\",\\"0, 0\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"0, 0\\",\\"ZO0144801448, ZO0219602196\\",67,67,2,2,order,rani", - "BwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Tyler\\",\\"Abdulraheem Al Tyler\\",MALE,33,Tyler,Tyler,\\"(empty)\\",Thursday,3,\\"abdulraheem al@tyler-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{", - " \\"\\"coordinates\\"\\": [", - " 54.4,", - " 24.5", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Abu Dhabi\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 12, 2019 @ 00:00:00.000\\",551324,\\"sold_product_551324_14742, sold_product_551324_19089\\",\\"sold_product_551324_14742, sold_product_551324_19089\\",\\"33, 12.992\\",\\"33, 12.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"15.18, 7.012\\",\\"33, 12.992\\",\\"14,742, 19,089\\",\\"Laptop bag - brown, Vest - white/dark blue\\",\\"Laptop bag - brown, Vest - white/dark blue\\",\\"1, 1\\",\\"ZO0316803168, ZO0566905669\\",\\"0, 0\\",\\"33, 12.992\\",\\"33, 12.992\\",\\"0, 0\\",\\"ZO0316803168, ZO0566905669\\",\\"45.969\\",\\"45.969\\",2,2,order,abdulraheem", - "mwMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan James\\",\\"Marwan James\\",MALE,51,James,James,\\"(empty)\\",Thursday,3,\\"marwan@james-family.zzz\\",Marrakesh,Africa,MA,\\"{", - " \\"\\"coordinates\\"\\": [", - " -8,", - " 31.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 12, 2019 @ 00:00:00.000\\",551355,\\"sold_product_551355_21057, sold_product_551355_23405\\",\\"sold_product_551355_21057, sold_product_551355_23405\\",\\"13.992, 11.992\\",\\"13.992, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"6.859, 5.762\\",\\"13.992, 11.992\\",\\"21,057, 23,405\\",\\"Scarf - navy/grey, Basic T-shirt - blue\\",\\"Scarf - navy/grey, Basic T-shirt - blue\\",\\"1, 1\\",\\"ZO0313403134, ZO0561205612\\",\\"0, 0\\",\\"13.992, 11.992\\",\\"13.992, 11.992\\",\\"0, 0\\",\\"ZO0313403134, ZO0561205612\\",\\"25.984\\",\\"25.984\\",2,2,order,marwan", - "twMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Mccormick\\",\\"Sonya Mccormick\\",FEMALE,28,Mccormick,Mccormick,\\"(empty)\\",Thursday,3,\\"sonya@mccormick-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74.1,", - " 4.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Bogota D.C.\\",Pyramidustries,Pyramidustries,\\"Jun 12, 2019 @ 00:00:00.000\\",550957,\\"sold_product_550957_22980, sold_product_550957_19828\\",\\"sold_product_550957_22980, sold_product_550957_19828\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"11.5, 9.172\\",\\"24.984, 16.984\\",\\"22,980, 19,828\\",\\"Classic heels - petrol, Watch - nude\\",\\"Classic heels - petrol, Watch - nude\\",\\"1, 1\\",\\"ZO0133101331, ZO0189401894\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0133101331, ZO0189401894\\",\\"41.969\\",\\"41.969\\",2,2,order,sonya", - "7AMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Hansen\\",\\"Kamal Hansen\\",MALE,39,Hansen,Hansen,\\"(empty)\\",Thursday,3,\\"kamal@hansen-family.zzz\\",Istanbul,Asia,TR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 29,", - " 41", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",Istanbul,\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 12, 2019 @ 00:00:00.000\\",551154,\\"sold_product_551154_13181, sold_product_551154_23660\\",\\"sold_product_551154_13181, sold_product_551154_23660\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"21, 6.109\\",\\"42, 11.992\\",\\"13,181, 23,660\\",\\"Briefcase - navy, Sports shirt - Seashell\\",\\"Briefcase - navy, Sports shirt - Seashell\\",\\"1, 1\\",\\"ZO0466704667, ZO0617306173\\",\\"0, 0\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"0, 0\\",\\"ZO0466704667, ZO0617306173\\",\\"53.969\\",\\"53.969\\",2,2,order,kamal", - "7QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Graves\\",\\"Elyssa Graves\\",FEMALE,27,Graves,Graves,\\"(empty)\\",Thursday,3,\\"elyssa@graves-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 12, 2019 @ 00:00:00.000\\",551204,\\"sold_product_551204_16805, sold_product_551204_12896\\",\\"sold_product_551204_16805, sold_product_551204_12896\\",\\"13.992, 20.984\\",\\"13.992, 20.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"7.129, 9.656\\",\\"13.992, 20.984\\",\\"16,805, 12,896\\",\\"Bustier - white, Across body bag - cognac\\",\\"Bustier - white, Across body bag - cognac\\",\\"1, 1\\",\\"ZO0212602126, ZO0200702007\\",\\"0, 0\\",\\"13.992, 20.984\\",\\"13.992, 20.984\\",\\"0, 0\\",\\"ZO0212602126, ZO0200702007\\",\\"34.969\\",\\"34.969\\",2,2,order,elyssa", - "7gMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Rose\\",\\"Pia Rose\\",FEMALE,45,Rose,Rose,\\"(empty)\\",Thursday,3,\\"pia@rose-family.zzz\\",Cannes,Europe,FR,\\"{", - " \\"\\"coordinates\\"\\": [", - " 7,", - " 43.6", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Primemaster\\",\\"Oceanavigations, Primemaster\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550466,\\"sold_product_550466_19198, sold_product_550466_16409\\",\\"sold_product_550466_19198, sold_product_550466_16409\\",\\"50, 100\\",\\"50, 100\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Primemaster\\",\\"Oceanavigations, Primemaster\\",\\"24, 52\\",\\"50, 100\\",\\"19,198, 16,409\\",\\"Summer dress - grey, Boots - passion\\",\\"Summer dress - grey, Boots - passion\\",\\"1, 1\\",\\"ZO0260702607, ZO0363203632\\",\\"0, 0\\",\\"50, 100\\",\\"50, 100\\",\\"0, 0\\",\\"ZO0260702607, ZO0363203632\\",150,150,2,2,order,pia", - "7wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Boone\\",\\"Wagdi Boone\\",MALE,15,Boone,Boone,\\"(empty)\\",Thursday,3,\\"wagdi@boone-family.zzz\\",\\"-\\",Asia,SA,\\"{", - " \\"\\"coordinates\\"\\": [", - " 45,", - " 25", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 12, 2019 @ 00:00:00.000\\",550503,\\"sold_product_550503_13211, sold_product_550503_24369\\",\\"sold_product_550503_13211, sold_product_550503_24369\\",\\"34, 11.992\\",\\"34, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"15.641, 6.109\\",\\"34, 11.992\\",\\"13,211, 24,369\\",\\"Tracksuit top - black, Print T-shirt - khaki\\",\\"Tracksuit top - black, Print T-shirt - khaki\\",\\"1, 1\\",\\"ZO0587505875, ZO0566405664\\",\\"0, 0\\",\\"34, 11.992\\",\\"34, 11.992\\",\\"0, 0\\",\\"ZO0587505875, ZO0566405664\\",\\"45.969\\",\\"45.969\\",2,2,order,wagdi", - "8AMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Hale\\",\\"Elyssa Hale\\",FEMALE,27,Hale,Hale,\\"(empty)\\",Thursday,3,\\"elyssa@hale-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -74,", - " 40.8", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",\\"New York\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550538,\\"sold_product_550538_15047, sold_product_550538_18189\\",\\"sold_product_550538_15047, sold_product_550538_18189\\",\\"75, 60\\",\\"75, 60\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"34.5, 28.797\\",\\"75, 60\\",\\"15,047, 18,189\\",\\"Handbag - black, Ankle boots - grey\\",\\"Handbag - black, Ankle boots - grey\\",\\"1, 1\\",\\"ZO0699406994, ZO0246202462\\",\\"0, 0\\",\\"75, 60\\",\\"75, 60\\",\\"0, 0\\",\\"ZO0699406994, ZO0246202462\\",135,135,2,2,order,elyssa", - "8QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Love\\",\\"Jackson Love\\",MALE,13,Love,Love,\\"(empty)\\",Thursday,3,\\"jackson@love-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{", - " \\"\\"coordinates\\"\\": [", - " -118.2,", - " 34.1", - " ],", - " \\"\\"type\\"\\": \\"\\"Point\\"\\"", - "}\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550568,\\"sold_product_550568_17210, sold_product_550568_12524\\",\\"sold_product_550568_17210, sold_product_550568_12524\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"25, 12.492\\",\\"50, 24.984\\",\\"17,210, 12,524\\",\\"Casual lace-ups - navy, Jumper - dark grey multicolor\\",\\"Casual lace-ups - navy, Jumper - dark grey multicolor\\",\\"1, 1\\",\\"ZO0388403884, ZO0447604476\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0388403884, ZO0447604476\\",75,75,2,2,order,jackson", -] +exports[`discover Discover CSV Export Generate CSV: new search generates a large export 2`] = ` +"cmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Graves\\",\\"Elyssa Graves\\",FEMALE,27,Graves,Graves,\\"(empty)\\",Thursday,3,\\"elyssa@graves-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 12, 2019 @ 00:00:00.000\\",551204,\\"sold_product_551204_16805, sold_product_551204_12896\\",\\"sold_product_551204_16805, sold_product_551204_12896\\",\\"13.992, 20.984\\",\\"13.992, 20.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"7.129, 9.656\\",\\"13.992, 20.984\\",\\"16,805, 12,896\\",\\"Bustier - white, Across body bag - cognac\\",\\"Bustier - white, Across body bag - cognac\\",\\"1, 1\\",\\"ZO0212602126, ZO0200702007\\",\\"0, 0\\",\\"13.992, 20.984\\",\\"13.992, 20.984\\",\\"0, 0\\",\\"ZO0212602126, ZO0200702007\\",\\"34.969\\",\\"34.969\\",2,2,order,elyssa +7gMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Rose\\",\\"Pia Rose\\",FEMALE,45,Rose,Rose,\\"(empty)\\",Thursday,3,\\"pia@rose-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Primemaster\\",\\"Oceanavigations, Primemaster\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550466,\\"sold_product_550466_19198, sold_product_550466_16409\\",\\"sold_product_550466_19198, sold_product_550466_16409\\",\\"50, 100\\",\\"50, 100\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Primemaster\\",\\"Oceanavigations, Primemaster\\",\\"24, 52\\",\\"50, 100\\",\\"19,198, 16,409\\",\\"Summer dress - grey, Boots - passion\\",\\"Summer dress - grey, Boots - passion\\",\\"1, 1\\",\\"ZO0260702607, ZO0363203632\\",\\"0, 0\\",\\"50, 100\\",\\"50, 100\\",\\"0, 0\\",\\"ZO0260702607, ZO0363203632\\",150,150,2,2,order,pia +7wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Boone\\",\\"Wagdi Boone\\",MALE,15,Boone,Boone,\\"(empty)\\",Thursday,3,\\"wagdi@boone-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 12, 2019 @ 00:00:00.000\\",550503,\\"sold_product_550503_13211, sold_product_550503_24369\\",\\"sold_product_550503_13211, sold_product_550503_24369\\",\\"34, 11.992\\",\\"34, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"15.641, 6.109\\",\\"34, 11.992\\",\\"13,211, 24,369\\",\\"Tracksuit top - black, Print T-shirt - khaki\\",\\"Tracksuit top - black, Print T-shirt - khaki\\",\\"1, 1\\",\\"ZO0587505875, ZO0566405664\\",\\"0, 0\\",\\"34, 11.992\\",\\"34, 11.992\\",\\"0, 0\\",\\"ZO0587505875, ZO0566405664\\",\\"45.969\\",\\"45.969\\",2,2,order,wagdi +8AMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Hale\\",\\"Elyssa Hale\\",FEMALE,27,Hale,Hale,\\"(empty)\\",Thursday,3,\\"elyssa@hale-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550538,\\"sold_product_550538_15047, sold_product_550538_18189\\",\\"sold_product_550538_15047, sold_product_550538_18189\\",\\"75, 60\\",\\"75, 60\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"34.5, 28.797\\",\\"75, 60\\",\\"15,047, 18,189\\",\\"Handbag - black, Ankle boots - grey\\",\\"Handbag - black, Ankle boots - grey\\",\\"1, 1\\",\\"ZO0699406994, ZO0246202462\\",\\"0, 0\\",\\"75, 60\\",\\"75, 60\\",\\"0, 0\\",\\"ZO0699406994, ZO0246202462\\",135,135,2,2,order,elyssa +8QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Love\\",\\"Jackson Love\\",MALE,13,Love,Love,\\"(empty)\\",Thursday,3,\\"jackson@love-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550568,\\"sold_product_550568_17210, sold_product_550568_12524\\",\\"sold_product_550568_17210, sold_product_550568_12524\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"25, 12.492\\",\\"50, 24.984\\",\\"17,210, 12,524\\",\\"Casual lace-ups - navy, Jumper - dark grey multicolor\\",\\"Casual lace-ups - navy, Jumper - dark grey multicolor\\",\\"1, 1\\",\\"ZO0388403884, ZO0447604476\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0388403884, ZO0447604476\\",75,75,2,2,order,jackson +" +`; + +exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: default 1`] = ` +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +9AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Bradley\\",\\"Boris Bradley\\",MALE,36,Bradley,Bradley,\\"(empty)\\",Wednesday,2,\\"boris@bradley-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568397,\\"sold_product_568397_24419, sold_product_568397_20207\\",\\"sold_product_568397_24419, sold_product_568397_20207\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"17.484, 13.922\\",\\"33, 28.984\\",\\"24,419, 20,207\\",\\"Cargo trousers - oliv, Trousers - black\\",\\"Cargo trousers - oliv, Trousers - black\\",\\"1, 1\\",\\"ZO0112101121, ZO0530405304\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0112101121, ZO0530405304\\",\\"61.969\\",\\"61.969\\",2,2,order,boris +9QMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Hubbard\\",\\"Oliver Hubbard\\",MALE,7,Hubbard,Hubbard,\\"(empty)\\",Wednesday,2,\\"oliver@hubbard-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spritechnologies, Microlutions\\",\\"Spritechnologies, Microlutions\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568044,\\"sold_product_568044_12799, sold_product_568044_18008\\",\\"sold_product_568044_12799, sold_product_568044_18008\\",\\"14.992, 16.984\\",\\"14.992, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Microlutions\\",\\"Spritechnologies, Microlutions\\",\\"6.898, 8.828\\",\\"14.992, 16.984\\",\\"12,799, 18,008\\",\\"Undershirt - dark grey multicolor, Long sleeved top - purple\\",\\"Undershirt - dark grey multicolor, Long sleeved top - purple\\",\\"1, 1\\",\\"ZO0630406304, ZO0120201202\\",\\"0, 0\\",\\"14.992, 16.984\\",\\"14.992, 16.984\\",\\"0, 0\\",\\"ZO0630406304, ZO0120201202\\",\\"31.984\\",\\"31.984\\",2,2,order,oliver +OAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Betty,Betty,\\"Betty Reese\\",\\"Betty Reese\\",FEMALE,44,Reese,Reese,\\"(empty)\\",Wednesday,2,\\"betty@reese-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 25, 2019 @ 00:00:00.000\\",568229,\\"sold_product_568229_24991, sold_product_568229_12039\\",\\"sold_product_568229_24991, sold_product_568229_12039\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"6.352, 5.82\\",\\"11.992, 10.992\\",\\"24,991, 12,039\\",\\"Scarf - rose/white, Scarf - nude/black/turquoise\\",\\"Scarf - rose/white, Scarf - nude/black/turquoise\\",\\"1, 1\\",\\"ZO0192201922, ZO0192801928\\",\\"0, 0\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"0, 0\\",\\"ZO0192201922, ZO0192801928\\",\\"22.984\\",\\"22.984\\",2,2,order,betty +OQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Recip,Recip,\\"Recip Salazar\\",\\"Recip Salazar\\",MALE,10,Salazar,Salazar,\\"(empty)\\",Wednesday,2,\\"recip@salazar-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568292,\\"sold_product_568292_23627, sold_product_568292_11149\\",\\"sold_product_568292_23627, sold_product_568292_11149\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"12.492, 5.059\\",\\"24.984, 10.992\\",\\"23,627, 11,149\\",\\"Slim fit jeans - grey, Sunglasses - black\\",\\"Slim fit jeans - grey, Sunglasses - black\\",\\"1, 1\\",\\"ZO0534205342, ZO0599605996\\",\\"0, 0\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"0, 0\\",\\"ZO0534205342, ZO0599605996\\",\\"35.969\\",\\"35.969\\",2,2,order,recip +jwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Harper\\",\\"Jackson Harper\\",MALE,13,Harper,Harper,\\"(empty)\\",Wednesday,2,\\"jackson@harper-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568386,\\"sold_product_568386_11959, sold_product_568386_2774\\",\\"sold_product_568386_11959, sold_product_568386_2774\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"12.742, 45.875\\",\\"24.984, 85\\",\\"11,959, 2,774\\",\\"SLIM FIT - Formal shirt - lila, Classic coat - black\\",\\"SLIM FIT - Formal shirt - lila, Classic coat - black\\",\\"1, 1\\",\\"ZO0422404224, ZO0291702917\\",\\"0, 0\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"0, 0\\",\\"ZO0422404224, ZO0291702917\\",110,110,2,2,order,jackson +kAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Brewer\\",\\"Betty Brewer\\",FEMALE,44,Brewer,Brewer,\\"(empty)\\",Wednesday,2,\\"betty@brewer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568023,\\"sold_product_568023_22309, sold_product_568023_22315\\",\\"sold_product_568023_22309, sold_product_568023_22315\\",\\"11.992, 16.984\\",\\"11.992, 16.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"5.879, 8.656\\",\\"11.992, 16.984\\",\\"22,309, 22,315\\",\\"Wallet - brown, Summer dress - black\\",\\"Wallet - brown, Summer dress - black\\",\\"1, 1\\",\\"ZO0075900759, ZO0489304893\\",\\"0, 0\\",\\"11.992, 16.984\\",\\"11.992, 16.984\\",\\"0, 0\\",\\"ZO0075900759, ZO0489304893\\",\\"28.984\\",\\"28.984\\",2,2,order,betty +9wMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Selena,Selena,\\"Selena Hernandez\\",\\"Selena Hernandez\\",FEMALE,42,Hernandez,Hernandez,\\"(empty)\\",Wednesday,2,\\"selena@hernandez-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568789,\\"sold_product_568789_11481, sold_product_568789_17046\\",\\"sold_product_568789_11481, sold_product_568789_17046\\",\\"24.984, 30.984\\",\\"24.984, 30.984\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"12.492, 15.797\\",\\"24.984, 30.984\\",\\"11,481, 17,046\\",\\"Tote bag - black, SET - Watch - rose gold-coloured\\",\\"Tote bag - black, SET - Watch - rose gold-coloured\\",\\"1, 1\\",\\"ZO0197501975, ZO0079300793\\",\\"0, 0\\",\\"24.984, 30.984\\",\\"24.984, 30.984\\",\\"0, 0\\",\\"ZO0197501975, ZO0079300793\\",\\"55.969\\",\\"55.969\\",2,2,order,selena +\\"-AMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Greene\\",\\"Kamal Greene\\",MALE,39,Greene,Greene,\\"(empty)\\",Wednesday,2,\\"kamal@greene-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568331,\\"sold_product_568331_11375, sold_product_568331_14190\\",\\"sold_product_568331_11375, sold_product_568331_14190\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"19.734, 13.344\\",\\"42, 28.984\\",\\"11,375, 14,190\\",\\"Lace-ups - Midnight Blue, Trainers - grey\\",\\"Lace-ups - Midnight Blue, Trainers - grey\\",\\"1, 1\\",\\"ZO0385903859, ZO0516605166\\",\\"0, 0\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"0, 0\\",\\"ZO0385903859, ZO0516605166\\",71,71,2,2,order,kamal +\\"-QMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Ryan\\",\\"Kamal Ryan\\",MALE,39,Ryan,Ryan,\\"(empty)\\",Wednesday,2,\\"kamal@ryan-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568524,\\"sold_product_568524_17644, sold_product_568524_12625\\",\\"sold_product_568524_17644, sold_product_568524_12625\\",\\"60, 60\\",\\"60, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"29.406, 31.188\\",\\"60, 60\\",\\"17,644, 12,625\\",\\"Suit jacket - dark blue, T-bar sandals - cognac\\",\\"Suit jacket - dark blue, T-bar sandals - cognac\\",\\"1, 1\\",\\"ZO0424104241, ZO0694706947\\",\\"0, 0\\",\\"60, 60\\",\\"60, 60\\",\\"0, 0\\",\\"ZO0424104241, ZO0694706947\\",120,120,2,2,order,kamal +\\"-gMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Recip,Recip,\\"Recip Reese\\",\\"Recip Reese\\",MALE,10,Reese,Reese,\\"(empty)\\",Wednesday,2,\\"recip@reese-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568589,\\"sold_product_568589_19575, sold_product_568589_21053\\",\\"sold_product_568589_19575, sold_product_568589_21053\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"35.094, 5.391\\",\\"65, 10.992\\",\\"19,575, 21,053\\",\\"Short coat - oliv, Print T-shirt - white/blue\\",\\"Short coat - oliv, Print T-shirt - white/blue\\",\\"1, 1\\",\\"ZO0114401144, ZO0564705647\\",\\"0, 0\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"0, 0\\",\\"ZO0114401144, ZO0564705647\\",76,76,2,2,order,recip +\\"-wMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Pope\\",\\"Oliver Pope\\",MALE,7,Pope,Pope,\\"(empty)\\",Wednesday,2,\\"oliver@pope-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568640,\\"sold_product_568640_20196, sold_product_568640_12339\\",\\"sold_product_568640_20196, sold_product_568640_12339\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"13.344, 10.906\\",\\"28.984, 20.984\\",\\"20,196, 12,339\\",\\"Sweatshirt - bright white, Polo shirt - grey multicolor\\",\\"Sweatshirt - bright white, Polo shirt - grey multicolor\\",\\"1, 1\\",\\"ZO0125901259, ZO0443204432\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0125901259, ZO0443204432\\",\\"49.969\\",\\"49.969\\",2,2,order,oliver +\\"_AMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Henderson\\",\\"Irwin Henderson\\",MALE,14,Henderson,Henderson,\\"(empty)\\",Wednesday,2,\\"irwin@henderson-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568682,\\"sold_product_568682_21985, sold_product_568682_15522\\",\\"sold_product_568682_21985, sold_product_568682_15522\\",\\"60, 42\\",\\"60, 42\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"28.797, 19.734\\",\\"60, 42\\",\\"21,985, 15,522\\",\\"Smart lace-ups - black, Smart lace-ups - cognac\\",\\"Smart lace-ups - black, Smart lace-ups - cognac\\",\\"1, 1\\",\\"ZO0680706807, ZO0392603926\\",\\"0, 0\\",\\"60, 42\\",\\"60, 42\\",\\"0, 0\\",\\"ZO0680706807, ZO0392603926\\",102,102,2,2,order,irwin +XQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Miller\\",\\"Rabbia Al Miller\\",FEMALE,5,Miller,Miller,\\"(empty)\\",Wednesday,2,\\"rabbia al@miller-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Gnomehouse, Low Tide Media\\",\\"Gnomehouse, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569259,\\"sold_product_569259_18845, sold_product_569259_21703\\",\\"sold_product_569259_18845, sold_product_569259_21703\\",\\"55, 60\\",\\"55, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Low Tide Media\\",\\"Gnomehouse, Low Tide Media\\",\\"25.844, 28.203\\",\\"55, 60\\",\\"18,845, 21,703\\",\\"Summer dress - navy blazer, Ankle boots - tan \\",\\"Summer dress - navy blazer, Ankle boots - tan \\",\\"1, 1\\",\\"ZO0335503355, ZO0381003810\\",\\"0, 0\\",\\"55, 60\\",\\"55, 60\\",\\"0, 0\\",\\"ZO0335503355, ZO0381003810\\",115,115,2,2,order,rabbia +HAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Washington\\",\\"Hicham Washington\\",MALE,8,Washington,Washington,\\"(empty)\\",Wednesday,2,\\"hicham@washington-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568793,\\"sold_product_568793_17004, sold_product_568793_20936\\",\\"sold_product_568793_17004, sold_product_568793_20936\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"18.141, 4.23\\",\\"33, 7.988\\",\\"17,004, 20,936\\",\\"Watch - dark brown, Basic T-shirt - dark blue\\",\\"Watch - dark brown, Basic T-shirt - dark blue\\",\\"1, 1\\",\\"ZO0312503125, ZO0545505455\\",\\"0, 0\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"0, 0\\",\\"ZO0312503125, ZO0545505455\\",\\"40.969\\",\\"40.969\\",2,2,order,hicham +HQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Youssef,Youssef,\\"Youssef Porter\\",\\"Youssef Porter\\",MALE,31,Porter,Porter,\\"(empty)\\",Wednesday,2,\\"youssef@porter-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568350,\\"sold_product_568350_14392, sold_product_568350_24934\\",\\"sold_product_568350_14392, sold_product_568350_24934\\",\\"42, 50\\",\\"42, 50\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"21.406, 22.5\\",\\"42, 50\\",\\"14,392, 24,934\\",\\"Zantos - Wash bag - black, Lace-up boots - resin coffee\\",\\"Zantos - Wash bag - black, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0317303173, ZO0403504035\\",\\"0, 0\\",\\"42, 50\\",\\"42, 50\\",\\"0, 0\\",\\"ZO0317303173, ZO0403504035\\",92,92,2,2,order,youssef +HgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Moss\\",\\"Youssef Moss\\",MALE,31,Moss,Moss,\\"(empty)\\",Wednesday,2,\\"youssef@moss-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"(empty), Low Tide Media\\",\\"(empty), Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568531,\\"sold_product_568531_12837, sold_product_568531_13153\\",\\"sold_product_568531_12837, sold_product_568531_13153\\",\\"165, 24.984\\",\\"165, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"(empty), Low Tide Media\\",\\"(empty), Low Tide Media\\",\\"77.563, 12\\",\\"165, 24.984\\",\\"12,837, 13,153\\",\\"Smart lace-ups - cognac, Cardigan - grey\\",\\"Smart lace-ups - cognac, Cardigan - grey\\",\\"1, 1\\",\\"ZO0482104821, ZO0447104471\\",\\"0, 0\\",\\"165, 24.984\\",\\"165, 24.984\\",\\"0, 0\\",\\"ZO0482104821, ZO0447104471\\",190,190,2,2,order,youssef +HwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Robert,Robert,\\"Robert Cross\\",\\"Robert Cross\\",MALE,29,Cross,Cross,\\"(empty)\\",Wednesday,2,\\"robert@cross-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568578,\\"sold_product_568578_17925, sold_product_568578_16500\\",\\"sold_product_568578_17925, sold_product_568578_16500\\",\\"47, 33\\",\\"47, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"24.438, 16.813\\",\\"47, 33\\",\\"17,925, 16,500\\",\\"Boots - tan, Casual Cuffed Pants\\",\\"Boots - tan, Casual Cuffed Pants\\",\\"1, 1\\",\\"ZO0520005200, ZO0421104211\\",\\"0, 0\\",\\"47, 33\\",\\"47, 33\\",\\"0, 0\\",\\"ZO0520005200, ZO0421104211\\",80,80,2,2,order,robert +IAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Phil,Phil,\\"Phil Cunningham\\",\\"Phil Cunningham\\",MALE,50,Cunningham,Cunningham,\\"(empty)\\",Wednesday,2,\\"phil@cunningham-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568609,\\"sold_product_568609_11893, sold_product_568609_2361\\",\\"sold_product_568609_11893, sold_product_568609_2361\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"5.172, 30\\",\\"10.992, 60\\",\\"11,893, 2,361\\",\\"Polo shirt - dark blue, Lace-up boots - dark brown\\",\\"Polo shirt - dark blue, Lace-up boots - dark brown\\",\\"1, 1\\",\\"ZO0570405704, ZO0256102561\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0570405704, ZO0256102561\\",71,71,2,2,order,phil +IQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Thad,Thad,\\"Thad Carr\\",\\"Thad Carr\\",MALE,30,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"thad@carr-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568652,\\"sold_product_568652_23582, sold_product_568652_20196\\",\\"sold_product_568652_23582, sold_product_568652_20196\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"24, 13.344\\",\\"50, 28.984\\",\\"23,582, 20,196\\",\\"Boots - black, Sweatshirt - bright white\\",\\"Boots - black, Sweatshirt - bright white\\",\\"1, 1\\",\\"ZO0403304033, ZO0125901259\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0403304033, ZO0125901259\\",79,79,2,2,order,thad +TAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Muniz,Muniz,\\"Muniz Jackson\\",\\"Muniz Jackson\\",MALE,37,Jackson,Jackson,\\"(empty)\\",Wednesday,2,\\"muniz@jackson-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568068,\\"sold_product_568068_12333, sold_product_568068_15128\\",\\"sold_product_568068_12333, sold_product_568068_15128\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"7.648, 5.059\\",\\"16.984, 10.992\\",\\"12,333, 15,128\\",\\"Tracksuit top - black, Wallet - brown\\",\\"Tracksuit top - black, Wallet - brown\\",\\"1, 1\\",\\"ZO0583005830, ZO0602706027\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0583005830, ZO0602706027\\",\\"27.984\\",\\"27.984\\",2,2,order,muniz +jgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Pope\\",\\"George Pope\\",MALE,32,Pope,Pope,\\"(empty)\\",Wednesday,2,\\"george@pope-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568070,\\"sold_product_568070_14421, sold_product_568070_13685\\",\\"sold_product_568070_14421, sold_product_568070_13685\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.703, 8.328\\",\\"20.984, 16.984\\",\\"14,421, 13,685\\",\\"Jumper - mottled grey/camel/khaki, Print T-shirt - grey multicolor\\",\\"Jumper - mottled grey/camel/khaki, Print T-shirt - grey multicolor\\",\\"1, 1\\",\\"ZO0575605756, ZO0293302933\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0575605756, ZO0293302933\\",\\"37.969\\",\\"37.969\\",2,2,order,george +jwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Duncan\\",\\"Selena Duncan\\",FEMALE,42,Duncan,Duncan,\\"(empty)\\",Wednesday,2,\\"selena@duncan-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568106,\\"sold_product_568106_8745, sold_product_568106_15742\\",\\"sold_product_568106_8745, sold_product_568106_15742\\",\\"33, 8.992\\",\\"33, 8.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"17.156, 4.941\\",\\"33, 8.992\\",\\"8,745, 15,742\\",\\"Cardigan - mottled brown, Tights - dark navy\\",\\"Cardigan - mottled brown, Tights - dark navy\\",\\"1, 1\\",\\"ZO0068700687, ZO0101301013\\",\\"0, 0\\",\\"33, 8.992\\",\\"33, 8.992\\",\\"0, 0\\",\\"ZO0068700687, ZO0101301013\\",\\"41.969\\",\\"41.969\\",2,2,order,selena +swMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Jensen\\",\\"Wilhemina St. Jensen\\",FEMALE,17,Jensen,Jensen,\\"(empty)\\",Wednesday,2,\\"wilhemina st.@jensen-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568439,\\"sold_product_568439_16712, sold_product_568439_5602\\",\\"sold_product_568439_16712, sold_product_568439_5602\\",\\"20.984, 100\\",\\"20.984, 100\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"9.656, 46\\",\\"20.984, 100\\",\\"16,712, 5,602\\",\\"Blouse - black/pink/blue, Winter boots - black\\",\\"Blouse - black/pink/blue, Winter boots - black\\",\\"1, 1\\",\\"ZO0170601706, ZO0251502515\\",\\"0, 0\\",\\"20.984, 100\\",\\"20.984, 100\\",\\"0, 0\\",\\"ZO0170601706, ZO0251502515\\",121,121,2,2,order,wilhemina +tAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Lawrence\\",\\"Thad Lawrence\\",MALE,30,Lawrence,Lawrence,\\"(empty)\\",Wednesday,2,\\"thad@lawrence-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568507,\\"sold_product_568507_6098, sold_product_568507_24890\\",\\"sold_product_568507_6098, sold_product_568507_24890\\",\\"75, 18.984\\",\\"75, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"41.25, 10.438\\",\\"75, 18.984\\",\\"6,098, 24,890\\",\\"Parka - black, Shirt - mottled grey\\",\\"Parka - black, Shirt - mottled grey\\",\\"1, 1\\",\\"ZO0431304313, ZO0523605236\\",\\"0, 0\\",\\"75, 18.984\\",\\"75, 18.984\\",\\"0, 0\\",\\"ZO0431304313, ZO0523605236\\",94,94,2,2,order,thad +KgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Daniels\\",\\"Marwan Daniels\\",MALE,51,Daniels,Daniels,\\"(empty)\\",Wednesday,2,\\"marwan@daniels-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568236,\\"sold_product_568236_6221, sold_product_568236_11869\\",\\"sold_product_568236_6221, sold_product_568236_11869\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"15.07, 10.906\\",\\"28.984, 20.984\\",\\"6,221, 11,869\\",\\"Shirt - dark blue, Sweatshirt - grey multicolor\\",\\"Shirt - dark blue, Sweatshirt - grey multicolor\\",\\"1, 1\\",\\"ZO0416604166, ZO0581605816\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0416604166, ZO0581605816\\",\\"49.969\\",\\"49.969\\",2,2,order,marwan +KwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Wednesday,2,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568275,\\"sold_product_568275_17190, sold_product_568275_15978\\",\\"sold_product_568275_17190, sold_product_568275_15978\\",\\"60, 6.988\\",\\"60, 6.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"27, 3.43\\",\\"60, 6.988\\",\\"17,190, 15,978\\",\\"Pleated skirt - grey, 2 PACK - Socks - black \\",\\"Pleated skirt - grey, 2 PACK - Socks - black \\",\\"1, 1\\",\\"ZO0330903309, ZO0214802148\\",\\"0, 0\\",\\"60, 6.988\\",\\"60, 6.988\\",\\"0, 0\\",\\"ZO0330903309, ZO0214802148\\",67,67,2,2,order,brigitte +LAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Padilla\\",\\"Elyssa Padilla\\",FEMALE,27,Padilla,Padilla,\\"(empty)\\",Wednesday,2,\\"elyssa@padilla-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568434,\\"sold_product_568434_15265, sold_product_568434_22206\\",\\"sold_product_568434_15265, sold_product_568434_22206\\",\\"145, 14.992\\",\\"145, 14.992\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"78.313, 7.051\\",\\"145, 14.992\\",\\"15,265, 22,206\\",\\"High heeled boots - brown, Ballet pumps - navy\\",\\"High heeled boots - brown, Ballet pumps - navy\\",\\"1, 1\\",\\"ZO0362203622, ZO0000300003\\",\\"0, 0\\",\\"145, 14.992\\",\\"145, 14.992\\",\\"0, 0\\",\\"ZO0362203622, ZO0000300003\\",160,160,2,2,order,elyssa +LQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Dawson\\",\\"Elyssa Dawson\\",FEMALE,27,Dawson,Dawson,\\"(empty)\\",Wednesday,2,\\"elyssa@dawson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 25, 2019 @ 00:00:00.000\\",568458,\\"sold_product_568458_19261, sold_product_568458_24302\\",\\"sold_product_568458_19261, sold_product_568458_24302\\",\\"13.992, 10.992\\",\\"13.992, 10.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"7, 5.711\\",\\"13.992, 10.992\\",\\"19,261, 24,302\\",\\"Vest - black, Snood - dark grey/light grey\\",\\"Vest - black, Snood - dark grey/light grey\\",\\"1, 1\\",\\"ZO0164501645, ZO0195501955\\",\\"0, 0\\",\\"13.992, 10.992\\",\\"13.992, 10.992\\",\\"0, 0\\",\\"ZO0164501645, ZO0195501955\\",\\"24.984\\",\\"24.984\\",2,2,order,elyssa +LgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Bryant\\",\\"Betty Bryant\\",FEMALE,44,Bryant,Bryant,\\"(empty)\\",Wednesday,2,\\"betty@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568503,\\"sold_product_568503_12451, sold_product_568503_22678\\",\\"sold_product_568503_12451, sold_product_568503_22678\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"3.68, 31.188\\",\\"7.988, 60\\",\\"12,451, 22,678\\",\\"Vest - black, Ankle boots - Midnight Blue\\",\\"Vest - black, Ankle boots - Midnight Blue\\",\\"1, 1\\",\\"ZO0643306433, ZO0376203762\\",\\"0, 0\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"0, 0\\",\\"ZO0643306433, ZO0376203762\\",68,68,2,2,order,betty +fQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",EUR,Tariq,Tariq,\\"Tariq Salazar\\",\\"Tariq Salazar\\",MALE,25,Salazar,Salazar,\\"(empty)\\",Wednesday,2,\\"tariq@salazar-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Oceanavigations, Low Tide Media, Angeldale\\",\\"Oceanavigations, Low Tide Media, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",714149,\\"sold_product_714149_19588, sold_product_714149_6158, sold_product_714149_1422, sold_product_714149_18002\\",\\"sold_product_714149_19588, sold_product_714149_6158, sold_product_714149_1422, sold_product_714149_18002\\",\\"13.992, 22.984, 65, 42\\",\\"13.992, 22.984, 65, 42\\",\\"Men's Accessories, Men's Clothing, Men's Shoes, Men's Shoes\\",\\"Men's Accessories, Men's Clothing, Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Low Tide Media, Angeldale, Low Tide Media\\",\\"Oceanavigations, Low Tide Media, Angeldale, Low Tide Media\\",\\"7.41, 11.492, 33.781, 21.406\\",\\"13.992, 22.984, 65, 42\\",\\"19,588, 6,158, 1,422, 18,002\\",\\"Belt - black, Shirt - black, Lace-ups - cognac, Boots - brown\\",\\"Belt - black, Shirt - black, Lace-ups - cognac, Boots - brown\\",\\"1, 1, 1, 1\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\",\\"0, 0, 0, 0\\",\\"13.992, 22.984, 65, 42\\",\\"13.992, 22.984, 65, 42\\",\\"0, 0, 0, 0\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\",144,144,4,4,order,tariq +QAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Wise\\",\\"Wagdi Wise\\",MALE,15,Wise,Wise,\\"(empty)\\",Wednesday,2,\\"wagdi@wise-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568232,\\"sold_product_568232_18129, sold_product_568232_19774\\",\\"sold_product_568232_18129, sold_product_568232_19774\\",\\"37, 11.992\\",\\"37, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"18.859, 5.879\\",\\"37, 11.992\\",\\"18,129, 19,774\\",\\"Trousers - grey, Print T-shirt - black/orange\\",\\"Trousers - grey, Print T-shirt - black/orange\\",\\"1, 1\\",\\"ZO0282902829, ZO0566605666\\",\\"0, 0\\",\\"37, 11.992\\",\\"37, 11.992\\",\\"0, 0\\",\\"ZO0282902829, ZO0566605666\\",\\"48.969\\",\\"48.969\\",2,2,order,wagdi +QQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Reyes\\",\\"Robbie Reyes\\",MALE,48,Reyes,Reyes,\\"(empty)\\",Wednesday,2,\\"robbie@reyes-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568269,\\"sold_product_568269_19175, sold_product_568269_2764\\",\\"sold_product_568269_19175, sold_product_568269_2764\\",\\"33, 135\\",\\"33, 135\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"15.844, 67.5\\",\\"33, 135\\",\\"19,175, 2,764\\",\\"Watch - dark brown, Suit - dark blue\\",\\"Watch - dark brown, Suit - dark blue\\",\\"1, 1\\",\\"ZO0318603186, ZO0407904079\\",\\"0, 0\\",\\"33, 135\\",\\"33, 135\\",\\"0, 0\\",\\"ZO0318603186, ZO0407904079\\",168,168,2,2,order,robbie +QgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Stokes\\",\\"Yasmine Stokes\\",FEMALE,43,Stokes,Stokes,\\"(empty)\\",Wednesday,2,\\"yasmine@stokes-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568301,\\"sold_product_568301_20011, sold_product_568301_20152\\",\\"sold_product_568301_20011, sold_product_568301_20152\\",\\"33, 42\\",\\"33, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"15.844, 22.25\\",\\"33, 42\\",\\"20,011, 20,152\\",\\"Jumpsuit - black, Platform boots - dark blue\\",\\"Jumpsuit - black, Platform boots - dark blue\\",\\"1, 1\\",\\"ZO0146401464, ZO0014700147\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0146401464, ZO0014700147\\",75,75,2,2,order,yasmine +QwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Ryan\\",\\"Clarice Ryan\\",FEMALE,18,Ryan,Ryan,\\"(empty)\\",Wednesday,2,\\"clarice@ryan-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568469,\\"sold_product_568469_10902, sold_product_568469_8739\\",\\"sold_product_568469_10902, sold_product_568469_8739\\",\\"26.984, 28.984\\",\\"26.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"13.758, 15.938\\",\\"26.984, 28.984\\",\\"10,902, 8,739\\",\\"Pyjamas - black, Jumper - anthractie multicolor\\",\\"Pyjamas - black, Jumper - anthractie multicolor\\",\\"1, 1\\",\\"ZO0659806598, ZO0070100701\\",\\"0, 0\\",\\"26.984, 28.984\\",\\"26.984, 28.984\\",\\"0, 0\\",\\"ZO0659806598, ZO0070100701\\",\\"55.969\\",\\"55.969\\",2,2,order,clarice +RAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Shaw\\",\\"Sultan Al Shaw\\",MALE,19,Shaw,Shaw,\\"(empty)\\",Wednesday,2,\\"sultan al@shaw-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568499,\\"sold_product_568499_23865, sold_product_568499_17752\\",\\"sold_product_568499_23865, sold_product_568499_17752\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"5.879, 17.391\\",\\"11.992, 37\\",\\"23,865, 17,752\\",\\"2 PACK - Basic T-shirt - dark grey multicolor, Slim fit jeans - black denim\\",\\"2 PACK - Basic T-shirt - dark grey multicolor, Slim fit jeans - black denim\\",\\"1, 1\\",\\"ZO0474604746, ZO0113801138\\",\\"0, 0\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"0, 0\\",\\"ZO0474604746, ZO0113801138\\",\\"48.969\\",\\"48.969\\",2,2,order,sultan +UQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Austin\\",\\"Wilhemina St. Austin\\",FEMALE,17,Austin,Austin,\\"(empty)\\",Wednesday,2,\\"wilhemina st.@austin-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568083,\\"sold_product_568083_14459, sold_product_568083_18901\\",\\"sold_product_568083_14459, sold_product_568083_18901\\",\\"11.992, 16.984\\",\\"11.992, 16.984\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"5.762, 8.328\\",\\"11.992, 16.984\\",\\"14,459, 18,901\\",\\"Across body bag - cognac, Clutch - white/black\\",\\"Across body bag - cognac, Clutch - white/black\\",\\"1, 1\\",\\"ZO0200902009, ZO0092300923\\",\\"0, 0\\",\\"11.992, 16.984\\",\\"11.992, 16.984\\",\\"0, 0\\",\\"ZO0200902009, ZO0092300923\\",\\"28.984\\",\\"28.984\\",2,2,order,wilhemina +VAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Abd,Abd,\\"Abd Lamb\\",\\"Abd Lamb\\",MALE,52,Lamb,Lamb,\\"(empty)\\",Wednesday,2,\\"abd@lamb-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Angeldale,Angeldale,\\"Jun 25, 2019 @ 00:00:00.000\\",569163,\\"sold_product_569163_1774, sold_product_569163_23724\\",\\"sold_product_569163_1774, sold_product_569163_23724\\",\\"60, 75\\",\\"60, 75\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Angeldale\\",\\"Angeldale, Angeldale\\",\\"27.594, 37.5\\",\\"60, 75\\",\\"1,774, 23,724\\",\\"Lace-ups - cognac, Lace-ups - bordeaux\\",\\"Lace-ups - cognac, Lace-ups - bordeaux\\",\\"1, 1\\",\\"ZO0681106811, ZO0682706827\\",\\"0, 0\\",\\"60, 75\\",\\"60, 75\\",\\"0, 0\\",\\"ZO0681106811, ZO0682706827\\",135,135,2,2,order,abd +VQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Clarice,Clarice,\\"Clarice Potter\\",\\"Clarice Potter\\",FEMALE,18,Potter,Potter,\\"(empty)\\",Wednesday,2,\\"clarice@potter-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569214,\\"sold_product_569214_15372, sold_product_569214_13660\\",\\"sold_product_569214_15372, sold_product_569214_13660\\",\\"20.984, 25.984\\",\\"20.984, 25.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"10.703, 13.25\\",\\"20.984, 25.984\\",\\"15,372, 13,660\\",\\"Jersey dress - khaki, Across body bag - brown\\",\\"Jersey dress - khaki, Across body bag - brown\\",\\"1, 1\\",\\"ZO0490104901, ZO0087200872\\",\\"0, 0\\",\\"20.984, 25.984\\",\\"20.984, 25.984\\",\\"0, 0\\",\\"ZO0490104901, ZO0087200872\\",\\"46.969\\",\\"46.969\\",2,2,order,clarice +VgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Lawrence\\",\\"Fitzgerald Lawrence\\",MALE,11,Lawrence,Lawrence,\\"(empty)\\",Wednesday,2,\\"fitzgerald@lawrence-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568875,\\"sold_product_568875_22460, sold_product_568875_12482\\",\\"sold_product_568875_22460, sold_product_568875_12482\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.92, 30\\",\\"7.988, 60\\",\\"22,460, 12,482\\",\\"3 PACK - Socks - white, Across body bag - black\\",\\"3 PACK - Socks - white, Across body bag - black\\",\\"1, 1\\",\\"ZO0613606136, ZO0463804638\\",\\"0, 0\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"0, 0\\",\\"ZO0613606136, ZO0463804638\\",68,68,2,2,order,fuzzy +VwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Wagdi,Wagdi,\\"Wagdi Griffin\\",\\"Wagdi Griffin\\",MALE,15,Griffin,Griffin,\\"(empty)\\",Wednesday,2,\\"wagdi@griffin-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568943,\\"sold_product_568943_22910, sold_product_568943_1665\\",\\"sold_product_568943_22910, sold_product_568943_1665\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"13.242, 31.203\\",\\"24.984, 65\\",\\"22,910, 1,665\\",\\"Cardigan - black, Boots - light brown\\",\\"Cardigan - black, Boots - light brown\\",\\"1, 1\\",\\"ZO0445804458, ZO0686106861\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0445804458, ZO0686106861\\",90,90,2,2,order,wagdi +WAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Dennis\\",\\"Yahya Dennis\\",MALE,23,Dennis,Dennis,\\"(empty)\\",Wednesday,2,\\"yahya@dennis-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569046,\\"sold_product_569046_15527, sold_product_569046_3489\\",\\"sold_product_569046_15527, sold_product_569046_3489\\",\\"33, 22.984\\",\\"33, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"15.844, 12.18\\",\\"33, 22.984\\",\\"15,527, 3,489\\",\\"Lace-ups - black, Tights - black\\",\\"Lace-ups - black, Tights - black\\",\\"1, 1\\",\\"ZO0393103931, ZO0619906199\\",\\"0, 0\\",\\"33, 22.984\\",\\"33, 22.984\\",\\"0, 0\\",\\"ZO0393103931, ZO0619906199\\",\\"55.969\\",\\"55.969\\",2,2,order,yahya +WQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Cortez\\",\\"Brigitte Cortez\\",FEMALE,12,Cortez,Cortez,\\"(empty)\\",Wednesday,2,\\"brigitte@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569103,\\"sold_product_569103_23059, sold_product_569103_19509\\",\\"sold_product_569103_23059, sold_product_569103_19509\\",\\"21.984, 28.984\\",\\"21.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"11.648, 15.648\\",\\"21.984, 28.984\\",\\"23,059, 19,509\\",\\"Jumper dress - bordeaux, Blouse - dark red\\",\\"Jumper dress - bordeaux, Blouse - dark red\\",\\"1, 1\\",\\"ZO0636506365, ZO0345503455\\",\\"0, 0\\",\\"21.984, 28.984\\",\\"21.984, 28.984\\",\\"0, 0\\",\\"ZO0636506365, ZO0345503455\\",\\"50.969\\",\\"50.969\\",2,2,order,brigitte +WgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Morgan\\",\\"Abdulraheem Al Morgan\\",MALE,33,Morgan,Morgan,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@morgan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568993,\\"sold_product_568993_21293, sold_product_568993_13143\\",\\"sold_product_568993_21293, sold_product_568993_13143\\",\\"24.984, 155\\",\\"24.984, 155\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"12.742, 79.063\\",\\"24.984, 155\\",\\"21,293, 13,143\\",\\"Trainers - white, Slip-ons - black\\",\\"Trainers - white, Slip-ons - black\\",\\"1, 1\\",\\"ZO0510505105, ZO0482604826\\",\\"0, 0\\",\\"24.984, 155\\",\\"24.984, 155\\",\\"0, 0\\",\\"ZO0510505105, ZO0482604826\\",180,180,2,2,order,abdulraheem +EAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Lloyd\\",\\"Sultan Al Lloyd\\",MALE,19,Lloyd,Lloyd,\\"(empty)\\",Wednesday,2,\\"sultan al@lloyd-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",720661,\\"sold_product_720661_22855, sold_product_720661_15602, sold_product_720661_15204, sold_product_720661_22811\\",\\"sold_product_720661_22855, sold_product_720661_15602, sold_product_720661_15204, sold_product_720661_22811\\",\\"22.984, 42, 42, 24.984\\",\\"22.984, 42, 42, 24.984\\",\\"Men's Clothing, Men's Accessories, Men's Accessories, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Low Tide Media\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Low Tide Media\\",\\"10.813, 21.828, 21.406, 11.5\\",\\"22.984, 42, 42, 24.984\\",\\"22,855, 15,602, 15,204, 22,811\\",\\"Shorts - black, Weekend bag - black , Weekend bag - black, Cardigan - beige multicolor\\",\\"Shorts - black, Weekend bag - black , Weekend bag - black, Cardigan - beige multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0423004230, ZO0471604716, ZO0315303153, ZO0445604456\\",\\"0, 0, 0, 0\\",\\"22.984, 42, 42, 24.984\\",\\"22.984, 42, 42, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0423004230, ZO0471604716, ZO0315303153, ZO0445604456\\",132,132,4,4,order,sultan +RQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Perkins\\",\\"Betty Perkins\\",FEMALE,44,Perkins,Perkins,\\"(empty)\\",Wednesday,2,\\"betty@perkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Microlutions, Champion Arts\\",\\"Microlutions, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569144,\\"sold_product_569144_9379, sold_product_569144_15599\\",\\"sold_product_569144_9379, sold_product_569144_15599\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Champion Arts\\",\\"Microlutions, Champion Arts\\",\\"16.813, 15.648\\",\\"33, 28.984\\",\\"9,379, 15,599\\",\\"Trousers - black, Tracksuit top - dark grey multicolor\\",\\"Trousers - black, Tracksuit top - dark grey multicolor\\",\\"1, 1\\",\\"ZO0108101081, ZO0501105011\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0108101081, ZO0501105011\\",\\"61.969\\",\\"61.969\\",2,2,order,betty +RgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Mullins\\",\\"Muniz Mullins\\",MALE,37,Mullins,Mullins,\\"(empty)\\",Wednesday,2,\\"muniz@mullins-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569198,\\"sold_product_569198_13676, sold_product_569198_6033\\",\\"sold_product_569198_13676, sold_product_569198_6033\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"15.938, 9.117\\",\\"28.984, 18.984\\",\\"13,676, 6,033\\",\\"Across body bag - brown , Sweatshirt - white\\",\\"Across body bag - brown , Sweatshirt - white\\",\\"1, 1\\",\\"ZO0464304643, ZO0581905819\\",\\"0, 0\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"0, 0\\",\\"ZO0464304643, ZO0581905819\\",\\"47.969\\",\\"47.969\\",2,2,order,muniz +RwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Yahya,Yahya,\\"Yahya Brady\\",\\"Yahya Brady\\",MALE,23,Brady,Brady,\\"(empty)\\",Wednesday,2,\\"yahya@brady-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Oceanavigations\\",\\"Spherecords, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568845,\\"sold_product_568845_11493, sold_product_568845_18854\\",\\"sold_product_568845_11493, sold_product_568845_18854\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Oceanavigations\\",\\"Spherecords, Oceanavigations\\",\\"10.078, 46.75\\",\\"20.984, 85\\",\\"11,493, 18,854\\",\\"Tracksuit bottoms - light grey multicolor, Boots - Midnight Blue\\",\\"Tracksuit bottoms - light grey multicolor, Boots - Midnight Blue\\",\\"1, 1\\",\\"ZO0657906579, ZO0258102581\\",\\"0, 0\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"0, 0\\",\\"ZO0657906579, ZO0258102581\\",106,106,2,2,order,yahya +SAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,rania,rania,\\"rania Byrd\\",\\"rania Byrd\\",FEMALE,24,Byrd,Byrd,\\"(empty)\\",Wednesday,2,\\"rania@byrd-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Pyramidustries,Pyramidustries,\\"Jun 25, 2019 @ 00:00:00.000\\",568894,\\"sold_product_568894_21617, sold_product_568894_16951\\",\\"sold_product_568894_21617, sold_product_568894_16951\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"21, 11.117\\",\\"42, 20.984\\",\\"21,617, 16,951\\",\\"Cowboy/Biker boots - black, Clutch - black\\",\\"Cowboy/Biker boots - black, Clutch - black\\",\\"1, 1\\",\\"ZO0141801418, ZO0206302063\\",\\"0, 0\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"0, 0\\",\\"ZO0141801418, ZO0206302063\\",\\"62.969\\",\\"62.969\\",2,2,order,rani +SQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Carpenter\\",\\"rania Carpenter\\",FEMALE,24,Carpenter,Carpenter,\\"(empty)\\",Wednesday,2,\\"rania@carpenter-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Spherecords,Spherecords,\\"Jun 25, 2019 @ 00:00:00.000\\",568938,\\"sold_product_568938_18398, sold_product_568938_19241\\",\\"sold_product_568938_18398, sold_product_568938_19241\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spherecords\\",\\"Spherecords, Spherecords\\",\\"5.391, 9.172\\",\\"10.992, 16.984\\",\\"18,398, 19,241\\",\\"Vest - black, Tracksuit bottoms - navy\\",\\"Vest - black, Tracksuit bottoms - navy\\",\\"1, 1\\",\\"ZO0642806428, ZO0632506325\\",\\"0, 0\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"0, 0\\",\\"ZO0642806428, ZO0632506325\\",\\"27.984\\",\\"27.984\\",2,2,order,rani +SgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Meyer\\",\\"Fitzgerald Meyer\\",MALE,11,Meyer,Meyer,\\"(empty)\\",Wednesday,2,\\"fitzgerald@meyer-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569045,\\"sold_product_569045_17857, sold_product_569045_12592\\",\\"sold_product_569045_17857, sold_product_569045_12592\\",\\"85, 14.992\\",\\"85, 14.992\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"39.938, 7.051\\",\\"85, 14.992\\",\\"17,857, 12,592\\",\\"Laptop bag - black, Belt - dark brown \\",\\"Laptop bag - black, Belt - dark brown \\",\\"1, 1\\",\\"ZO0315903159, ZO0461104611\\",\\"0, 0\\",\\"85, 14.992\\",\\"85, 14.992\\",\\"0, 0\\",\\"ZO0315903159, ZO0461104611\\",100,100,2,2,order,fuzzy +SwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Thad,Thad,\\"Thad Munoz\\",\\"Thad Munoz\\",MALE,30,Munoz,Munoz,\\"(empty)\\",Wednesday,2,\\"thad@munoz-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569097,\\"sold_product_569097_20740, sold_product_569097_12607\\",\\"sold_product_569097_20740, sold_product_569097_12607\\",\\"33, 155\\",\\"33, 155\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"14.852, 83.688\\",\\"33, 155\\",\\"20,740, 12,607\\",\\"High-top trainers - beige, Smart slip-ons - black\\",\\"High-top trainers - beige, Smart slip-ons - black\\",\\"1, 1\\",\\"ZO0511605116, ZO0483004830\\",\\"0, 0\\",\\"33, 155\\",\\"33, 155\\",\\"0, 0\\",\\"ZO0511605116, ZO0483004830\\",188,188,2,2,order,thad +dwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Franklin\\",\\"Elyssa Franklin\\",FEMALE,27,Franklin,Franklin,\\"(empty)\\",Wednesday,2,\\"elyssa@franklin-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Angeldale, Gnomehouse, Tigress Enterprises\\",\\"Angeldale, Gnomehouse, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",727370,\\"sold_product_727370_24280, sold_product_727370_20519, sold_product_727370_18829, sold_product_727370_16904\\",\\"sold_product_727370_24280, sold_product_727370_20519, sold_product_727370_18829, sold_product_727370_16904\\",\\"85, 50, 37, 33\\",\\"85, 50, 37, 33\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Shoes\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Gnomehouse, Tigress Enterprises, Tigress Enterprises\\",\\"Angeldale, Gnomehouse, Tigress Enterprises, Tigress Enterprises\\",\\"45.875, 24.5, 17.391, 15.508\\",\\"85, 50, 37, 33\\",\\"24,280, 20,519, 18,829, 16,904\\",\\"Boots - black, Classic heels - Midnight Blue, Jersey dress - Blue Violety/black, Trainers - black\\",\\"Boots - black, Classic heels - Midnight Blue, Jersey dress - Blue Violety/black, Trainers - black\\",\\"1, 1, 1, 1\\",\\"ZO0680206802, ZO0321703217, ZO0049900499, ZO0029400294\\",\\"0, 0, 0, 0\\",\\"85, 50, 37, 33\\",\\"85, 50, 37, 33\\",\\"0, 0, 0, 0\\",\\"ZO0680206802, ZO0321703217, ZO0049900499, ZO0029400294\\",205,205,4,4,order,elyssa +kwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Frances,Frances,\\"Frances Davidson\\",\\"Frances Davidson\\",FEMALE,49,Davidson,Davidson,\\"(empty)\\",Wednesday,2,\\"frances@davidson-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568751,\\"sold_product_568751_22085, sold_product_568751_22963\\",\\"sold_product_568751_22085, sold_product_568751_22963\\",\\"11.992, 7.988\\",\\"11.992, 7.988\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"6.352, 4.148\\",\\"11.992, 7.988\\",\\"22,085, 22,963\\",\\"Hat - black, 3 PACK - Socks - grey/white/black\\",\\"Hat - black, 3 PACK - Socks - grey/white/black\\",\\"1, 1\\",\\"ZO0308703087, ZO0613106131\\",\\"0, 0\\",\\"11.992, 7.988\\",\\"11.992, 7.988\\",\\"0, 0\\",\\"ZO0308703087, ZO0613106131\\",\\"19.984\\",\\"19.984\\",2,2,order,frances +oQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Nash\\",\\"Yasmine Nash\\",FEMALE,43,Nash,Nash,\\"(empty)\\",Wednesday,2,\\"yasmine@nash-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569010,\\"sold_product_569010_17948, sold_product_569010_22803\\",\\"sold_product_569010_17948, sold_product_569010_22803\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"15.359, 17.484\\",\\"28.984, 33\\",\\"17,948, 22,803\\",\\"Tote bag - old rose, Blouse - red\\",\\"Tote bag - old rose, Blouse - red\\",\\"1, 1\\",\\"ZO0090700907, ZO0265002650\\",\\"0, 0\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"0, 0\\",\\"ZO0090700907, ZO0265002650\\",\\"61.969\\",\\"61.969\\",2,2,order,yasmine +uwMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Rivera\\",\\"Tariq Rivera\\",MALE,25,Rivera,Rivera,\\"(empty)\\",Wednesday,2,\\"tariq@rivera-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568745,\\"sold_product_568745_24487, sold_product_568745_17279\\",\\"sold_product_568745_24487, sold_product_568745_17279\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.906, 6.109\\",\\"20.984, 11.992\\",\\"24,487, 17,279\\",\\"Chinos - grey, Hat - navy\\",\\"Chinos - grey, Hat - navy\\",\\"1, 1\\",\\"ZO0528305283, ZO0309203092\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0528305283, ZO0309203092\\",\\"32.969\\",\\"32.969\\",2,2,order,tariq +AwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories, Women's Clothing\\",\\"Women's Shoes, Women's Accessories, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Simpson\\",\\"Rabbia Al Simpson\\",FEMALE,5,Simpson,Simpson,\\"(empty)\\",Wednesday,2,\\"rabbia al@simpson-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",728962,\\"sold_product_728962_24881, sold_product_728962_18382, sold_product_728962_14470, sold_product_728962_18450\\",\\"sold_product_728962_24881, sold_product_728962_18382, sold_product_728962_14470, sold_product_728962_18450\\",\\"42, 24.984, 28.984, 50\\",\\"42, 24.984, 28.984, 50\\",\\"Women's Shoes, Women's Accessories, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Accessories, Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Tigress Enterprises, Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Tigress Enterprises, Tigress Enterprises, Gnomehouse\\",\\"20.578, 12.992, 15.648, 22.5\\",\\"42, 24.984, 28.984, 50\\",\\"24,881, 18,382, 14,470, 18,450\\",\\"Ankle boots - black, Across body bag - taupe/black/pink, Cardigan - tan, Summer dress - flame scarlet\\",\\"Ankle boots - black, Across body bag - taupe/black/pink, Cardigan - tan, Summer dress - flame scarlet\\",\\"1, 1, 1, 1\\",\\"ZO0019800198, ZO0089200892, ZO0069700697, ZO0332303323\\",\\"0, 0, 0, 0\\",\\"42, 24.984, 28.984, 50\\",\\"42, 24.984, 28.984, 50\\",\\"0, 0, 0, 0\\",\\"ZO0019800198, ZO0089200892, ZO0069700697, ZO0332303323\\",146,146,4,4,order,rabbia +XAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Love\\",\\"Yahya Love\\",MALE,23,Love,Love,\\"(empty)\\",Wednesday,2,\\"yahya@love-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568069,\\"sold_product_568069_14245, sold_product_568069_19287\\",\\"sold_product_568069_14245, sold_product_568069_19287\\",\\"28.984, 21.984\\",\\"28.984, 21.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"13.922, 10.563\\",\\"28.984, 21.984\\",\\"14,245, 19,287\\",\\"Trousers - grey, Chinos - dark blue\\",\\"Trousers - grey, Chinos - dark blue\\",\\"1, 1\\",\\"ZO0530305303, ZO0528405284\\",\\"0, 0\\",\\"28.984, 21.984\\",\\"28.984, 21.984\\",\\"0, 0\\",\\"ZO0530305303, ZO0528405284\\",\\"50.969\\",\\"50.969\\",2,2,order,yahya +jQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Massey\\",\\"Rabbia Al Massey\\",FEMALE,5,Massey,Massey,\\"(empty)\\",Wednesday,2,\\"rabbia al@massey-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises MAMA, Champion Arts, Microlutions, Primemaster\\",\\"Tigress Enterprises MAMA, Champion Arts, Microlutions, Primemaster\\",\\"Jun 25, 2019 @ 00:00:00.000\\",732546,\\"sold_product_732546_17971, sold_product_732546_18249, sold_product_732546_18483, sold_product_732546_18726\\",\\"sold_product_732546_17971, sold_product_732546_18249, sold_product_732546_18483, sold_product_732546_18726\\",\\"36, 24.984, 20.984, 140\\",\\"36, 24.984, 20.984, 140\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises MAMA, Champion Arts, Microlutions, Primemaster\\",\\"Tigress Enterprises MAMA, Champion Arts, Microlutions, Primemaster\\",\\"19.063, 13.742, 10.078, 64.375\\",\\"36, 24.984, 20.984, 140\\",\\"17,971, 18,249, 18,483, 18,726\\",\\"Jersey dress - navy/offwhite, Hoodie - off-white, Print T-shirt - olive night, High heeled boots - stone\\",\\"Jersey dress - navy/offwhite, Hoodie - off-white, Print T-shirt - olive night, High heeled boots - stone\\",\\"1, 1, 1, 1\\",\\"ZO0228602286, ZO0502605026, ZO0108901089, ZO0362503625\\",\\"0, 0, 0, 0\\",\\"36, 24.984, 20.984, 140\\",\\"36, 24.984, 20.984, 140\\",\\"0, 0, 0, 0\\",\\"ZO0228602286, ZO0502605026, ZO0108901089, ZO0362503625\\",222,222,4,4,order,rabbia +BwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Simpson\\",\\"Wilhemina St. Simpson\\",FEMALE,17,Simpson,Simpson,\\"(empty)\\",Wednesday,2,\\"wilhemina st.@simpson-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries active, Tigress Enterprises\\",\\"Pyramidustries active, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568218,\\"sold_product_568218_10736, sold_product_568218_16297\\",\\"sold_product_568218_10736, sold_product_568218_16297\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Tigress Enterprises\\",\\"Pyramidustries active, Tigress Enterprises\\",\\"16.172, 9.344\\",\\"33, 16.984\\",\\"10,736, 16,297\\",\\"Tracksuit top - grey multicolor , Watch - nude\\",\\"Tracksuit top - grey multicolor , Watch - nude\\",\\"1, 1\\",\\"ZO0227402274, ZO0079000790\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0227402274, ZO0079000790\\",\\"49.969\\",\\"49.969\\",2,2,order,wilhemina +CAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Perkins\\",\\"Robbie Perkins\\",MALE,48,Perkins,Perkins,\\"(empty)\\",Wednesday,2,\\"robbie@perkins-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568278,\\"sold_product_568278_6696, sold_product_568278_21136\\",\\"sold_product_568278_6696, sold_product_568278_21136\\",\\"33, 33\\",\\"33, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"15.844, 17.813\\",\\"33, 33\\",\\"6,696, 21,136\\",\\"Slim fit jeans - dark blue, Jumper - dark blue\\",\\"Slim fit jeans - dark blue, Jumper - dark blue\\",\\"1, 1\\",\\"ZO0536705367, ZO0449804498\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0536705367, ZO0449804498\\",66,66,2,2,order,robbie +CQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Ruiz\\",\\"Boris Ruiz\\",MALE,36,Ruiz,Ruiz,\\"(empty)\\",Wednesday,2,\\"boris@ruiz-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568428,\\"sold_product_568428_22274, sold_product_568428_12864\\",\\"sold_product_568428_22274, sold_product_568428_12864\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"34.438, 11.719\\",\\"65, 22.984\\",\\"22,274, 12,864\\",\\"Suit jacket - black, SLIM FIT - Formal shirt - black\\",\\"Suit jacket - black, SLIM FIT - Formal shirt - black\\",\\"1, 1\\",\\"ZO0408404084, ZO0422304223\\",\\"0, 0\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"0, 0\\",\\"ZO0408404084, ZO0422304223\\",88,88,2,2,order,boris +CgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Hopkins\\",\\"Abigail Hopkins\\",FEMALE,46,Hopkins,Hopkins,\\"(empty)\\",Wednesday,2,\\"abigail@hopkins-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568492,\\"sold_product_568492_21002, sold_product_568492_19078\\",\\"sold_product_568492_21002, sold_product_568492_19078\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"17.156, 8.828\\",\\"33, 16.984\\",\\"21,002, 19,078\\",\\"Shirt - Dark Turquoise, Print T-shirt - black\\",\\"Shirt - Dark Turquoise, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0346103461, ZO0054100541\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0346103461, ZO0054100541\\",\\"49.969\\",\\"49.969\\",2,2,order,abigail +GgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Greene\\",\\"Abdulraheem Al Greene\\",MALE,33,Greene,Greene,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@greene-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569262,\\"sold_product_569262_11467, sold_product_569262_11510\\",\\"sold_product_569262_11467, sold_product_569262_11510\\",\\"12.992, 10.992\\",\\"12.992, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"6.109, 5.82\\",\\"12.992, 10.992\\",\\"11,467, 11,510\\",\\"3 PACK - Shorts - black/royal/mint, Sports shirt - black\\",\\"3 PACK - Shorts - black/royal/mint, Sports shirt - black\\",\\"1, 1\\",\\"ZO0609906099, ZO0614806148\\",\\"0, 0\\",\\"12.992, 10.992\\",\\"12.992, 10.992\\",\\"0, 0\\",\\"ZO0609906099, ZO0614806148\\",\\"23.984\\",\\"23.984\\",2,2,order,abdulraheem +GwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mckenzie\\",\\"Abd Mckenzie\\",MALE,52,Mckenzie,Mckenzie,\\"(empty)\\",Wednesday,2,\\"abd@mckenzie-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569306,\\"sold_product_569306_13753, sold_product_569306_19486\\",\\"sold_product_569306_13753, sold_product_569306_19486\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"13.742, 44.188\\",\\"24.984, 85\\",\\"13,753, 19,486\\",\\"Formal shirt - white/blue, Snowboard jacket - black\\",\\"Formal shirt - white/blue, Snowboard jacket - black\\",\\"1, 1\\",\\"ZO0412004120, ZO0625406254\\",\\"0, 0\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"0, 0\\",\\"ZO0412004120, ZO0625406254\\",110,110,2,2,order,abd +0gMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Yuri,Yuri,\\"Yuri Perry\\",\\"Yuri Perry\\",MALE,21,Perry,Perry,\\"(empty)\\",Wednesday,2,\\"yuri@perry-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569223,\\"sold_product_569223_12715, sold_product_569223_20466\\",\\"sold_product_569223_12715, sold_product_569223_20466\\",\\"18.984, 7.988\\",\\"18.984, 7.988\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"8.742, 4.23\\",\\"18.984, 7.988\\",\\"12,715, 20,466\\",\\"Polo shirt - off-white, Hat - black\\",\\"Polo shirt - off-white, Hat - black\\",\\"1, 1\\",\\"ZO0444004440, ZO0596805968\\",\\"0, 0\\",\\"18.984, 7.988\\",\\"18.984, 7.988\\",\\"0, 0\\",\\"ZO0444004440, ZO0596805968\\",\\"26.984\\",\\"26.984\\",2,2,order,yuri +GAMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Perkins\\",\\"Muniz Perkins\\",MALE,37,Perkins,Perkins,\\"(empty)\\",Wednesday,2,\\"muniz@perkins-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568039,\\"sold_product_568039_13197, sold_product_568039_11137\\",\\"sold_product_568039_13197, sold_product_568039_11137\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.172, 15.359\\",\\"10.992, 28.984\\",\\"13,197, 11,137\\",\\"Sunglasses - black/silver-coloured, Shirt - white\\",\\"Sunglasses - black/silver-coloured, Shirt - white\\",\\"1, 1\\",\\"ZO0599705997, ZO0416704167\\",\\"0, 0\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"0, 0\\",\\"ZO0599705997, ZO0416704167\\",\\"39.969\\",\\"39.969\\",2,2,order,muniz +YgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Parker\\",\\"Abd Parker\\",MALE,52,Parker,Parker,\\"(empty)\\",Wednesday,2,\\"abd@parker-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568117,\\"sold_product_568117_13602, sold_product_568117_20020\\",\\"sold_product_568117_13602, sold_product_568117_20020\\",\\"20.984, 60\\",\\"20.984, 60\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"10.289, 28.797\\",\\"20.984, 60\\",\\"13,602, 20,020\\",\\"Across body bag - dark brown, Boots - navy\\",\\"Across body bag - dark brown, Boots - navy\\",\\"1, 1\\",\\"ZO0315203152, ZO0406304063\\",\\"0, 0\\",\\"20.984, 60\\",\\"20.984, 60\\",\\"0, 0\\",\\"ZO0315203152, ZO0406304063\\",81,81,2,2,order,abd +YwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Figueroa\\",\\"Clarice Figueroa\\",FEMALE,18,Figueroa,Figueroa,\\"(empty)\\",Wednesday,2,\\"clarice@figueroa-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568165,\\"sold_product_568165_22895, sold_product_568165_20510\\",\\"sold_product_568165_22895, sold_product_568165_20510\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"13.492, 28.797\\",\\"24.984, 60\\",\\"22,895, 20,510\\",\\"Vest - moroccan blue, Dress - navy blazer\\",\\"Vest - moroccan blue, Dress - navy blazer\\",\\"1, 1\\",\\"ZO0065600656, ZO0337003370\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0065600656, ZO0337003370\\",85,85,2,2,order,clarice +hQMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Mccarthy\\",\\"Elyssa Mccarthy\\",FEMALE,27,Mccarthy,Mccarthy,\\"(empty)\\",Wednesday,2,\\"elyssa@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568393,\\"sold_product_568393_5224, sold_product_568393_18968\\",\\"sold_product_568393_5224, sold_product_568393_18968\\",\\"85, 50\\",\\"85, 50\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"41.656, 25\\",\\"85, 50\\",\\"5,224, 18,968\\",\\"Boots - cognac, High heeled sandals - black\\",\\"Boots - cognac, High heeled sandals - black\\",\\"1, 1\\",\\"ZO0374103741, ZO0242102421\\",\\"0, 0\\",\\"85, 50\\",\\"85, 50\\",\\"0, 0\\",\\"ZO0374103741, ZO0242102421\\",135,135,2,2,order,elyssa +1QMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Cunningham\\",\\"Gwen Cunningham\\",FEMALE,26,Cunningham,Cunningham,\\"(empty)\\",Wednesday,2,\\"gwen@cunningham-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",567996,\\"sold_product_567996_21740, sold_product_567996_20451\\",\\"sold_product_567996_21740, sold_product_567996_20451\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"11.25, 15.648\\",\\"24.984, 28.984\\",\\"21,740, 20,451\\",\\"Print T-shirt - scarab, Jersey dress - port royal\\",\\"Print T-shirt - scarab, Jersey dress - port royal\\",\\"1, 1\\",\\"ZO0105401054, ZO0046200462\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0105401054, ZO0046200462\\",\\"53.969\\",\\"53.969\\",2,2,order,gwen +BwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Carr\\",\\"Marwan Carr\\",MALE,51,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"marwan@carr-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569173,\\"sold_product_569173_17602, sold_product_569173_2924\\",\\"sold_product_569173_17602, sold_product_569173_2924\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"11.75, 18.125\\",\\"24.984, 37\\",\\"17,602, 2,924\\",\\"Jumper - mulitcoloured/dark blue, Tracksuit - navy blazer\\",\\"Jumper - mulitcoloured/dark blue, Tracksuit - navy blazer\\",\\"1, 1\\",\\"ZO0452204522, ZO0631206312\\",\\"0, 0\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"0, 0\\",\\"ZO0452204522, ZO0631206312\\",\\"61.969\\",\\"61.969\\",2,2,order,marwan +CAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Frances,Frances,\\"Frances Wells\\",\\"Frances Wells\\",FEMALE,49,Wells,Wells,\\"(empty)\\",Wednesday,2,\\"frances@wells-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569209,\\"sold_product_569209_16819, sold_product_569209_24934\\",\\"sold_product_569209_16819, sold_product_569209_24934\\",\\"42, 50\\",\\"42, 50\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"19.734, 22.5\\",\\"42, 50\\",\\"16,819, 24,934\\",\\"Weekend bag - cognac, Lace-up boots - resin coffee\\",\\"Weekend bag - cognac, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0472304723, ZO0403504035\\",\\"0, 0\\",\\"42, 50\\",\\"42, 50\\",\\"0, 0\\",\\"ZO0472304723, ZO0403504035\\",92,92,2,2,order,frances +CQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Gibbs\\",\\"Jackson Gibbs\\",MALE,13,Gibbs,Gibbs,\\"(empty)\\",Wednesday,2,\\"jackson@gibbs-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568865,\\"sold_product_568865_15772, sold_product_568865_13481\\",\\"sold_product_568865_15772, sold_product_568865_13481\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"6.23, 5.281\\",\\"11.992, 10.992\\",\\"15,772, 13,481\\",\\"Print T-shirt - white, Print T-shirt - white\\",\\"Print T-shirt - white, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0294502945, ZO0560605606\\",\\"0, 0\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"0, 0\\",\\"ZO0294502945, ZO0560605606\\",\\"22.984\\",\\"22.984\\",2,2,order,jackson +CgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Holland\\",\\"Yahya Holland\\",MALE,23,Holland,Holland,\\"(empty)\\",Wednesday,2,\\"yahya@holland-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Oceanavigations,Oceanavigations,\\"Jun 25, 2019 @ 00:00:00.000\\",568926,\\"sold_product_568926_19082, sold_product_568926_17588\\",\\"sold_product_568926_19082, sold_product_568926_17588\\",\\"70, 20.984\\",\\"70, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"37.094, 10.906\\",\\"70, 20.984\\",\\"19,082, 17,588\\",\\"Jumper - ecru, Sweatshirt - mustard\\",\\"Jumper - ecru, Sweatshirt - mustard\\",\\"1, 1\\",\\"ZO0298302983, ZO0300003000\\",\\"0, 0\\",\\"70, 20.984\\",\\"70, 20.984\\",\\"0, 0\\",\\"ZO0298302983, ZO0300003000\\",91,91,2,2,order,yahya +CwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Haynes\\",\\"Selena Haynes\\",FEMALE,42,Haynes,Haynes,\\"(empty)\\",Wednesday,2,\\"selena@haynes-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568955,\\"sold_product_568955_7789, sold_product_568955_11911\\",\\"sold_product_568955_7789, sold_product_568955_11911\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"15.359, 6\\",\\"28.984, 11.992\\",\\"7,789, 11,911\\",\\"Cardigan - blue grey, Leggings - black/white\\",\\"Cardigan - blue grey, Leggings - black/white\\",\\"1, 1\\",\\"ZO0068900689, ZO0076200762\\",\\"0, 0\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"0, 0\\",\\"ZO0068900689, ZO0076200762\\",\\"40.969\\",\\"40.969\\",2,2,order,selena +DAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Yasmine,Yasmine,\\"Yasmine Roberson\\",\\"Yasmine Roberson\\",FEMALE,43,Roberson,Roberson,\\"(empty)\\",Wednesday,2,\\"yasmine@roberson-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569056,\\"sold_product_569056_18276, sold_product_569056_16315\\",\\"sold_product_569056_18276, sold_product_569056_16315\\",\\"10.992, 33\\",\\"10.992, 33\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"5.82, 16.813\\",\\"10.992, 33\\",\\"18,276, 16,315\\",\\"Print T-shirt - dark grey, Handbag - taupe\\",\\"Print T-shirt - dark grey, Handbag - taupe\\",\\"1, 1\\",\\"ZO0494804948, ZO0096000960\\",\\"0, 0\\",\\"10.992, 33\\",\\"10.992, 33\\",\\"0, 0\\",\\"ZO0494804948, ZO0096000960\\",\\"43.969\\",\\"43.969\\",2,2,order,yasmine +DQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Hudson\\",\\"Yasmine Hudson\\",FEMALE,43,Hudson,Hudson,\\"(empty)\\",Wednesday,2,\\"yasmine@hudson-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569083,\\"sold_product_569083_17188, sold_product_569083_11983\\",\\"sold_product_569083_17188, sold_product_569083_11983\\",\\"13.992, 24.984\\",\\"13.992, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"7.551, 12.492\\",\\"13.992, 24.984\\",\\"17,188, 11,983\\",\\"Bustier - dark blue, Summer dress - red\\",\\"Bustier - dark blue, Summer dress - red\\",\\"1, 1\\",\\"ZO0099000990, ZO0631606316\\",\\"0, 0\\",\\"13.992, 24.984\\",\\"13.992, 24.984\\",\\"0, 0\\",\\"ZO0099000990, ZO0631606316\\",\\"38.969\\",\\"38.969\\",2,2,order,yasmine +EgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Conner\\",\\"Jackson Conner\\",MALE,13,Conner,Conner,\\"(empty)\\",Wednesday,2,\\"jackson@conner-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, (empty), Low Tide Media\\",\\"Oceanavigations, (empty), Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",717726,\\"sold_product_717726_23932, sold_product_717726_12833, sold_product_717726_20363, sold_product_717726_13390\\",\\"sold_product_717726_23932, sold_product_717726_12833, sold_product_717726_20363, sold_product_717726_13390\\",\\"28.984, 155, 50, 24.984\\",\\"28.984, 155, 50, 24.984\\",\\"Men's Clothing, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, (empty), Low Tide Media, Oceanavigations\\",\\"Oceanavigations, (empty), Low Tide Media, Oceanavigations\\",\\"13.922, 79.063, 24, 12\\",\\"28.984, 155, 50, 24.984\\",\\"23,932, 12,833, 20,363, 13,390\\",\\"SVEN - Jeans Tapered Fit - light blue, Smart lace-ups - cognac, Boots - Lime, Chinos - military green\\",\\"SVEN - Jeans Tapered Fit - light blue, Smart lace-ups - cognac, Boots - Lime, Chinos - military green\\",\\"1, 1, 1, 1\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\",\\"0, 0, 0, 0\\",\\"28.984, 155, 50, 24.984\\",\\"28.984, 155, 50, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\",259,259,4,4,order,jackson +QwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,rania,rania,\\"rania Chapman\\",\\"rania Chapman\\",FEMALE,24,Chapman,Chapman,\\"(empty)\\",Wednesday,2,\\"rania@chapman-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568149,\\"sold_product_568149_12205, sold_product_568149_24905\\",\\"sold_product_568149_12205, sold_product_568149_24905\\",\\"33, 80\\",\\"33, 80\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"15.18, 42.375\\",\\"33, 80\\",\\"12,205, 24,905\\",\\"Jacket - black, Lace-up boots - black\\",\\"Jacket - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0342503425, ZO0675206752\\",\\"0, 0\\",\\"33, 80\\",\\"33, 80\\",\\"0, 0\\",\\"ZO0342503425, ZO0675206752\\",113,113,2,2,order,rani +RAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Howell\\",\\"Rabbia Al Howell\\",FEMALE,5,Howell,Howell,\\"(empty)\\",Wednesday,2,\\"rabbia al@howell-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Crystal Lighting, Gnomehouse\\",\\"Crystal Lighting, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568192,\\"sold_product_568192_23290, sold_product_568192_11670\\",\\"sold_product_568192_23290, sold_product_568192_11670\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Crystal Lighting, Gnomehouse\\",\\"Crystal Lighting, Gnomehouse\\",\\"10.703, 9.867\\",\\"20.984, 20.984\\",\\"23,290, 11,670\\",\\"Wool jumper - dark blue, Hat - beige\\",\\"Wool jumper - dark blue, Hat - beige\\",\\"1, 1\\",\\"ZO0485504855, ZO0355603556\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0485504855, ZO0355603556\\",\\"41.969\\",\\"41.969\\",2,2,order,rabbia +YQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Gibbs\\",\\"Elyssa Gibbs\\",FEMALE,27,Gibbs,Gibbs,\\"(empty)\\",Wednesday,2,\\"elyssa@gibbs-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569183,\\"sold_product_569183_12081, sold_product_569183_8623\\",\\"sold_product_569183_12081, sold_product_569183_8623\\",\\"10.992, 17.984\\",\\"10.992, 17.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.172, 8.102\\",\\"10.992, 17.984\\",\\"12,081, 8,623\\",\\"Long sleeved top - dark brown, Long sleeved top - red ochre\\",\\"Long sleeved top - dark brown, Long sleeved top - red ochre\\",\\"1, 1\\",\\"ZO0641206412, ZO0165301653\\",\\"0, 0\\",\\"10.992, 17.984\\",\\"10.992, 17.984\\",\\"0, 0\\",\\"ZO0641206412, ZO0165301653\\",\\"28.984\\",\\"28.984\\",2,2,order,elyssa +YgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Mckinney\\",\\"Kamal Mckinney\\",MALE,39,Mckinney,Mckinney,\\"(empty)\\",Wednesday,2,\\"kamal@mckinney-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568818,\\"sold_product_568818_12415, sold_product_568818_24390\\",\\"sold_product_568818_12415, sold_product_568818_24390\\",\\"18.984, 16.984\\",\\"18.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"9.313, 8.828\\",\\"18.984, 16.984\\",\\"12,415, 24,390\\",\\"Polo shirt - mottled grey, Jumper - dark brown multicolor\\",\\"Polo shirt - mottled grey, Jumper - dark brown multicolor\\",\\"1, 1\\",\\"ZO0294802948, ZO0451404514\\",\\"0, 0\\",\\"18.984, 16.984\\",\\"18.984, 16.984\\",\\"0, 0\\",\\"ZO0294802948, ZO0451404514\\",\\"35.969\\",\\"35.969\\",2,2,order,kamal +YwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robert,Robert,\\"Robert Rivera\\",\\"Robert Rivera\\",MALE,29,Rivera,Rivera,\\"(empty)\\",Wednesday,2,\\"robert@rivera-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568854,\\"sold_product_568854_12479, sold_product_568854_1820\\",\\"sold_product_568854_12479, sold_product_568854_1820\\",\\"10.992, 75\\",\\"10.992, 75\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"5.059, 36.75\\",\\"10.992, 75\\",\\"12,479, 1,820\\",\\"Print T-shirt - black, Smart slip-ons - oro\\",\\"Print T-shirt - black, Smart slip-ons - oro\\",\\"1, 1\\",\\"ZO0616706167, ZO0255402554\\",\\"0, 0\\",\\"10.992, 75\\",\\"10.992, 75\\",\\"0, 0\\",\\"ZO0616706167, ZO0255402554\\",86,86,2,2,order,robert +ZAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Carpenter\\",\\"Ahmed Al Carpenter\\",MALE,4,Carpenter,Carpenter,\\"(empty)\\",Wednesday,2,\\"ahmed al@carpenter-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568901,\\"sold_product_568901_13181, sold_product_568901_23144\\",\\"sold_product_568901_13181, sold_product_568901_23144\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"21, 15.359\\",\\"42, 28.984\\",\\"13,181, 23,144\\",\\"Briefcase - navy, Slim fit jeans - grey\\",\\"Briefcase - navy, Slim fit jeans - grey\\",\\"1, 1\\",\\"ZO0466704667, ZO0427104271\\",\\"0, 0\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"0, 0\\",\\"ZO0466704667, ZO0427104271\\",71,71,2,2,order,ahmed +ZQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Mostafa,Mostafa,\\"Mostafa Hansen\\",\\"Mostafa Hansen\\",MALE,9,Hansen,Hansen,\\"(empty)\\",Wednesday,2,\\"mostafa@hansen-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568954,\\"sold_product_568954_591, sold_product_568954_1974\\",\\"sold_product_568954_591, sold_product_568954_1974\\",\\"65, 60\\",\\"65, 60\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"29.906, 28.203\\",\\"65, 60\\",\\"591, 1,974\\",\\"Lace-up boots - black barro, Lace-up boots - black\\",\\"Lace-up boots - black barro, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0399603996, ZO0685906859\\",\\"0, 0\\",\\"65, 60\\",\\"65, 60\\",\\"0, 0\\",\\"ZO0399603996, ZO0685906859\\",125,125,2,2,order,mostafa +ZgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Pia,Pia,\\"Pia Palmer\\",\\"Pia Palmer\\",FEMALE,45,Palmer,Palmer,\\"(empty)\\",Wednesday,2,\\"pia@palmer-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569033,\\"sold_product_569033_7233, sold_product_569033_18726\\",\\"sold_product_569033_7233, sold_product_569033_18726\\",\\"50, 140\\",\\"50, 140\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"26.484, 64.375\\",\\"50, 140\\",\\"7,233, 18,726\\",\\"Over-the-knee boots - cognac, High heeled boots - stone\\",\\"Over-the-knee boots - cognac, High heeled boots - stone\\",\\"1, 1\\",\\"ZO0015700157, ZO0362503625\\",\\"0, 0\\",\\"50, 140\\",\\"50, 140\\",\\"0, 0\\",\\"ZO0015700157, ZO0362503625\\",190,190,2,2,order,pia +ZwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Mcdonald\\",\\"Fitzgerald Mcdonald\\",MALE,11,Mcdonald,Mcdonald,\\"(empty)\\",Wednesday,2,\\"fitzgerald@mcdonald-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569091,\\"sold_product_569091_13103, sold_product_569091_12677\\",\\"sold_product_569091_13103, sold_product_569091_12677\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"17.156, 8.492\\",\\"33, 16.984\\",\\"13,103, 12,677\\",\\"T-bar sandals - black, Long sleeved top - black\\",\\"T-bar sandals - black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0258602586, ZO0552205522\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0258602586, ZO0552205522\\",\\"49.969\\",\\"49.969\\",2,2,order,fuzzy +aAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Gibbs\\",\\"Ahmed Al Gibbs\\",MALE,4,Gibbs,Gibbs,\\"(empty)\\",Wednesday,2,\\"ahmed al@gibbs-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569003,\\"sold_product_569003_13719, sold_product_569003_12174\\",\\"sold_product_569003_13719, sold_product_569003_12174\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"13.242, 27\\",\\"24.984, 60\\",\\"13,719, 12,174\\",\\"Shirt - blue/grey, Smart lace-ups - Dark Red\\",\\"Shirt - blue/grey, Smart lace-ups - Dark Red\\",\\"1, 1\\",\\"ZO0414704147, ZO0387503875\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0414704147, ZO0387503875\\",85,85,2,2,order,ahmed +bQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Jim,Jim,\\"Jim Potter\\",\\"Jim Potter\\",MALE,41,Potter,Potter,\\"(empty)\\",Wednesday,2,\\"jim@potter-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568707,\\"sold_product_568707_24723, sold_product_568707_24246\\",\\"sold_product_568707_24723, sold_product_568707_24246\\",\\"33, 65\\",\\"33, 65\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"17.484, 33.781\\",\\"33, 65\\",\\"24,723, 24,246\\",\\"High-top trainers - multicolor, Lace-up boots - black\\",\\"High-top trainers - multicolor, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0513305133, ZO0253302533\\",\\"0, 0\\",\\"33, 65\\",\\"33, 65\\",\\"0, 0\\",\\"ZO0513305133, ZO0253302533\\",98,98,2,2,order,jim +eQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Underwood\\",\\"George Underwood\\",MALE,32,Underwood,Underwood,\\"(empty)\\",Wednesday,2,\\"george@underwood-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568019,\\"sold_product_568019_17179, sold_product_568019_20306\\",\\"sold_product_568019_17179, sold_product_568019_20306\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"15.07, 5.52\\",\\"28.984, 11.992\\",\\"17,179, 20,306\\",\\"Chinos - black, Long sleeved top - mottled dark grey\\",\\"Chinos - black, Long sleeved top - mottled dark grey\\",\\"1, 1\\",\\"ZO0530805308, ZO0563905639\\",\\"0, 0\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"0, 0\\",\\"ZO0530805308, ZO0563905639\\",\\"40.969\\",\\"40.969\\",2,2,order,george +qQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Ruiz\\",\\"Yasmine Ruiz\\",FEMALE,43,Ruiz,Ruiz,\\"(empty)\\",Wednesday,2,\\"yasmine@ruiz-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568182,\\"sold_product_568182_18562, sold_product_568182_21438\\",\\"sold_product_568182_18562, sold_product_568182_21438\\",\\"42, 10.992\\",\\"42, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"18.906, 5.711\\",\\"42, 10.992\\",\\"18,562, 21,438\\",\\"Jersey dress - black, Long sleeved top - light grey multicolor\\",\\"Jersey dress - black, Long sleeved top - light grey multicolor\\",\\"1, 1\\",\\"ZO0338603386, ZO0641006410\\",\\"0, 0\\",\\"42, 10.992\\",\\"42, 10.992\\",\\"0, 0\\",\\"ZO0338603386, ZO0641006410\\",\\"52.969\\",\\"52.969\\",2,2,order,yasmine +CwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jim,Jim,\\"Jim Munoz\\",\\"Jim Munoz\\",MALE,41,Munoz,Munoz,\\"(empty)\\",Wednesday,2,\\"jim@munoz-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569299,\\"sold_product_569299_18493, sold_product_569299_22273\\",\\"sold_product_569299_18493, sold_product_569299_22273\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"15.18, 5.93\\",\\"33, 10.992\\",\\"18,493, 22,273\\",\\"Lace-up boots - camel, Shorts - black\\",\\"Lace-up boots - camel, Shorts - black\\",\\"1, 1\\",\\"ZO0519605196, ZO0630806308\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0519605196, ZO0630806308\\",\\"43.969\\",\\"43.969\\",2,2,order,jim +DAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Watkins\\",\\"Jackson Watkins\\",MALE,13,Watkins,Watkins,\\"(empty)\\",Wednesday,2,\\"jackson@watkins-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569123,\\"sold_product_569123_15429, sold_product_569123_23856\\",\\"sold_product_569123_15429, sold_product_569123_23856\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.703, 5.398\\",\\"20.984, 11.992\\",\\"15,429, 23,856\\",\\"Rucksack - black, Polo shirt - dark grey multicolor\\",\\"Rucksack - black, Polo shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0609006090, ZO0441504415\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0609006090, ZO0441504415\\",\\"32.969\\",\\"32.969\\",2,2,order,jackson +kAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Austin\\",\\"Elyssa Austin\\",FEMALE,27,Austin,Austin,\\"(empty)\\",Wednesday,2,\\"elyssa@austin-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises, Pyramidustries active\\",\\"Pyramidustries, Tigress Enterprises, Pyramidustries active\\",\\"Jun 25, 2019 @ 00:00:00.000\\",728335,\\"sold_product_728335_15156, sold_product_728335_21016, sold_product_728335_24932, sold_product_728335_18891\\",\\"sold_product_728335_15156, sold_product_728335_21016, sold_product_728335_24932, sold_product_728335_18891\\",\\"24.984, 33, 21.984, 33\\",\\"24.984, 33, 21.984, 33\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Shoes\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Tigress Enterprises, Pyramidustries active, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises, Pyramidustries active, Tigress Enterprises\\",\\"12.992, 15.844, 12.094, 18.141\\",\\"24.984, 33, 21.984, 33\\",\\"15,156, 21,016, 24,932, 18,891\\",\\"Classic heels - light blue, Ankle boots - black, Tights - grey multicolor, Ankle boots - black\\",\\"Classic heels - light blue, Ankle boots - black, Tights - grey multicolor, Ankle boots - black\\",\\"1, 1, 1, 1\\",\\"ZO0134701347, ZO0026200262, ZO0223102231, ZO0022900229\\",\\"0, 0, 0, 0\\",\\"24.984, 33, 21.984, 33\\",\\"24.984, 33, 21.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0134701347, ZO0026200262, ZO0223102231, ZO0022900229\\",\\"112.938\\",\\"112.938\\",4,4,order,elyssa +mgMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Powell\\",\\"Rabbia Al Powell\\",FEMALE,5,Powell,Powell,\\"(empty)\\",Wednesday,2,\\"rabbia al@powell-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Primemaster, Tigress Enterprises, Spherecords Maternity, Champion Arts\\",\\"Primemaster, Tigress Enterprises, Spherecords Maternity, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",726874,\\"sold_product_726874_12603, sold_product_726874_14008, sold_product_726874_16407, sold_product_726874_23268\\",\\"sold_product_726874_12603, sold_product_726874_14008, sold_product_726874_16407, sold_product_726874_23268\\",\\"140, 37, 13.992, 42\\",\\"140, 37, 13.992, 42\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Primemaster, Tigress Enterprises, Spherecords Maternity, Champion Arts\\",\\"Primemaster, Tigress Enterprises, Spherecords Maternity, Champion Arts\\",\\"70, 18.5, 7, 19.734\\",\\"140, 37, 13.992, 42\\",\\"12,603, 14,008, 16,407, 23,268\\",\\"Boots - Midnight Blue, Summer dress - rose/black, Maxi skirt - mid grey multicolor, Light jacket - black/off-white\\",\\"Boots - Midnight Blue, Summer dress - rose/black, Maxi skirt - mid grey multicolor, Light jacket - black/off-white\\",\\"1, 1, 1, 1\\",\\"ZO0362303623, ZO0035400354, ZO0705207052, ZO0504005040\\",\\"0, 0, 0, 0\\",\\"140, 37, 13.992, 42\\",\\"140, 37, 13.992, 42\\",\\"0, 0, 0, 0\\",\\"ZO0362303623, ZO0035400354, ZO0705207052, ZO0504005040\\",233,233,4,4,order,rabbia +vAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Benson\\",\\"Stephanie Benson\\",FEMALE,6,Benson,Benson,\\"(empty)\\",Wednesday,2,\\"stephanie@benson-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569218,\\"sold_product_569218_18040, sold_product_569218_14398\\",\\"sold_product_569218_18040, sold_product_569218_14398\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"12.25, 10.906\\",\\"24.984, 20.984\\",\\"18,040, 14,398\\",\\"Trousers - black, Tracksuit bottoms - dark grey\\",\\"Trousers - black, Tracksuit bottoms - dark grey\\",\\"1, 1\\",\\"ZO0633206332, ZO0488604886\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0633206332, ZO0488604886\\",\\"45.969\\",\\"45.969\\",2,2,order,stephanie +0wMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Nash\\",\\"Jackson Nash\\",MALE,13,Nash,Nash,\\"(empty)\\",Wednesday,2,\\"jackson@nash-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Spritechnologies, Low Tide Media, Elitelligence\\",\\"Spritechnologies, Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",722613,\\"sold_product_722613_11046, sold_product_722613_11747, sold_product_722613_16568, sold_product_722613_15828\\",\\"sold_product_722613_11046, sold_product_722613_11747, sold_product_722613_16568, sold_product_722613_15828\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spritechnologies, Low Tide Media, Elitelligence, Low Tide Media\\",\\"Spritechnologies, Low Tide Media, Elitelligence, Low Tide Media\\",\\"9.453, 10.906, 15.938, 5.172\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"11,046, 11,747, 16,568, 15,828\\",\\"Tracksuit bottoms - black, Polo shirt - blue, Chinos - dark blue, Tie - black\\",\\"Tracksuit bottoms - black, Polo shirt - blue, Chinos - dark blue, Tie - black\\",\\"1, 1, 1, 1\\",\\"ZO0618806188, ZO0442804428, ZO0530705307, ZO0410804108\\",\\"0, 0, 0, 0\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0618806188, ZO0442804428, ZO0530705307, ZO0410804108\\",\\"81.938\\",\\"81.938\\",4,4,order,jackson +1AMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Kim\\",\\"Sonya Kim\\",FEMALE,28,Kim,Kim,\\"(empty)\\",Wednesday,2,\\"sonya@kim-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568152,\\"sold_product_568152_16870, sold_product_568152_17608\\",\\"sold_product_568152_16870, sold_product_568152_17608\\",\\"37, 28.984\\",\\"37, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"17.391, 14.211\\",\\"37, 28.984\\",\\"16,870, 17,608\\",\\"Blouse - multicolored, Summer dress - black/berry\\",\\"Blouse - multicolored, Summer dress - black/berry\\",\\"1, 1\\",\\"ZO0349303493, ZO0043900439\\",\\"0, 0\\",\\"37, 28.984\\",\\"37, 28.984\\",\\"0, 0\\",\\"ZO0349303493, ZO0043900439\\",66,66,2,2,order,sonya +1QMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Hampton\\",\\"Irwin Hampton\\",MALE,14,Hampton,Hampton,\\"(empty)\\",Wednesday,2,\\"irwin@hampton-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568212,\\"sold_product_568212_19457, sold_product_568212_1471\\",\\"sold_product_568212_19457, sold_product_568212_1471\\",\\"25.984, 60\\",\\"25.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"12.219, 30\\",\\"25.984, 60\\",\\"19,457, 1,471\\",\\"Slim fit jeans - khaki, Lace-up boots - tan\\",\\"Slim fit jeans - khaki, Lace-up boots - tan\\",\\"1, 1\\",\\"ZO0536405364, ZO0688306883\\",\\"0, 0\\",\\"25.984, 60\\",\\"25.984, 60\\",\\"0, 0\\",\\"ZO0536405364, ZO0688306883\\",86,86,2,2,order,irwin +5AMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Gomez\\",\\"Abdulraheem Al Gomez\\",MALE,33,Gomez,Gomez,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@gomez-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568228,\\"sold_product_568228_17075, sold_product_568228_21129\\",\\"sold_product_568228_17075, sold_product_568228_21129\\",\\"60, 22.984\\",\\"60, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"31.797, 11.039\\",\\"60, 22.984\\",\\"17,075, 21,129\\",\\"Smart lace-ups - cognac, Jumper - khaki\\",\\"Smart lace-ups - cognac, Jumper - khaki\\",\\"1, 1\\",\\"ZO0387103871, ZO0580005800\\",\\"0, 0\\",\\"60, 22.984\\",\\"60, 22.984\\",\\"0, 0\\",\\"ZO0387103871, ZO0580005800\\",83,83,2,2,order,abdulraheem +5QMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robert,Robert,\\"Robert Lloyd\\",\\"Robert Lloyd\\",MALE,29,Lloyd,Lloyd,\\"(empty)\\",Wednesday,2,\\"robert@lloyd-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568455,\\"sold_product_568455_13779, sold_product_568455_15022\\",\\"sold_product_568455_13779, sold_product_568455_15022\\",\\"22.984, 60\\",\\"22.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"11.273, 30.594\\",\\"22.984, 60\\",\\"13,779, 15,022\\",\\"Formal shirt - light blue, Lace-ups - cognac\\",\\"Formal shirt - light blue, Lace-ups - cognac\\",\\"1, 1\\",\\"ZO0413104131, ZO0392303923\\",\\"0, 0\\",\\"22.984, 60\\",\\"22.984, 60\\",\\"0, 0\\",\\"ZO0413104131, ZO0392303923\\",83,83,2,2,order,robert +7wMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Evans\\",\\"Abdulraheem Al Evans\\",MALE,33,Evans,Evans,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@evans-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",567994,\\"sold_product_567994_12464, sold_product_567994_14037\\",\\"sold_product_567994_12464, sold_product_567994_14037\\",\\"75, 140\\",\\"75, 140\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"33.75, 68.625\\",\\"75, 140\\",\\"12,464, 14,037\\",\\"Short coat - dark grey, Leather jacket - black\\",\\"Short coat - dark grey, Leather jacket - black\\",\\"1, 1\\",\\"ZO0430904309, ZO0288402884\\",\\"0, 0\\",\\"75, 140\\",\\"75, 140\\",\\"0, 0\\",\\"ZO0430904309, ZO0288402884\\",215,215,2,2,order,abdulraheem +CAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Hayes\\",\\"Elyssa Hayes\\",FEMALE,27,Hayes,Hayes,\\"(empty)\\",Wednesday,2,\\"elyssa@hayes-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568045,\\"sold_product_568045_16186, sold_product_568045_24601\\",\\"sold_product_568045_16186, sold_product_568045_24601\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"5.762, 14.492\\",\\"11.992, 28.984\\",\\"16,186, 24,601\\",\\"Print T-shirt - white, Cardigan - white/black\\",\\"Print T-shirt - white, Cardigan - white/black\\",\\"1, 1\\",\\"ZO0160501605, ZO0069500695\\",\\"0, 0\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"0, 0\\",\\"ZO0160501605, ZO0069500695\\",\\"40.969\\",\\"40.969\\",2,2,order,elyssa +VQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Bryant\\",\\"Elyssa Bryant\\",FEMALE,27,Bryant,Bryant,\\"(empty)\\",Wednesday,2,\\"elyssa@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568308,\\"sold_product_568308_15499, sold_product_568308_17990\\",\\"sold_product_568308_15499, sold_product_568308_17990\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"29.906, 12.992\\",\\"65, 24.984\\",\\"15,499, 17,990\\",\\"Over-the-knee boots - black, Ankle boots - cognac\\",\\"Over-the-knee boots - black, Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0138701387, ZO0024600246\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0138701387, ZO0024600246\\",90,90,2,2,order,elyssa +VgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Stephanie,Stephanie,\\"Stephanie Chapman\\",\\"Stephanie Chapman\\",FEMALE,6,Chapman,Chapman,\\"(empty)\\",Wednesday,2,\\"stephanie@chapman-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568515,\\"sold_product_568515_19990, sold_product_568515_18594\\",\\"sold_product_568515_19990, sold_product_568515_18594\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"5.762, 34.438\\",\\"11.992, 65\\",\\"19,990, 18,594\\",\\"Vest - Forest Green, Classic heels - black\\",\\"Vest - Forest Green, Classic heels - black\\",\\"1, 1\\",\\"ZO0159901599, ZO0238702387\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0159901599, ZO0238702387\\",77,77,2,2,order,stephanie +dgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Marshall\\",\\"Eddie Marshall\\",MALE,38,Marshall,Marshall,\\"(empty)\\",Wednesday,2,\\"eddie@marshall-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",721706,\\"sold_product_721706_21844, sold_product_721706_11106, sold_product_721706_1850, sold_product_721706_22242\\",\\"sold_product_721706_21844, sold_product_721706_11106, sold_product_721706_1850, sold_product_721706_22242\\",\\"33, 10.992, 28.984, 24.984\\",\\"33, 10.992, 28.984, 24.984\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence, Elitelligence, Elitelligence\\",\\"17.484, 5.711, 14.211, 12.992\\",\\"33, 10.992, 28.984, 24.984\\",\\"21,844, 11,106, 1,850, 22,242\\",\\"Lace-up boots - red, 2 PACK - Shorts - black/stripe, Trainers - black/grey, Sweatshirt - black\\",\\"Lace-up boots - red, 2 PACK - Shorts - black/stripe, Trainers - black/grey, Sweatshirt - black\\",\\"1, 1, 1, 1\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\",\\"0, 0, 0, 0\\",\\"33, 10.992, 28.984, 24.984\\",\\"33, 10.992, 28.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\",\\"97.938\\",\\"97.938\\",4,4,order,eddie +fQMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Roberson\\",\\"Wilhemina St. Roberson\\",FEMALE,17,Roberson,Roberson,\\"(empty)\\",Wednesday,2,\\"wilhemina st.@roberson-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569250,\\"sold_product_569250_22975, sold_product_569250_16886\\",\\"sold_product_569250_22975, sold_product_569250_16886\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"17.484, 14.781\\",\\"33, 28.984\\",\\"22,975, 16,886\\",\\"Jersey dress - Medium Sea Green, Wedges - black\\",\\"Jersey dress - Medium Sea Green, Wedges - black\\",\\"1, 1\\",\\"ZO0228902289, ZO0005400054\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0228902289, ZO0005400054\\",\\"61.969\\",\\"61.969\\",2,2,order,wilhemina +3wMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Washington\\",\\"Thad Washington\\",MALE,30,Washington,Washington,\\"(empty)\\",Wednesday,2,\\"thad@washington-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568776,\\"sold_product_568776_22271, sold_product_568776_18957\\",\\"sold_product_568776_22271, sold_product_568776_18957\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"5.711, 11.75\\",\\"10.992, 24.984\\",\\"22,271, 18,957\\",\\"Sports shirt - dark green, Jumper - black\\",\\"Sports shirt - dark green, Jumper - black\\",\\"1, 1\\",\\"ZO0616906169, ZO0296902969\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0616906169, ZO0296902969\\",\\"35.969\\",\\"35.969\\",2,2,order,thad +\\"-wMtOW0BH63Xcmy4524Z\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Moran\\",\\"Samir Moran\\",MALE,34,Moran,Moran,\\"(empty)\\",Wednesday,2,\\"samir@moran-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568014,\\"sold_product_568014_6401, sold_product_568014_19633\\",\\"sold_product_568014_6401, sold_product_568014_19633\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.078, 6.352\\",\\"20.984, 11.992\\",\\"6,401, 19,633\\",\\"Shirt - Blue Violety, Long sleeved top - white and red\\",\\"Shirt - Blue Violety, Long sleeved top - white and red\\",\\"1, 1\\",\\"ZO0523905239, ZO0556605566\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0523905239, ZO0556605566\\",\\"32.969\\",\\"32.969\\",2,2,order,samir +8wMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Riley\\",\\"Elyssa Riley\\",FEMALE,27,Riley,Riley,\\"(empty)\\",Wednesday,2,\\"elyssa@riley-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 25, 2019 @ 00:00:00.000\\",568702,\\"sold_product_568702_18286, sold_product_568702_14025\\",\\"sold_product_568702_18286, sold_product_568702_14025\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"16.5, 11.5\\",\\"33, 24.984\\",\\"18,286, 14,025\\",\\"Ankle boots - black, Blazer - black\\",\\"Ankle boots - black, Blazer - black\\",\\"1, 1\\",\\"ZO0142801428, ZO0182801828\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0142801428, ZO0182801828\\",\\"57.969\\",\\"57.969\\",2,2,order,elyssa +HwMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Lloyd\\",\\"Diane Lloyd\\",FEMALE,22,Lloyd,Lloyd,\\"(empty)\\",Wednesday,2,\\"diane@lloyd-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568128,\\"sold_product_568128_11766, sold_product_568128_22927\\",\\"sold_product_568128_11766, sold_product_568128_22927\\",\\"24.984, 34\\",\\"24.984, 34\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"12.992, 17.672\\",\\"24.984, 34\\",\\"11,766, 22,927\\",\\"Tote bag - berry, Lace-ups - black\\",\\"Tote bag - berry, Lace-ups - black\\",\\"1, 1\\",\\"ZO0087500875, ZO0007100071\\",\\"0, 0\\",\\"24.984, 34\\",\\"24.984, 34\\",\\"0, 0\\",\\"ZO0087500875, ZO0007100071\\",\\"58.969\\",\\"58.969\\",2,2,order,diane +IAMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Fleming\\",\\"Jackson Fleming\\",MALE,13,Fleming,Fleming,\\"(empty)\\",Wednesday,2,\\"jackson@fleming-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568177,\\"sold_product_568177_15382, sold_product_568177_18515\\",\\"sold_product_568177_15382, sold_product_568177_18515\\",\\"37, 65\\",\\"37, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"19.594, 31.844\\",\\"37, 65\\",\\"15,382, 18,515\\",\\"Tracksuit top - mottled grey, Lace-up boots - tan\\",\\"Tracksuit top - mottled grey, Lace-up boots - tan\\",\\"1, 1\\",\\"ZO0584505845, ZO0403804038\\",\\"0, 0\\",\\"37, 65\\",\\"37, 65\\",\\"0, 0\\",\\"ZO0584505845, ZO0403804038\\",102,102,2,2,order,jackson +cwMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Franklin\\",\\"rania Franklin\\",FEMALE,24,Franklin,Franklin,\\"(empty)\\",Wednesday,2,\\"rania@franklin-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569178,\\"sold_product_569178_15398, sold_product_569178_23456\\",\\"sold_product_569178_15398, sold_product_569178_23456\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"15.359, 25.484\\",\\"28.984, 50\\",\\"15,398, 23,456\\",\\"Jumper - offwhite, Maxi dress - black/white\\",\\"Jumper - offwhite, Maxi dress - black/white\\",\\"1, 1\\",\\"ZO0177001770, ZO0260502605\\",\\"0, 0\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"0, 0\\",\\"ZO0177001770, ZO0260502605\\",79,79,2,2,order,rani +dAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Griffin\\",\\"Sonya Griffin\\",FEMALE,28,Griffin,Griffin,\\"(empty)\\",Wednesday,2,\\"sonya@griffin-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568877,\\"sold_product_568877_19521, sold_product_568877_19378\\",\\"sold_product_568877_19521, sold_product_568877_19378\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"11.5, 13.492\\",\\"24.984, 24.984\\",\\"19,521, 19,378\\",\\"Classic heels - cognac, Long sleeved top - winternude\\",\\"Classic heels - cognac, Long sleeved top - winternude\\",\\"1, 1\\",\\"ZO0132401324, ZO0058200582\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0132401324, ZO0058200582\\",\\"49.969\\",\\"49.969\\",2,2,order,sonya +dQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Little\\",\\"Abdulraheem Al Little\\",MALE,33,Little,Little,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@little-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568898,\\"sold_product_568898_11865, sold_product_568898_21764\\",\\"sold_product_568898_11865, sold_product_568898_21764\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"25.984, 15.359\\",\\"50, 28.984\\",\\"11,865, 21,764\\",\\"Down jacket - gru00fcn, Trainers - black\\",\\"Down jacket - gru00fcn, Trainers - black\\",\\"1, 1\\",\\"ZO0542205422, ZO0517805178\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0542205422, ZO0517805178\\",79,79,2,2,order,abdulraheem +dgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Selena,Selena,\\"Selena Padilla\\",\\"Selena Padilla\\",FEMALE,42,Padilla,Padilla,\\"(empty)\\",Wednesday,2,\\"selena@padilla-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568941,\\"sold_product_568941_14120, sold_product_568941_8820\\",\\"sold_product_568941_14120, sold_product_568941_8820\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"5.641, 13.344\\",\\"11.992, 28.984\\",\\"14,120, 8,820\\",\\"3 PACK - Belt - black/red/gunmetal, Jumper - peacoat/light blue\\",\\"3 PACK - Belt - black/red/gunmetal, Jumper - peacoat/light blue\\",\\"1, 1\\",\\"ZO0076600766, ZO0068800688\\",\\"0, 0\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"0, 0\\",\\"ZO0076600766, ZO0068800688\\",\\"40.969\\",\\"40.969\\",2,2,order,selena +dwMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Ramsey\\",\\"Brigitte Ramsey\\",FEMALE,12,Ramsey,Ramsey,\\"(empty)\\",Wednesday,2,\\"brigitte@ramsey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569027,\\"sold_product_569027_15733, sold_product_569027_20410\\",\\"sold_product_569027_15733, sold_product_569027_20410\\",\\"75, 18.984\\",\\"75, 18.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"36, 9.492\\",\\"75, 18.984\\",\\"15,733, 20,410\\",\\"Boots - tan, Long sleeved top - black\\",\\"Boots - tan, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0245402454, ZO0060100601\\",\\"0, 0\\",\\"75, 18.984\\",\\"75, 18.984\\",\\"0, 0\\",\\"ZO0245402454, ZO0060100601\\",94,94,2,2,order,brigitte +eAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Morgan\\",\\"Sonya Morgan\\",FEMALE,28,Morgan,Morgan,\\"(empty)\\",Wednesday,2,\\"sonya@morgan-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569055,\\"sold_product_569055_12453, sold_product_569055_13828\\",\\"sold_product_569055_12453, sold_product_569055_13828\\",\\"60, 33\\",\\"60, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"31.797, 15.18\\",\\"60, 33\\",\\"12,453, 13,828\\",\\"Ankle boots - Midnight Blue, Jumper - white/black\\",\\"Ankle boots - Midnight Blue, Jumper - white/black\\",\\"1, 1\\",\\"ZO0375903759, ZO0269402694\\",\\"0, 0\\",\\"60, 33\\",\\"60, 33\\",\\"0, 0\\",\\"ZO0375903759, ZO0269402694\\",93,93,2,2,order,sonya +eQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Hubbard\\",\\"Pia Hubbard\\",FEMALE,45,Hubbard,Hubbard,\\"(empty)\\",Wednesday,2,\\"pia@hubbard-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Champion Arts\\",\\"Gnomehouse, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569107,\\"sold_product_569107_24376, sold_product_569107_8430\\",\\"sold_product_569107_24376, sold_product_569107_8430\\",\\"60, 60\\",\\"60, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Champion Arts\\",\\"Gnomehouse, Champion Arts\\",\\"27, 30.594\\",\\"60, 60\\",\\"24,376, 8,430\\",\\"Fun and Flowery Dress, Winter coat - red\\",\\"Fun and Flowery Dress, Winter coat - red\\",\\"1, 1\\",\\"ZO0339603396, ZO0504705047\\",\\"0, 0\\",\\"60, 60\\",\\"60, 60\\",\\"0, 0\\",\\"ZO0339603396, ZO0504705047\\",120,120,2,2,order,pia +iQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Clayton\\",\\"Tariq Clayton\\",MALE,25,Clayton,Clayton,\\"(empty)\\",Wednesday,2,\\"tariq@clayton-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Oceanavigations, Low Tide Media\\",\\"Elitelligence, Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",714385,\\"sold_product_714385_13039, sold_product_714385_16435, sold_product_714385_15502, sold_product_714385_6719\\",\\"sold_product_714385_13039, sold_product_714385_16435, sold_product_714385_15502, sold_product_714385_6719\\",\\"24.984, 21.984, 33, 28.984\\",\\"24.984, 21.984, 33, 28.984\\",\\"Men's Clothing, Men's Accessories, Men's Accessories, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Oceanavigations, Low Tide Media\\",\\"Elitelligence, Elitelligence, Oceanavigations, Low Tide Media\\",\\"12.492, 12.094, 15.844, 15.359\\",\\"24.984, 21.984, 33, 28.984\\",\\"13,039, 16,435, 15,502, 6,719\\",\\"Sweatshirt - dark blue, Across body bag - dark grey, Watch - black, Trousers - dark blue\\",\\"Sweatshirt - dark blue, Across body bag - dark grey, Watch - black, Trousers - dark blue\\",\\"1, 1, 1, 1\\",\\"ZO0586805868, ZO0609106091, ZO0310903109, ZO0420104201\\",\\"0, 0, 0, 0\\",\\"24.984, 21.984, 33, 28.984\\",\\"24.984, 21.984, 33, 28.984\\",\\"0, 0, 0, 0\\",\\"ZO0586805868, ZO0609106091, ZO0310903109, ZO0420104201\\",\\"108.938\\",\\"108.938\\",4,4,order,tariq +hQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mcdonald\\",\\"Abd Mcdonald\\",MALE,52,Mcdonald,Mcdonald,\\"(empty)\\",Wednesday,2,\\"abd@mcdonald-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media, Elitelligence\\",\\"Oceanavigations, Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",723213,\\"sold_product_723213_6457, sold_product_723213_19528, sold_product_723213_12063, sold_product_723213_14510\\",\\"sold_product_723213_6457, sold_product_723213_19528, sold_product_723213_12063, sold_product_723213_14510\\",\\"28.984, 20.984, 20.984, 33\\",\\"28.984, 20.984, 20.984, 33\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Low Tide Media, Elitelligence, Oceanavigations\\",\\"Oceanavigations, Low Tide Media, Elitelligence, Oceanavigations\\",\\"15.359, 11.117, 9.867, 15.18\\",\\"28.984, 20.984, 20.984, 33\\",\\"6,457, 19,528, 12,063, 14,510\\",\\"Jumper - offwhite, Sweatshirt - navy, Cardigan - offwhite multicolor, Shirt - grey multicolor\\",\\"Jumper - offwhite, Sweatshirt - navy, Cardigan - offwhite multicolor, Shirt - grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0297802978, ZO0456704567, ZO0572105721, ZO0280502805\\",\\"0, 0, 0, 0\\",\\"28.984, 20.984, 20.984, 33\\",\\"28.984, 20.984, 20.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0297802978, ZO0456704567, ZO0572105721, ZO0280502805\\",\\"103.938\\",\\"103.938\\",4,4,order,abd +zQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Thad,Thad,\\"Thad Carr\\",\\"Thad Carr\\",MALE,30,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"thad@carr-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568325,\\"sold_product_568325_11553, sold_product_568325_17851\\",\\"sold_product_568325_11553, sold_product_568325_17851\\",\\"140, 50\\",\\"140, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"72.813, 25.984\\",\\"140, 50\\",\\"11,553, 17,851\\",\\"Leather jacket - camel, Casual lace-ups - dark blue\\",\\"Leather jacket - camel, Casual lace-ups - dark blue\\",\\"1, 1\\",\\"ZO0288202882, ZO0391803918\\",\\"0, 0\\",\\"140, 50\\",\\"140, 50\\",\\"0, 0\\",\\"ZO0288202882, ZO0391803918\\",190,190,2,2,order,thad +zgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Cook\\",\\"Wagdi Cook\\",MALE,15,Cook,Cook,\\"(empty)\\",Wednesday,2,\\"wagdi@cook-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568360,\\"sold_product_568360_13315, sold_product_568360_18355\\",\\"sold_product_568360_13315, sold_product_568360_18355\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"5.398, 32.5\\",\\"11.992, 65\\",\\"13,315, 18,355\\",\\"5 PACK - Socks - blue/red/grey/green/black, Suit jacket - offwhite\\",\\"5 PACK - Socks - blue/red/grey/green/black, Suit jacket - offwhite\\",\\"1, 1\\",\\"ZO0480304803, ZO0274402744\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0480304803, ZO0274402744\\",77,77,2,2,order,wagdi +EAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Wednesday,2,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569278,\\"sold_product_569278_7811, sold_product_569278_19226\\",\\"sold_product_569278_7811, sold_product_569278_19226\\",\\"100, 18.984\\",\\"100, 18.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"48, 9.68\\",\\"100, 18.984\\",\\"7,811, 19,226\\",\\"Short coat - dark blue multicolor, Print T-shirt - black\\",\\"Short coat - dark blue multicolor, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0271802718, ZO0057100571\\",\\"0, 0\\",\\"100, 18.984\\",\\"100, 18.984\\",\\"0, 0\\",\\"ZO0271802718, ZO0057100571\\",119,119,2,2,order,brigitte +UgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Underwood\\",\\"Gwen Underwood\\",FEMALE,26,Underwood,Underwood,\\"(empty)\\",Wednesday,2,\\"gwen@underwood-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568816,\\"sold_product_568816_24602, sold_product_568816_21413\\",\\"sold_product_568816_24602, sold_product_568816_21413\\",\\"21.984, 37\\",\\"21.984, 37\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"12.094, 18.5\\",\\"21.984, 37\\",\\"24,602, 21,413\\",\\"Trousers - black, Jersey dress - black\\",\\"Trousers - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0146601466, ZO0108601086\\",\\"0, 0\\",\\"21.984, 37\\",\\"21.984, 37\\",\\"0, 0\\",\\"ZO0146601466, ZO0108601086\\",\\"58.969\\",\\"58.969\\",2,2,order,gwen +UwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Yuri,Yuri,\\"Yuri Carr\\",\\"Yuri Carr\\",MALE,21,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"yuri@carr-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568375,\\"sold_product_568375_11121, sold_product_568375_14185\\",\\"sold_product_568375_11121, sold_product_568375_14185\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"30.547, 11.75\\",\\"65, 24.984\\",\\"11,121, 14,185\\",\\"Winter jacket - black, Rucksack - washed black/black\\",\\"Winter jacket - black, Rucksack - washed black/black\\",\\"1, 1\\",\\"ZO0623606236, ZO0605306053\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0623606236, ZO0605306053\\",90,90,2,2,order,yuri +VAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Taylor\\",\\"Eddie Taylor\\",MALE,38,Taylor,Taylor,\\"(empty)\\",Wednesday,2,\\"eddie@taylor-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568559,\\"sold_product_568559_17305, sold_product_568559_15031\\",\\"sold_product_568559_17305, sold_product_568559_15031\\",\\"11.992, 33\\",\\"11.992, 33\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"6.109, 16.813\\",\\"11.992, 33\\",\\"17,305, 15,031\\",\\"Belt - black, Wool - black\\",\\"Belt - black, Wool - black\\",\\"1, 1\\",\\"ZO0599005990, ZO0626506265\\",\\"0, 0\\",\\"11.992, 33\\",\\"11.992, 33\\",\\"0, 0\\",\\"ZO0599005990, ZO0626506265\\",\\"44.969\\",\\"44.969\\",2,2,order,eddie +VQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Pia,Pia,\\"Pia Valdez\\",\\"Pia Valdez\\",FEMALE,45,Valdez,Valdez,\\"(empty)\\",Wednesday,2,\\"pia@valdez-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568611,\\"sold_product_568611_12564, sold_product_568611_12268\\",\\"sold_product_568611_12564, sold_product_568611_12268\\",\\"38, 42\\",\\"38, 42\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"17.484, 19.734\\",\\"38, 42\\",\\"12,564, 12,268\\",\\"Short coat - black, Tote bag - light brown\\",\\"Short coat - black, Tote bag - light brown\\",\\"1, 1\\",\\"ZO0174701747, ZO0305103051\\",\\"0, 0\\",\\"38, 42\\",\\"38, 42\\",\\"0, 0\\",\\"ZO0174701747, ZO0305103051\\",80,80,2,2,order,pia +VgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jason,Jason,\\"Jason Hodges\\",\\"Jason Hodges\\",MALE,16,Hodges,Hodges,\\"(empty)\\",Wednesday,2,\\"jason@hodges-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568638,\\"sold_product_568638_18188, sold_product_568638_6975\\",\\"sold_product_568638_18188, sold_product_568638_6975\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"17.484, 8.742\\",\\"33, 18.984\\",\\"18,188, 6,975\\",\\"Smart lace-ups - cognac, Pyjama bottoms - green\\",\\"Smart lace-ups - cognac, Pyjama bottoms - green\\",\\"1, 1\\",\\"ZO0388003880, ZO0478304783\\",\\"0, 0\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"0, 0\\",\\"ZO0388003880, ZO0478304783\\",\\"51.969\\",\\"51.969\\",2,2,order,jason +VwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Hampton\\",\\"Mary Hampton\\",FEMALE,20,Hampton,Hampton,\\"(empty)\\",Wednesday,2,\\"mary@hampton-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568706,\\"sold_product_568706_15826, sold_product_568706_11255\\",\\"sold_product_568706_15826, sold_product_568706_11255\\",\\"110, 50\\",\\"110, 50\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"55, 25.984\\",\\"110, 50\\",\\"15,826, 11,255\\",\\"Over-the-knee boots - black, Jersey dress - dark navy and white\\",\\"Over-the-knee boots - black, Jersey dress - dark navy and white\\",\\"1, 1\\",\\"ZO0672206722, ZO0331903319\\",\\"0, 0\\",\\"110, 50\\",\\"110, 50\\",\\"0, 0\\",\\"ZO0672206722, ZO0331903319\\",160,160,2,2,order,mary +mgMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Banks\\",\\"Tariq Banks\\",MALE,25,Banks,Banks,\\"(empty)\\",Wednesday,2,\\"tariq@banks-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, (empty), Low Tide Media\\",\\"Elitelligence, (empty), Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",716889,\\"sold_product_716889_21293, sold_product_716889_12288, sold_product_716889_22189, sold_product_716889_19058\\",\\"sold_product_716889_21293, sold_product_716889_12288, sold_product_716889_22189, sold_product_716889_19058\\",\\"24.984, 155, 10.992, 16.984\\",\\"24.984, 155, 10.992, 16.984\\",\\"Men's Shoes, Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Men's Shoes, Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, (empty), Elitelligence, Low Tide Media\\",\\"Elitelligence, (empty), Elitelligence, Low Tide Media\\",\\"12.742, 71.313, 5.82, 7.648\\",\\"24.984, 155, 10.992, 16.984\\",\\"21,293, 12,288, 22,189, 19,058\\",\\"Trainers - white, Smart slip-ons - brown, Wallet - black, Jumper - dark grey multicolor\\",\\"Trainers - white, Smart slip-ons - brown, Wallet - black, Jumper - dark grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\",\\"0, 0, 0, 0\\",\\"24.984, 155, 10.992, 16.984\\",\\"24.984, 155, 10.992, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\",208,208,4,4,order,tariq +1wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Butler\\",\\"Rabbia Al Butler\\",FEMALE,5,Butler,Butler,\\"(empty)\\",Wednesday,2,\\"rabbia al@butler-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Pyramidustries, Champion Arts, Tigress Enterprises\\",\\"Pyramidustries, Champion Arts, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",728580,\\"sold_product_728580_12102, sold_product_728580_24113, sold_product_728580_22614, sold_product_728580_19229\\",\\"sold_product_728580_12102, sold_product_728580_24113, sold_product_728580_22614, sold_product_728580_19229\\",\\"10.992, 33, 28.984, 16.984\\",\\"10.992, 33, 28.984, 16.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Champion Arts, Tigress Enterprises, Tigress Enterprises\\",\\"Pyramidustries, Champion Arts, Tigress Enterprises, Tigress Enterprises\\",\\"5.059, 15.508, 13.633, 7.988\\",\\"10.992, 33, 28.984, 16.984\\",\\"12,102, 24,113, 22,614, 19,229\\",\\"Vest - white, Cardigan - dark blue/off-white, Cardigan - black, Clutch - black\\",\\"Vest - white, Cardigan - dark blue/off-white, Cardigan - black, Clutch - black\\",\\"1, 1, 1, 1\\",\\"ZO0156601566, ZO0498004980, ZO0070700707, ZO0086700867\\",\\"0, 0, 0, 0\\",\\"10.992, 33, 28.984, 16.984\\",\\"10.992, 33, 28.984, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0156601566, ZO0498004980, ZO0070700707, ZO0086700867\\",\\"89.938\\",\\"89.938\\",4,4,order,rabbia +3wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane King\\",\\"Diane King\\",FEMALE,22,King,King,\\"(empty)\\",Wednesday,2,\\"diane@king-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568762,\\"sold_product_568762_22428, sold_product_568762_9391\\",\\"sold_product_568762_22428, sold_product_568762_9391\\",\\"37, 33\\",\\"37, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"17.391, 17.484\\",\\"37, 33\\",\\"22,428, 9,391\\",\\"Jersey dress - royal blue, Shirt - white\\",\\"Jersey dress - royal blue, Shirt - white\\",\\"1, 1\\",\\"ZO0052200522, ZO0265602656\\",\\"0, 0\\",\\"37, 33\\",\\"37, 33\\",\\"0, 0\\",\\"ZO0052200522, ZO0265602656\\",70,70,2,2,order,diane +6QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Graves\\",\\"Abigail Graves\\",FEMALE,46,Graves,Graves,\\"(empty)\\",Wednesday,2,\\"abigail@graves-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568571,\\"sold_product_568571_23698, sold_product_568571_23882\\",\\"sold_product_568571_23698, sold_product_568571_23882\\",\\"33, 33\\",\\"33, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"17.156, 16.813\\",\\"33, 33\\",\\"23,698, 23,882\\",\\"Pleated skirt - black, Long sleeved top - chinese red\\",\\"Pleated skirt - black, Long sleeved top - chinese red\\",\\"1, 1\\",\\"ZO0034100341, ZO0343103431\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0034100341, ZO0343103431\\",66,66,2,2,order,abigail +6gMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Hale\\",\\"Diane Hale\\",FEMALE,22,Hale,Hale,\\"(empty)\\",Wednesday,2,\\"diane@hale-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords, Pyramidustries active\\",\\"Spherecords, Pyramidustries active\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568671,\\"sold_product_568671_18674, sold_product_568671_9937\\",\\"sold_product_568671_18674, sold_product_568671_9937\\",\\"5.988, 11.992\\",\\"5.988, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries active\\",\\"Spherecords, Pyramidustries active\\",\\"2.76, 6.352\\",\\"5.988, 11.992\\",\\"18,674, 9,937\\",\\"Vest - white, Sports shirt - black \\",\\"Vest - white, Sports shirt - black \\",\\"1, 1\\",\\"ZO0637406374, ZO0219002190\\",\\"0, 0\\",\\"5.988, 11.992\\",\\"5.988, 11.992\\",\\"0, 0\\",\\"ZO0637406374, ZO0219002190\\",\\"17.984\\",\\"17.984\\",2,2,order,diane +9AMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Summers\\",\\"Elyssa Summers\\",FEMALE,27,Summers,Summers,\\"(empty)\\",Wednesday,2,\\"elyssa@summers-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568774,\\"sold_product_568774_24937, sold_product_568774_24748\\",\\"sold_product_568774_24937, sold_product_568774_24748\\",\\"34, 60\\",\\"34, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"17, 33\\",\\"34, 60\\",\\"24,937, 24,748\\",\\"Jersey dress - dark green, Lace-ups - bianco\\",\\"Jersey dress - dark green, Lace-ups - bianco\\",\\"1, 1\\",\\"ZO0037200372, ZO0369303693\\",\\"0, 0\\",\\"34, 60\\",\\"34, 60\\",\\"0, 0\\",\\"ZO0037200372, ZO0369303693\\",94,94,2,2,order,elyssa +9QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Summers\\",\\"Jackson Summers\\",MALE,13,Summers,Summers,\\"(empty)\\",Wednesday,2,\\"jackson@summers-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568319,\\"sold_product_568319_16715, sold_product_568319_24934\\",\\"sold_product_568319_16715, sold_product_568319_24934\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"14.492, 22.5\\",\\"28.984, 50\\",\\"16,715, 24,934\\",\\"Slim fit jeans - black, Lace-up boots - resin coffee\\",\\"Slim fit jeans - black, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0535105351, ZO0403504035\\",\\"0, 0\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"0, 0\\",\\"ZO0535105351, ZO0403504035\\",79,79,2,2,order,jackson +9gMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Gregory\\",\\"Sultan Al Gregory\\",MALE,19,Gregory,Gregory,\\"(empty)\\",Wednesday,2,\\"sultan al@gregory-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568363,\\"sold_product_568363_19188, sold_product_568363_14507\\",\\"sold_product_568363_19188, sold_product_568363_14507\\",\\"20.984, 115\\",\\"20.984, 115\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"9.453, 59.781\\",\\"20.984, 115\\",\\"19,188, 14,507\\",\\"Swimming shorts - dark grey , Weekend bag - black\\",\\"Swimming shorts - dark grey , Weekend bag - black\\",\\"1, 1\\",\\"ZO0629806298, ZO0467104671\\",\\"0, 0\\",\\"20.984, 115\\",\\"20.984, 115\\",\\"0, 0\\",\\"ZO0629806298, ZO0467104671\\",136,136,2,2,order,sultan +9wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Garner\\",\\"Thad Garner\\",MALE,30,Garner,Garner,\\"(empty)\\",Wednesday,2,\\"thad@garner-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568541,\\"sold_product_568541_14083, sold_product_568541_11234\\",\\"sold_product_568541_14083, sold_product_568541_11234\\",\\"75, 42\\",\\"75, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"35.25, 21.828\\",\\"75, 42\\",\\"14,083, 11,234\\",\\"Light jacket - dark blue, Tracksuit top - black\\",\\"Light jacket - dark blue, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0428904289, ZO0588205882\\",\\"0, 0\\",\\"75, 42\\",\\"75, 42\\",\\"0, 0\\",\\"ZO0428904289, ZO0588205882\\",117,117,2,2,order,thad +\\"-AMtOW0BH63Xcmy46HLV\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Simmons\\",\\"Selena Simmons\\",FEMALE,42,Simmons,Simmons,\\"(empty)\\",Wednesday,2,\\"selena@simmons-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568586,\\"sold_product_568586_14747, sold_product_568586_15677\\",\\"sold_product_568586_14747, sold_product_568586_15677\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"16.5, 8.742\\",\\"33, 18.984\\",\\"14,747, 15,677\\",\\"Blouse - pomegranate, Across body bag - black\\",\\"Blouse - pomegranate, Across body bag - black\\",\\"1, 1\\",\\"ZO0232202322, ZO0208402084\\",\\"0, 0\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"0, 0\\",\\"ZO0232202322, ZO0208402084\\",\\"51.969\\",\\"51.969\\",2,2,order,selena +\\"-QMtOW0BH63Xcmy46HLV\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Carr\\",\\"Gwen Carr\\",FEMALE,26,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"gwen@carr-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Champion Arts, (empty)\\",\\"Champion Arts, (empty)\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568636,\\"sold_product_568636_17497, sold_product_568636_11982\\",\\"sold_product_568636_17497, sold_product_568636_11982\\",\\"42, 50\\",\\"42, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, (empty)\\",\\"Champion Arts, (empty)\\",\\"23.094, 22.5\\",\\"42, 50\\",\\"17,497, 11,982\\",\\"Winter jacket - navy, Blazer - white\\",\\"Winter jacket - navy, Blazer - white\\",\\"1, 1\\",\\"ZO0503905039, ZO0631806318\\",\\"0, 0\\",\\"42, 50\\",\\"42, 50\\",\\"0, 0\\",\\"ZO0503905039, ZO0631806318\\",92,92,2,2,order,gwen +\\"-gMtOW0BH63Xcmy46HLV\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Rice\\",\\"Diane Rice\\",FEMALE,22,Rice,Rice,\\"(empty)\\",Wednesday,2,\\"diane@rice-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568674,\\"sold_product_568674_16704, sold_product_568674_16971\\",\\"sold_product_568674_16704, sold_product_568674_16971\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"5.711, 13.922\\",\\"10.992, 28.984\\",\\"16,704, 16,971\\",\\"Scarf - black/white, High heeled sandals - black\\",\\"Scarf - black/white, High heeled sandals - black\\",\\"1, 1\\",\\"ZO0192301923, ZO0011400114\\",\\"0, 0\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"0, 0\\",\\"ZO0192301923, ZO0011400114\\",\\"39.969\\",\\"39.969\\",2,2,order,diane +NwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Lambert\\",\\"Mostafa Lambert\\",MALE,9,Lambert,Lambert,\\"(empty)\\",Tuesday,1,\\"mostafa@lambert-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567868,\\"sold_product_567868_15827, sold_product_567868_6221\\",\\"sold_product_567868_15827, sold_product_567868_6221\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"9.867, 15.07\\",\\"20.984, 28.984\\",\\"15,827, 6,221\\",\\"Belt - black/brown, Shirt - dark blue\\",\\"Belt - black/brown, Shirt - dark blue\\",\\"1, 1\\",\\"ZO0310403104, ZO0416604166\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0310403104, ZO0416604166\\",\\"49.969\\",\\"49.969\\",2,2,order,mostafa +SgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Selena,Selena,\\"Selena Lewis\\",\\"Selena Lewis\\",FEMALE,42,Lewis,Lewis,\\"(empty)\\",Tuesday,1,\\"selena@lewis-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567446,\\"sold_product_567446_12751, sold_product_567446_12494\\",\\"sold_product_567446_12751, sold_product_567446_12494\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"31.844, 11.25\\",\\"65, 24.984\\",\\"12,751, 12,494\\",\\"Lace-ups - black, Classic heels - cognac/beige\\",\\"Lace-ups - black, Classic heels - cognac/beige\\",\\"1, 1\\",\\"ZO0322803228, ZO0002700027\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0322803228, ZO0002700027\\",90,90,2,2,order,selena +bwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Oliver,Oliver,\\"Oliver Martin\\",\\"Oliver Martin\\",MALE,7,Martin,Martin,\\"(empty)\\",Tuesday,1,\\"oliver@martin-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567340,\\"sold_product_567340_3840, sold_product_567340_14835\\",\\"sold_product_567340_3840, sold_product_567340_14835\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"7.82, 21.406\\",\\"16.984, 42\\",\\"3,840, 14,835\\",\\"Sports shirt - dark grey multicolor, High-top trainers - grey\\",\\"Sports shirt - dark grey multicolor, High-top trainers - grey\\",\\"1, 1\\",\\"ZO0615606156, ZO0514905149\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0615606156, ZO0514905149\\",\\"58.969\\",\\"58.969\\",2,2,order,oliver +5AMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Salazar\\",\\"Kamal Salazar\\",MALE,39,Salazar,Salazar,\\"(empty)\\",Tuesday,1,\\"kamal@salazar-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Spherecords, Spritechnologies\\",\\"Spherecords, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567736,\\"sold_product_567736_24718, sold_product_567736_24306\\",\\"sold_product_567736_24718, sold_product_567736_24306\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spritechnologies\\",\\"Spherecords, Spritechnologies\\",\\"6.109, 36.75\\",\\"11.992, 75\\",\\"24,718, 24,306\\",\\"Pyjama bottoms - light grey multicolor, Waterproof trousers - scarlet\\",\\"Pyjama bottoms - light grey multicolor, Waterproof trousers - scarlet\\",\\"1, 1\\",\\"ZO0663706637, ZO0620906209\\",\\"0, 0\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"0, 0\\",\\"ZO0663706637, ZO0620906209\\",87,87,2,2,order,kamal +EQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Fleming\\",\\"Kamal Fleming\\",MALE,39,Fleming,Fleming,\\"(empty)\\",Tuesday,1,\\"kamal@fleming-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567755,\\"sold_product_567755_16941, sold_product_567755_1820\\",\\"sold_product_567755_16941, sold_product_567755_1820\\",\\"16.984, 75\\",\\"16.984, 75\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"8.492, 36.75\\",\\"16.984, 75\\",\\"16,941, 1,820\\",\\"Vibrant Pattern Polo, Smart slip-ons - oro\\",\\"Vibrant Pattern Polo, Smart slip-ons - oro\\",\\"1, 1\\",\\"ZO0571405714, ZO0255402554\\",\\"0, 0\\",\\"16.984, 75\\",\\"16.984, 75\\",\\"0, 0\\",\\"ZO0571405714, ZO0255402554\\",92,92,2,2,order,kamal +OQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Meyer\\",\\"Sultan Al Meyer\\",MALE,19,Meyer,Meyer,\\"(empty)\\",Tuesday,1,\\"sultan al@meyer-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence, Microlutions\\",\\"Low Tide Media, Elitelligence, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",715455,\\"sold_product_715455_11902, sold_product_715455_19957, sold_product_715455_17361, sold_product_715455_12368\\",\\"sold_product_715455_11902, sold_product_715455_19957, sold_product_715455_17361, sold_product_715455_12368\\",\\"13.992, 7.988, 28.984, 33\\",\\"13.992, 7.988, 28.984, 33\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, Elitelligence, Microlutions\\",\\"Low Tide Media, Elitelligence, Elitelligence, Microlutions\\",\\"7.551, 4.07, 14.211, 17.156\\",\\"13.992, 7.988, 28.984, 33\\",\\"11,902, 19,957, 17,361, 12,368\\",\\"3 PACK - Shorts - black, 3 PACK - Socks - black/grey/orange, Sweatshirt - multicoloured, Shirt - dark green\\",\\"3 PACK - Shorts - black, 3 PACK - Socks - black/grey/orange, Sweatshirt - multicoloured, Shirt - dark green\\",\\"1, 1, 1, 1\\",\\"ZO0477504775, ZO0613206132, ZO0585405854, ZO0110701107\\",\\"0, 0, 0, 0\\",\\"13.992, 7.988, 28.984, 33\\",\\"13.992, 7.988, 28.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0477504775, ZO0613206132, ZO0585405854, ZO0110701107\\",\\"83.938\\",\\"83.938\\",4,4,order,sultan +ggMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Holland\\",\\"Clarice Holland\\",FEMALE,18,Holland,Holland,\\"(empty)\\",Tuesday,1,\\"clarice@holland-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566768,\\"sold_product_566768_12004, sold_product_566768_23314\\",\\"sold_product_566768_12004, sold_product_566768_23314\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"8.656, 25.984\\",\\"16.984, 50\\",\\"12,004, 23,314\\",\\"Zelda - Long sleeved top - black, A-line skirt - navy blazer\\",\\"Zelda - Long sleeved top - black, A-line skirt - navy blazer\\",\\"1, 1\\",\\"ZO0217702177, ZO0331703317\\",\\"0, 0\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"0, 0\\",\\"ZO0217702177, ZO0331703317\\",67,67,2,2,order,clarice +gwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Boone\\",\\"Pia Boone\\",FEMALE,45,Boone,Boone,\\"(empty)\\",Tuesday,1,\\"pia@boone-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",Oceanavigations,Oceanavigations,\\"Jun 24, 2019 @ 00:00:00.000\\",566812,\\"sold_product_566812_19012, sold_product_566812_5941\\",\\"sold_product_566812_19012, sold_product_566812_5941\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"9.453, 41.656\\",\\"20.984, 85\\",\\"19,012, 5,941\\",\\"Vest - black/rose, Boots - tan\\",\\"Vest - black/rose, Boots - tan\\",\\"1, 1\\",\\"ZO0266902669, ZO0244202442\\",\\"0, 0\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"0, 0\\",\\"ZO0266902669, ZO0244202442\\",106,106,2,2,order,pia +jgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Mostafa,Mostafa,\\"Mostafa Underwood\\",\\"Mostafa Underwood\\",MALE,9,Underwood,Underwood,\\"(empty)\\",Tuesday,1,\\"mostafa@underwood-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566680,\\"sold_product_566680_15413, sold_product_566680_16394\\",\\"sold_product_566680_15413, sold_product_566680_16394\\",\\"33, 42\\",\\"33, 42\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"16.172, 20.156\\",\\"33, 42\\",\\"15,413, 16,394\\",\\"Laptop bag - brown, Lace-ups - black\\",\\"Laptop bag - brown, Lace-ups - black\\",\\"1, 1\\",\\"ZO0316703167, ZO0393303933\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0316703167, ZO0393303933\\",75,75,2,2,order,mostafa +jwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Larson\\",\\"Yasmine Larson\\",FEMALE,43,Larson,Larson,\\"(empty)\\",Tuesday,1,\\"yasmine@larson-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566944,\\"sold_product_566944_13250, sold_product_566944_13079\\",\\"sold_product_566944_13250, sold_product_566944_13079\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"13.742, 8.828\\",\\"24.984, 16.984\\",\\"13,250, 13,079\\",\\"Jumper - black/white, Print T-shirt - black\\",\\"Jumper - black/white, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0497004970, ZO0054900549\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0497004970, ZO0054900549\\",\\"41.969\\",\\"41.969\\",2,2,order,yasmine +kAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Palmer\\",\\"Clarice Palmer\\",FEMALE,18,Palmer,Palmer,\\"(empty)\\",Tuesday,1,\\"clarice@palmer-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566979,\\"sold_product_566979_19260, sold_product_566979_21565\\",\\"sold_product_566979_19260, sold_product_566979_21565\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"17.156, 5.281\\",\\"33, 10.992\\",\\"19,260, 21,565\\",\\"Cardigan - grey, Print T-shirt - dark grey multicolor\\",\\"Cardigan - grey, Print T-shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0071900719, ZO0493404934\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0071900719, ZO0493404934\\",\\"43.969\\",\\"43.969\\",2,2,order,clarice +kQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Duncan\\",\\"Fitzgerald Duncan\\",MALE,11,Duncan,Duncan,\\"(empty)\\",Tuesday,1,\\"fitzgerald@duncan-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566734,\\"sold_product_566734_17263, sold_product_566734_13452\\",\\"sold_product_566734_17263, sold_product_566734_13452\\",\\"75, 42\\",\\"75, 42\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"40.5, 20.578\\",\\"75, 42\\",\\"17,263, 13,452\\",\\"Lace-up boots - cognac, Weekend bag - black\\",\\"Lace-up boots - cognac, Weekend bag - black\\",\\"1, 1\\",\\"ZO0691006910, ZO0314203142\\",\\"0, 0\\",\\"75, 42\\",\\"75, 42\\",\\"0, 0\\",\\"ZO0691006910, ZO0314203142\\",117,117,2,2,order,fuzzy +kgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Howell\\",\\"Abdulraheem Al Howell\\",MALE,33,Howell,Howell,\\"(empty)\\",Tuesday,1,\\"abdulraheem al@howell-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567094,\\"sold_product_567094_12311, sold_product_567094_12182\\",\\"sold_product_567094_12311, sold_product_567094_12182\\",\\"16.984, 12.992\\",\\"16.984, 12.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"8.656, 7.141\\",\\"16.984, 12.992\\",\\"12,311, 12,182\\",\\"Polo shirt - white, Swimming shorts - black\\",\\"Polo shirt - white, Swimming shorts - black\\",\\"1, 1\\",\\"ZO0442904429, ZO0629706297\\",\\"0, 0\\",\\"16.984, 12.992\\",\\"16.984, 12.992\\",\\"0, 0\\",\\"ZO0442904429, ZO0629706297\\",\\"29.984\\",\\"29.984\\",2,2,order,abdulraheem +kwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie King\\",\\"Eddie King\\",MALE,38,King,King,\\"(empty)\\",Tuesday,1,\\"eddie@king-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",566892,\\"sold_product_566892_21978, sold_product_566892_14543\\",\\"sold_product_566892_21978, sold_product_566892_14543\\",\\"24.984, 17.984\\",\\"24.984, 17.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"12.492, 8.992\\",\\"24.984, 17.984\\",\\"21,978, 14,543\\",\\"Hoodie - dark blue, Jumper - black\\",\\"Hoodie - dark blue, Jumper - black\\",\\"1, 1\\",\\"ZO0589505895, ZO0575405754\\",\\"0, 0\\",\\"24.984, 17.984\\",\\"24.984, 17.984\\",\\"0, 0\\",\\"ZO0589505895, ZO0575405754\\",\\"42.969\\",\\"42.969\\",2,2,order,eddie +tQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Morgan\\",\\"Sultan Al Morgan\\",MALE,19,Morgan,Morgan,\\"(empty)\\",Tuesday,1,\\"sultan al@morgan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567950,\\"sold_product_567950_24164, sold_product_567950_11096\\",\\"sold_product_567950_24164, sold_product_567950_11096\\",\\"110, 42\\",\\"110, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"52.813, 20.156\\",\\"110, 42\\",\\"24,164, 11,096\\",\\"Suit - dark blue, Bomber Jacket - black\\",\\"Suit - dark blue, Bomber Jacket - black\\",\\"1, 1\\",\\"ZO0273002730, ZO0541105411\\",\\"0, 0\\",\\"110, 42\\",\\"110, 42\\",\\"0, 0\\",\\"ZO0273002730, ZO0541105411\\",152,152,2,2,order,sultan +uAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Rose\\",\\"Sultan Al Rose\\",MALE,19,Rose,Rose,\\"(empty)\\",Tuesday,1,\\"sultan al@rose-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",566826,\\"sold_product_566826_15908, sold_product_566826_13927\\",\\"sold_product_566826_15908, sold_product_566826_13927\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9.172, 21.406\\",\\"16.984, 42\\",\\"15,908, 13,927\\",\\"Jumper - camel, Bomber Jacket - khaki\\",\\"Jumper - camel, Bomber Jacket - khaki\\",\\"1, 1\\",\\"ZO0575305753, ZO0540605406\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0575305753, ZO0540605406\\",\\"58.969\\",\\"58.969\\",2,2,order,sultan +fQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Franklin\\",\\"Fitzgerald Franklin\\",MALE,11,Franklin,Franklin,\\"(empty)\\",Tuesday,1,\\"fitzgerald@franklin-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567240,\\"sold_product_567240_23744, sold_product_567240_2098\\",\\"sold_product_567240_23744, sold_product_567240_2098\\",\\"31.984, 80\\",\\"31.984, 80\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"15.68, 41.594\\",\\"31.984, 80\\",\\"23,744, 2,098\\",\\"Chinos - dark blue, Lace-up boots - black\\",\\"Chinos - dark blue, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0421004210, ZO0689006890\\",\\"0, 0\\",\\"31.984, 80\\",\\"31.984, 80\\",\\"0, 0\\",\\"ZO0421004210, ZO0689006890\\",112,112,2,2,order,fuzzy +fgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Byrd\\",\\"Mostafa Byrd\\",MALE,9,Byrd,Byrd,\\"(empty)\\",Tuesday,1,\\"mostafa@byrd-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567290,\\"sold_product_567290_24934, sold_product_567290_15288\\",\\"sold_product_567290_24934, sold_product_567290_15288\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"22.5, 11.211\\",\\"50, 21.984\\",\\"24,934, 15,288\\",\\"Lace-up boots - resin coffee, Polo shirt - grey\\",\\"Lace-up boots - resin coffee, Polo shirt - grey\\",\\"1, 1\\",\\"ZO0403504035, ZO0442704427\\",\\"0, 0\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"0, 0\\",\\"ZO0403504035, ZO0442704427\\",72,72,2,2,order,mostafa +kAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,rania,rania,\\"rania Goodwin\\",\\"rania Goodwin\\",FEMALE,24,Goodwin,Goodwin,\\"(empty)\\",Tuesday,1,\\"rania@goodwin-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",567669,\\"sold_product_567669_22893, sold_product_567669_17796\\",\\"sold_product_567669_22893, sold_product_567669_17796\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"8.156, 9.344\\",\\"16.984, 16.984\\",\\"22,893, 17,796\\",\\"A-line skirt - dark purple, Across body bag - black \\",\\"A-line skirt - dark purple, Across body bag - black \\",\\"1, 1\\",\\"ZO0148301483, ZO0202902029\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0148301483, ZO0202902029\\",\\"33.969\\",\\"33.969\\",2,2,order,rani +rgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Simpson\\",\\"Gwen Simpson\\",FEMALE,26,Simpson,Simpson,\\"(empty)\\",Tuesday,1,\\"gwen@simpson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567365,\\"sold_product_567365_11663, sold_product_567365_24272\\",\\"sold_product_567365_11663, sold_product_567365_24272\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"5.879, 18.125\\",\\"11.992, 37\\",\\"11,663, 24,272\\",\\"Slip-ons - white, Shirt - white\\",\\"Slip-ons - white, Shirt - white\\",\\"1, 1\\",\\"ZO0008600086, ZO0266002660\\",\\"0, 0\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"0, 0\\",\\"ZO0008600086, ZO0266002660\\",\\"48.969\\",\\"48.969\\",2,2,order,gwen +1AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Sanders\\",\\"George Sanders\\",MALE,32,Sanders,Sanders,\\"(empty)\\",Tuesday,1,\\"george@sanders-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",566845,\\"sold_product_566845_24161, sold_product_566845_13674\\",\\"sold_product_566845_24161, sold_product_566845_13674\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"3.92, 12.25\\",\\"7.988, 24.984\\",\\"24,161, 13,674\\",\\"Basic T-shirt - white, Hoodie - black\\",\\"Basic T-shirt - white, Hoodie - black\\",\\"1, 1\\",\\"ZO0547905479, ZO0583305833\\",\\"0, 0\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"0, 0\\",\\"ZO0547905479, ZO0583305833\\",\\"32.969\\",\\"32.969\\",2,2,order,george +1QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Fletcher\\",\\"Jim Fletcher\\",MALE,41,Fletcher,Fletcher,\\"(empty)\\",Tuesday,1,\\"jim@fletcher-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567048,\\"sold_product_567048_19089, sold_product_567048_20261\\",\\"sold_product_567048_19089, sold_product_567048_20261\\",\\"12.992, 11.992\\",\\"12.992, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"7.012, 5.52\\",\\"12.992, 11.992\\",\\"19,089, 20,261\\",\\"Vest - white/dark blue, Vest - black\\",\\"Vest - white/dark blue, Vest - black\\",\\"1, 1\\",\\"ZO0566905669, ZO0564005640\\",\\"0, 0\\",\\"12.992, 11.992\\",\\"12.992, 11.992\\",\\"0, 0\\",\\"ZO0566905669, ZO0564005640\\",\\"24.984\\",\\"24.984\\",2,2,order,jim +EQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Hudson\\",\\"Yasmine Hudson\\",FEMALE,43,Hudson,Hudson,\\"(empty)\\",Tuesday,1,\\"yasmine@hudson-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries active, Spherecords\\",\\"Pyramidustries active, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567281,\\"sold_product_567281_14758, sold_product_567281_23174\\",\\"sold_product_567281_14758, sold_product_567281_23174\\",\\"13.992, 22.984\\",\\"13.992, 22.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Spherecords\\",\\"Pyramidustries active, Spherecords\\",\\"7.27, 12.18\\",\\"13.992, 22.984\\",\\"14,758, 23,174\\",\\"Print T-shirt - black, Chinos - dark blue\\",\\"Print T-shirt - black, Chinos - dark blue\\",\\"1, 1\\",\\"ZO0221402214, ZO0632806328\\",\\"0, 0\\",\\"13.992, 22.984\\",\\"13.992, 22.984\\",\\"0, 0\\",\\"ZO0221402214, ZO0632806328\\",\\"36.969\\",\\"36.969\\",2,2,order,yasmine +FAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Chapman\\",\\"rania Chapman\\",FEMALE,24,Chapman,Chapman,\\"(empty)\\",Tuesday,1,\\"rania@chapman-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Spherecords Curvy, Gnomehouse\\",\\"Spherecords Curvy, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567119,\\"sold_product_567119_22695, sold_product_567119_23515\\",\\"sold_product_567119_22695, sold_product_567119_23515\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Gnomehouse\\",\\"Spherecords Curvy, Gnomehouse\\",\\"7.82, 27.594\\",\\"16.984, 60\\",\\"22,695, 23,515\\",\\"Cardigan - grey multicolor/black, Blazer - black/white\\",\\"Cardigan - grey multicolor/black, Blazer - black/white\\",\\"1, 1\\",\\"ZO0711507115, ZO0350903509\\",\\"0, 0\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"0, 0\\",\\"ZO0711507115, ZO0350903509\\",77,77,2,2,order,rani +FQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Harper\\",\\"Samir Harper\\",MALE,34,Harper,Harper,\\"(empty)\\",Tuesday,1,\\"samir@harper-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567169,\\"sold_product_567169_20800, sold_product_567169_18749\\",\\"sold_product_567169_20800, sold_product_567169_18749\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"5.602, 9.344\\",\\"10.992, 16.984\\",\\"20,800, 18,749\\",\\"Print T-shirt - white, Sports shorts - black\\",\\"Print T-shirt - white, Sports shorts - black\\",\\"1, 1\\",\\"ZO0558805588, ZO0622206222\\",\\"0, 0\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"0, 0\\",\\"ZO0558805588, ZO0622206222\\",\\"27.984\\",\\"27.984\\",2,2,order,samir +KAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Underwood\\",\\"Abd Underwood\\",MALE,52,Underwood,Underwood,\\"(empty)\\",Tuesday,1,\\"abd@underwood-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567869,\\"sold_product_567869_14147, sold_product_567869_16719\\",\\"sold_product_567869_14147, sold_product_567869_16719\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"8.656, 8.328\\",\\"16.984, 16.984\\",\\"14,147, 16,719\\",\\"Print T-shirt - black/green, Polo shirt - blue multicolor\\",\\"Print T-shirt - black/green, Polo shirt - blue multicolor\\",\\"1, 1\\",\\"ZO0565105651, ZO0443804438\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0565105651, ZO0443804438\\",\\"33.969\\",\\"33.969\\",2,2,order,abd +KQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Strickland\\",\\"Muniz Strickland\\",MALE,37,Strickland,Strickland,\\"(empty)\\",Tuesday,1,\\"muniz@strickland-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567909,\\"sold_product_567909_24768, sold_product_567909_11414\\",\\"sold_product_567909_24768, sold_product_567909_11414\\",\\"24.984, 18.984\\",\\"24.984, 18.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.25, 8.93\\",\\"24.984, 18.984\\",\\"24,768, 11,414\\",\\"SET - Gloves - dark grey multicolor, Sweatshirt - light blue\\",\\"SET - Gloves - dark grey multicolor, Sweatshirt - light blue\\",\\"1, 1\\",\\"ZO0609606096, ZO0588905889\\",\\"0, 0\\",\\"24.984, 18.984\\",\\"24.984, 18.984\\",\\"0, 0\\",\\"ZO0609606096, ZO0588905889\\",\\"43.969\\",\\"43.969\\",2,2,order,muniz +eQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Stokes\\",\\"Betty Stokes\\",FEMALE,44,Stokes,Stokes,\\"(empty)\\",Tuesday,1,\\"betty@stokes-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567524,\\"sold_product_567524_14033, sold_product_567524_24564\\",\\"sold_product_567524_14033, sold_product_567524_24564\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"10.906, 35.094\\",\\"20.984, 65\\",\\"14,033, 24,564\\",\\"Clutch - black , Ankle boots - cognac\\",\\"Clutch - black , Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0096300963, ZO0377403774\\",\\"0, 0\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"0, 0\\",\\"ZO0096300963, ZO0377403774\\",86,86,2,2,order,betty +egMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Turner\\",\\"Elyssa Turner\\",FEMALE,27,Turner,Turner,\\"(empty)\\",Tuesday,1,\\"elyssa@turner-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567565,\\"sold_product_567565_4684, sold_product_567565_18489\\",\\"sold_product_567565_4684, sold_product_567565_18489\\",\\"50, 60\\",\\"50, 60\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"23.5, 33\\",\\"50, 60\\",\\"4,684, 18,489\\",\\"Boots - black, Slip-ons - Midnight Blue\\",\\"Boots - black, Slip-ons - Midnight Blue\\",\\"1, 1\\",\\"ZO0015600156, ZO0323603236\\",\\"0, 0\\",\\"50, 60\\",\\"50, 60\\",\\"0, 0\\",\\"ZO0015600156, ZO0323603236\\",110,110,2,2,order,elyssa +nQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Powell\\",\\"Sonya Powell\\",FEMALE,28,Powell,Powell,\\"(empty)\\",Tuesday,1,\\"sonya@powell-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",567019,\\"sold_product_567019_14411, sold_product_567019_24149\\",\\"sold_product_567019_14411, sold_product_567019_24149\\",\\"28.984, 21.984\\",\\"28.984, 21.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"13.344, 10.344\\",\\"28.984, 21.984\\",\\"14,411, 24,149\\",\\"Summer dress - black, Rucksack - black\\",\\"Summer dress - black, Rucksack - black\\",\\"1, 1\\",\\"ZO0151301513, ZO0204902049\\",\\"0, 0\\",\\"28.984, 21.984\\",\\"28.984, 21.984\\",\\"0, 0\\",\\"ZO0151301513, ZO0204902049\\",\\"50.969\\",\\"50.969\\",2,2,order,sonya +ngMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Massey\\",\\"Pia Massey\\",FEMALE,45,Massey,Massey,\\"(empty)\\",Tuesday,1,\\"pia@massey-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567069,\\"sold_product_567069_22261, sold_product_567069_16325\\",\\"sold_product_567069_22261, sold_product_567069_16325\\",\\"50, 33\\",\\"50, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"22.5, 17.156\\",\\"50, 33\\",\\"22,261, 16,325\\",\\"Winter jacket - bordeaux, Summer dress - black\\",\\"Winter jacket - bordeaux, Summer dress - black\\",\\"1, 1\\",\\"ZO0503805038, ZO0047500475\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0503805038, ZO0047500475\\",83,83,2,2,order,pia +qAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Frances,Frances,\\"Frances Lamb\\",\\"Frances Lamb\\",FEMALE,49,Lamb,Lamb,\\"(empty)\\",Tuesday,1,\\"frances@lamb-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567935,\\"sold_product_567935_13174, sold_product_567935_14395\\",\\"sold_product_567935_13174, sold_product_567935_14395\\",\\"14.992, 24.984\\",\\"14.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"7.789, 12.25\\",\\"14.992, 24.984\\",\\"13,174, 14,395\\",\\"Print T-shirt - bright white, Jumper - offwhite\\",\\"Print T-shirt - bright white, Jumper - offwhite\\",\\"1, 1\\",\\"ZO0116101161, ZO0574305743\\",\\"0, 0\\",\\"14.992, 24.984\\",\\"14.992, 24.984\\",\\"0, 0\\",\\"ZO0116101161, ZO0574305743\\",\\"39.969\\",\\"39.969\\",2,2,order,frances +qwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Jackson\\",\\"Betty Jackson\\",FEMALE,44,Jackson,Jackson,\\"(empty)\\",Tuesday,1,\\"betty@jackson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566831,\\"sold_product_566831_22424, sold_product_566831_17957\\",\\"sold_product_566831_22424, sold_product_566831_17957\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"23.5, 5.5\\",\\"50, 10.992\\",\\"22,424, 17,957\\",\\"Jersey dress - chinese red, Long sleeved top - black\\",\\"Jersey dress - chinese red, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0341103411, ZO0648406484\\",\\"0, 0\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"0, 0\\",\\"ZO0341103411, ZO0648406484\\",\\"60.969\\",\\"60.969\\",2,2,order,betty +5AMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Sharp\\",\\"Marwan Sharp\\",MALE,51,Sharp,Sharp,\\"(empty)\\",Tuesday,1,\\"marwan@sharp-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567543,\\"sold_product_567543_14075, sold_product_567543_20484\\",\\"sold_product_567543_14075, sold_product_567543_20484\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"12.742, 9.867\\",\\"24.984, 20.984\\",\\"14,075, 20,484\\",\\"Rucksack - black, Jumper - dark grey\\",\\"Rucksack - black, Jumper - dark grey\\",\\"1, 1\\",\\"ZO0608106081, ZO0296502965\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0608106081, ZO0296502965\\",\\"45.969\\",\\"45.969\\",2,2,order,marwan +5QMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Tran\\",\\"Gwen Tran\\",FEMALE,26,Tran,Tran,\\"(empty)\\",Tuesday,1,\\"gwen@tran-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567598,\\"sold_product_567598_11254, sold_product_567598_11666\\",\\"sold_product_567598_11254, sold_product_567598_11666\\",\\"29.984, 75\\",\\"29.984, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"14.398, 41.25\\",\\"29.984, 75\\",\\"11,254, 11,666\\",\\"Jersey dress - black, Boots - blue\\",\\"Jersey dress - black, Boots - blue\\",\\"1, 1\\",\\"ZO0039400394, ZO0672906729\\",\\"0, 0\\",\\"29.984, 75\\",\\"29.984, 75\\",\\"0, 0\\",\\"ZO0039400394, ZO0672906729\\",105,105,2,2,order,gwen +PwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Lloyd\\",\\"Wilhemina St. Lloyd\\",FEMALE,17,Lloyd,Lloyd,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@lloyd-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567876,\\"sold_product_567876_21798, sold_product_567876_24299\\",\\"sold_product_567876_21798, sold_product_567876_24299\\",\\"14.992, 42\\",\\"14.992, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"7.789, 19.313\\",\\"14.992, 42\\",\\"21,798, 24,299\\",\\"Jersey dress - black, Summer dress - black\\",\\"Jersey dress - black, Summer dress - black\\",\\"1, 1\\",\\"ZO0705707057, ZO0047700477\\",\\"0, 0\\",\\"14.992, 42\\",\\"14.992, 42\\",\\"0, 0\\",\\"ZO0705707057, ZO0047700477\\",\\"56.969\\",\\"56.969\\",2,2,order,wilhemina +UwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Jacobs\\",\\"Stephanie Jacobs\\",FEMALE,6,Jacobs,Jacobs,\\"(empty)\\",Tuesday,1,\\"stephanie@jacobs-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567684,\\"sold_product_567684_13627, sold_product_567684_21755\\",\\"sold_product_567684_13627, sold_product_567684_21755\\",\\"16.984, 20.984\\",\\"16.984, 20.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"9, 9.453\\",\\"16.984, 20.984\\",\\"13,627, 21,755\\",\\"Across body bag - black , Pencil skirt - black\\",\\"Across body bag - black , Pencil skirt - black\\",\\"1, 1\\",\\"ZO0201202012, ZO0035000350\\",\\"0, 0\\",\\"16.984, 20.984\\",\\"16.984, 20.984\\",\\"0, 0\\",\\"ZO0201202012, ZO0035000350\\",\\"37.969\\",\\"37.969\\",2,2,order,stephanie +aAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Oliver,Oliver,\\"Oliver Smith\\",\\"Oliver Smith\\",MALE,7,Smith,Smith,\\"(empty)\\",Tuesday,1,\\"oliver@smith-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567790,\\"sold_product_567790_13490, sold_product_567790_22013\\",\\"sold_product_567790_13490, sold_product_567790_22013\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.602, 29.406\\",\\"10.992, 60\\",\\"13,490, 22,013\\",\\"T-bar sandals - black/green, Boots - black\\",\\"T-bar sandals - black/green, Boots - black\\",\\"1, 1\\",\\"ZO0522405224, ZO0405104051\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0522405224, ZO0405104051\\",71,71,2,2,order,oliver +rAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,George,George,\\"George Hubbard\\",\\"George Hubbard\\",MALE,32,Hubbard,Hubbard,\\"(empty)\\",Tuesday,1,\\"george@hubbard-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567465,\\"sold_product_567465_19025, sold_product_567465_1753\\",\\"sold_product_567465_19025, sold_product_567465_1753\\",\\"65, 65\\",\\"65, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"31.844, 30.547\\",\\"65, 65\\",\\"19,025, 1,753\\",\\"Suit jacket - black, Boots - dark blue\\",\\"Suit jacket - black, Boots - dark blue\\",\\"1, 1\\",\\"ZO0274502745, ZO0686006860\\",\\"0, 0\\",\\"65, 65\\",\\"65, 65\\",\\"0, 0\\",\\"ZO0274502745, ZO0686006860\\",130,130,2,2,order,george +zwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Phil,Phil,\\"Phil Alvarez\\",\\"Phil Alvarez\\",MALE,50,Alvarez,Alvarez,\\"(empty)\\",Tuesday,1,\\"phil@alvarez-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567256,\\"sold_product_567256_24717, sold_product_567256_23939\\",\\"sold_product_567256_24717, sold_product_567256_23939\\",\\"14.992, 50\\",\\"14.992, 50\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"7.789, 24.5\\",\\"14.992, 50\\",\\"24,717, 23,939\\",\\"Belt - dark brown , Weekend bag - black\\",\\"Belt - dark brown , Weekend bag - black\\",\\"1, 1\\",\\"ZO0461004610, ZO0702707027\\",\\"0, 0\\",\\"14.992, 50\\",\\"14.992, 50\\",\\"0, 0\\",\\"ZO0461004610, ZO0702707027\\",65,65,2,2,order,phil +CwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Jackson,Jackson,\\"Jackson Bryant\\",\\"Jackson Bryant\\",MALE,13,Bryant,Bryant,\\"(empty)\\",Tuesday,1,\\"jackson@bryant-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media, Spritechnologies\\",\\"Elitelligence, Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",716462,\\"sold_product_716462_13612, sold_product_716462_21781, sold_product_716462_17754, sold_product_716462_17020\\",\\"sold_product_716462_13612, sold_product_716462_21781, sold_product_716462_17754, sold_product_716462_17020\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"Men's Clothing, Men's Clothing, Men's Accessories, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Low Tide Media, Elitelligence, Spritechnologies\\",\\"Elitelligence, Low Tide Media, Elitelligence, Spritechnologies\\",\\"6.469, 10.289, 5.059, 10.078\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"13,612, 21,781, 17,754, 17,020\\",\\"Basic T-shirt - light red/white, Sweatshirt - mottled light grey, Wallet - cognac/black, Sports shirt - grey multicolor\\",\\"Basic T-shirt - light red/white, Sweatshirt - mottled light grey, Wallet - cognac/black, Sports shirt - grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0549505495, ZO0458504585, ZO0602506025, ZO0617506175\\",\\"0, 0, 0, 0\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0549505495, ZO0458504585, ZO0602506025, ZO0617506175\\",\\"64.938\\",\\"64.938\\",4,4,order,jackson +GQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Elliott\\",\\"Abigail Elliott\\",FEMALE,46,Elliott,Elliott,\\"(empty)\\",Tuesday,1,\\"abigail@elliott-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Angeldale, Spherecords Maternity\\",\\"Angeldale, Spherecords Maternity\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566775,\\"sold_product_566775_7253, sold_product_566775_25143\\",\\"sold_product_566775_7253, sold_product_566775_25143\\",\\"110, 16.984\\",\\"110, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spherecords Maternity\\",\\"Angeldale, Spherecords Maternity\\",\\"53.906, 7.988\\",\\"110, 16.984\\",\\"7,253, 25,143\\",\\"Over-the-knee boots - bison, Long sleeved top - mid grey multicolor\\",\\"Over-the-knee boots - bison, Long sleeved top - mid grey multicolor\\",\\"1, 1\\",\\"ZO0671006710, ZO0708007080\\",\\"0, 0\\",\\"110, 16.984\\",\\"110, 16.984\\",\\"0, 0\\",\\"ZO0671006710, ZO0708007080\\",127,127,2,2,order,abigail +IQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Mccarthy\\",\\"Jason Mccarthy\\",MALE,16,Mccarthy,Mccarthy,\\"(empty)\\",Tuesday,1,\\"jason@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567926,\\"sold_product_567926_22732, sold_product_567926_11389\\",\\"sold_product_567926_22732, sold_product_567926_11389\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"16.172, 3.6\\",\\"33, 7.988\\",\\"22,732, 11,389\\",\\"Relaxed fit jeans - black denim, Basic T-shirt - green\\",\\"Relaxed fit jeans - black denim, Basic T-shirt - green\\",\\"1, 1\\",\\"ZO0113301133, ZO0562105621\\",\\"0, 0\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"0, 0\\",\\"ZO0113301133, ZO0562105621\\",\\"40.969\\",\\"40.969\\",2,2,order,jason +JAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Miller\\",\\"Elyssa Miller\\",FEMALE,27,Miller,Miller,\\"(empty)\\",Tuesday,1,\\"elyssa@miller-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Gnomehouse mom\\",\\"Tigress Enterprises, Gnomehouse mom\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566829,\\"sold_product_566829_21605, sold_product_566829_17889\\",\\"sold_product_566829_21605, sold_product_566829_17889\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse mom\\",\\"Tigress Enterprises, Gnomehouse mom\\",\\"12.25, 15.07\\",\\"24.984, 28.984\\",\\"21,605, 17,889\\",\\"Pyjama top - navy, Blouse - black\\",\\"Pyjama top - navy, Blouse - black\\",\\"1, 1\\",\\"ZO0100901009, ZO0235102351\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0100901009, ZO0235102351\\",\\"53.969\\",\\"53.969\\",2,2,order,elyssa +RAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Fleming\\",\\"Muniz Fleming\\",MALE,37,Fleming,Fleming,\\"(empty)\\",Tuesday,1,\\"muniz@fleming-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Oceanavigations,Oceanavigations,\\"Jun 24, 2019 @ 00:00:00.000\\",567666,\\"sold_product_567666_17099, sold_product_567666_2908\\",\\"sold_product_567666_17099, sold_product_567666_2908\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"13.242, 14.781\\",\\"24.984, 28.984\\",\\"17,099, 2,908\\",\\"Watch - black, Chinos - beige \\",\\"Watch - black, Chinos - beige \\",\\"1, 1\\",\\"ZO0311403114, ZO0282002820\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0311403114, ZO0282002820\\",\\"53.969\\",\\"53.969\\",2,2,order,muniz +kgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Austin\\",\\"Pia Austin\\",FEMALE,45,Austin,Austin,\\"(empty)\\",Tuesday,1,\\"pia@austin-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567383,\\"sold_product_567383_16258, sold_product_567383_15314\\",\\"sold_product_567383_16258, sold_product_567383_15314\\",\\"10.992, 42\\",\\"10.992, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"5.059, 20.578\\",\\"10.992, 42\\",\\"16,258, 15,314\\",\\"Print T-shirt - light grey/white, A-line skirt - navy blazer\\",\\"Print T-shirt - light grey/white, A-line skirt - navy blazer\\",\\"1, 1\\",\\"ZO0647406474, ZO0330703307\\",\\"0, 0\\",\\"10.992, 42\\",\\"10.992, 42\\",\\"0, 0\\",\\"ZO0647406474, ZO0330703307\\",\\"52.969\\",\\"52.969\\",2,2,order,pia +ugMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Greene\\",\\"Abd Greene\\",MALE,52,Greene,Greene,\\"(empty)\\",Tuesday,1,\\"abd@greene-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567381,\\"sold_product_567381_13005, sold_product_567381_18590\\",\\"sold_product_567381_13005, sold_product_567381_18590\\",\\"22.984, 42\\",\\"22.984, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"10.352, 19.313\\",\\"22.984, 42\\",\\"13,005, 18,590\\",\\"Shirt - grey, Light jacket - mottled light grey\\",\\"Shirt - grey, Light jacket - mottled light grey\\",\\"1, 1\\",\\"ZO0278402784, ZO0458304583\\",\\"0, 0\\",\\"22.984, 42\\",\\"22.984, 42\\",\\"0, 0\\",\\"ZO0278402784, ZO0458304583\\",65,65,2,2,order,abd +zwMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Simpson\\",\\"Jackson Simpson\\",MALE,13,Simpson,Simpson,\\"(empty)\\",Tuesday,1,\\"jackson@simpson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567437,\\"sold_product_567437_16571, sold_product_567437_11872\\",\\"sold_product_567437_16571, sold_product_567437_11872\\",\\"65, 7.988\\",\\"65, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"35.094, 3.68\\",\\"65, 7.988\\",\\"16,571, 11,872\\",\\"Suit jacket - black, Basic T-shirt - light red multicolor\\",\\"Suit jacket - black, Basic T-shirt - light red multicolor\\",\\"1, 1\\",\\"ZO0275902759, ZO0545005450\\",\\"0, 0\\",\\"65, 7.988\\",\\"65, 7.988\\",\\"0, 0\\",\\"ZO0275902759, ZO0545005450\\",73,73,2,2,order,jackson +CwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Gomez\\",\\"Irwin Gomez\\",MALE,14,Gomez,Gomez,\\"(empty)\\",Tuesday,1,\\"irwin@gomez-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567324,\\"sold_product_567324_15839, sold_product_567324_11429\\",\\"sold_product_567324_15839, sold_product_567324_11429\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"16.813, 5.391\\",\\"33, 10.992\\",\\"15,839, 11,429\\",\\"Slim fit jeans - sand , Swimming shorts - lime punch\\",\\"Slim fit jeans - sand , Swimming shorts - lime punch\\",\\"1, 1\\",\\"ZO0426604266, ZO0629406294\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0426604266, ZO0629406294\\",\\"43.969\\",\\"43.969\\",2,2,order,irwin +QwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Hubbard\\",\\"Yuri Hubbard\\",MALE,21,Hubbard,Hubbard,\\"(empty)\\",Tuesday,1,\\"yuri@hubbard-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567504,\\"sold_product_567504_18713, sold_product_567504_23235\\",\\"sold_product_567504_18713, sold_product_567504_23235\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.75, 13.242\\",\\"24.984, 24.984\\",\\"18,713, 23,235\\",\\"Rucksack - navy/Blue Violety, Shirt - grey/black\\",\\"Rucksack - navy/Blue Violety, Shirt - grey/black\\",\\"1, 1\\",\\"ZO0606506065, ZO0277702777\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0606506065, ZO0277702777\\",\\"49.969\\",\\"49.969\\",2,2,order,yuri +RAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Selena,Selena,\\"Selena Gregory\\",\\"Selena Gregory\\",FEMALE,42,Gregory,Gregory,\\"(empty)\\",Tuesday,1,\\"selena@gregory-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567623,\\"sold_product_567623_14283, sold_product_567623_22330\\",\\"sold_product_567623_14283, sold_product_567623_22330\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"32.375, 5.52\\",\\"60, 11.992\\",\\"14,283, 22,330\\",\\"Lace-ups - nude, Long sleeved top - off white/navy\\",\\"Lace-ups - nude, Long sleeved top - off white/navy\\",\\"1, 1\\",\\"ZO0239802398, ZO0645406454\\",\\"0, 0\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"0, 0\\",\\"ZO0239802398, ZO0645406454\\",72,72,2,2,order,selena +RwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Rios\\",\\"Abd Rios\\",MALE,52,Rios,Rios,\\"(empty)\\",Tuesday,1,\\"abd@rios-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567400,\\"sold_product_567400_13372, sold_product_567400_7092\\",\\"sold_product_567400_13372, sold_product_567400_7092\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.75, 23.094\\",\\"24.984, 42\\",\\"13,372, 7,092\\",\\"Rucksack - navy/cognac , Tracksuit top - oliv\\",\\"Rucksack - navy/cognac , Tracksuit top - oliv\\",\\"1, 1\\",\\"ZO0605606056, ZO0588105881\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0605606056, ZO0588105881\\",67,67,2,2,order,abd +TwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Garner\\",\\"Yasmine Garner\\",FEMALE,43,Garner,Garner,\\"(empty)\\",Tuesday,1,\\"yasmine@garner-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",566757,\\"sold_product_566757_16685, sold_product_566757_20906\\",\\"sold_product_566757_16685, sold_product_566757_20906\\",\\"18.984, 11.992\\",\\"18.984, 11.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"9.492, 6.23\\",\\"18.984, 11.992\\",\\"16,685, 20,906\\",\\"Across body bag - black, Print T-shirt - white\\",\\"Across body bag - black, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0196201962, ZO0168601686\\",\\"0, 0\\",\\"18.984, 11.992\\",\\"18.984, 11.992\\",\\"0, 0\\",\\"ZO0196201962, ZO0168601686\\",\\"30.984\\",\\"30.984\\",2,2,order,yasmine +UAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Gregory\\",\\"Brigitte Gregory\\",FEMALE,12,Gregory,Gregory,\\"(empty)\\",Tuesday,1,\\"brigitte@gregory-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566884,\\"sold_product_566884_23198, sold_product_566884_5945\\",\\"sold_product_566884_23198, sold_product_566884_5945\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"10.492, 11.5\\",\\"20.984, 24.984\\",\\"23,198, 5,945\\",\\"Jersey dress - black, Ankle boots - black\\",\\"Jersey dress - black, Ankle boots - black\\",\\"1, 1\\",\\"ZO0490204902, ZO0025000250\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0490204902, ZO0025000250\\",\\"45.969\\",\\"45.969\\",2,2,order,brigitte +pwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Brewer\\",\\"Abigail Brewer\\",FEMALE,46,Brewer,Brewer,\\"(empty)\\",Tuesday,1,\\"abigail@brewer-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,Oceanavigations,Oceanavigations,\\"Jun 24, 2019 @ 00:00:00.000\\",567815,\\"sold_product_567815_24802, sold_product_567815_7476\\",\\"sold_product_567815_24802, sold_product_567815_7476\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"8.328, 32.375\\",\\"16.984, 60\\",\\"24,802, 7,476\\",\\"Print T-shirt - red, Slip-ons - Wheat\\",\\"Print T-shirt - red, Slip-ons - Wheat\\",\\"1, 1\\",\\"ZO0263602636, ZO0241002410\\",\\"0, 0\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"0, 0\\",\\"ZO0263602636, ZO0241002410\\",77,77,2,2,order,abigail +GwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Massey\\",\\"Wilhemina St. Massey\\",FEMALE,17,Massey,Massey,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@massey-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",567177,\\"sold_product_567177_12365, sold_product_567177_23200\\",\\"sold_product_567177_12365, sold_product_567177_23200\\",\\"30.984, 24.984\\",\\"30.984, 24.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"15.492, 12.25\\",\\"30.984, 24.984\\",\\"12,365, 23,200\\",\\"Rucksack - grey , Bomber Jacket - black\\",\\"Rucksack - grey , Bomber Jacket - black\\",\\"1, 1\\",\\"ZO0197301973, ZO0180401804\\",\\"0, 0\\",\\"30.984, 24.984\\",\\"30.984, 24.984\\",\\"0, 0\\",\\"ZO0197301973, ZO0180401804\\",\\"55.969\\",\\"55.969\\",2,2,order,wilhemina +lwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Lambert\\",\\"Elyssa Lambert\\",FEMALE,27,Lambert,Lambert,\\"(empty)\\",Tuesday,1,\\"elyssa@lambert-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises, Oceanavigations, Low Tide Media\\",\\"Pyramidustries, Tigress Enterprises, Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",733060,\\"sold_product_733060_13851, sold_product_733060_7400, sold_product_733060_20106, sold_product_733060_5045\\",\\"sold_product_733060_13851, sold_product_733060_7400, sold_product_733060_20106, sold_product_733060_5045\\",\\"20.984, 50, 50, 60\\",\\"20.984, 50, 50, 60\\",\\"Women's Clothing, Women's Shoes, Women's Shoes, Women's Shoes\\",\\"Women's Clothing, Women's Shoes, Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Tigress Enterprises, Oceanavigations, Low Tide Media\\",\\"Pyramidustries, Tigress Enterprises, Oceanavigations, Low Tide Media\\",\\"10.492, 23.5, 22.5, 30.594\\",\\"20.984, 50, 50, 60\\",\\"13,851, 7,400, 20,106, 5,045\\",\\"Summer dress - black, Lace-up boots - black, Ballet pumps - bronze, Boots - black\\",\\"Summer dress - black, Lace-up boots - black, Ballet pumps - bronze, Boots - black\\",\\"1, 1, 1, 1\\",\\"ZO0155601556, ZO0013600136, ZO0235702357, ZO0383203832\\",\\"0, 0, 0, 0\\",\\"20.984, 50, 50, 60\\",\\"20.984, 50, 50, 60\\",\\"0, 0, 0, 0\\",\\"ZO0155601556, ZO0013600136, ZO0235702357, ZO0383203832\\",181,181,4,4,order,elyssa +zgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Selena,Selena,\\"Selena Rose\\",\\"Selena Rose\\",FEMALE,42,Rose,Rose,\\"(empty)\\",Tuesday,1,\\"selena@rose-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567486,\\"sold_product_567486_19378, sold_product_567486_21859\\",\\"sold_product_567486_19378, sold_product_567486_21859\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"13.492, 20.156\\",\\"24.984, 42\\",\\"19,378, 21,859\\",\\"Long sleeved top - winternude, Wedge sandals - black\\",\\"Long sleeved top - winternude, Wedge sandals - black\\",\\"1, 1\\",\\"ZO0058200582, ZO0365503655\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0058200582, ZO0365503655\\",67,67,2,2,order,selena +zwMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Goodwin\\",\\"Abigail Goodwin\\",FEMALE,46,Goodwin,Goodwin,\\"(empty)\\",Tuesday,1,\\"abigail@goodwin-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,Gnomehouse,Gnomehouse,\\"Jun 24, 2019 @ 00:00:00.000\\",567625,\\"sold_product_567625_21570, sold_product_567625_16910\\",\\"sold_product_567625_21570, sold_product_567625_16910\\",\\"55, 42\\",\\"55, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"28.047, 19.734\\",\\"55, 42\\",\\"21,570, 16,910\\",\\"A-line skirt - flame scarlet, Pleated skirt - black\\",\\"A-line skirt - flame scarlet, Pleated skirt - black\\",\\"1, 1\\",\\"ZO0328603286, ZO0328803288\\",\\"0, 0\\",\\"55, 42\\",\\"55, 42\\",\\"0, 0\\",\\"ZO0328603286, ZO0328803288\\",97,97,2,2,order,abigail +2gMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Recip,Recip,\\"Recip Brock\\",\\"Recip Brock\\",MALE,10,Brock,Brock,\\"(empty)\\",Tuesday,1,\\"recip@brock-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567224,\\"sold_product_567224_16809, sold_product_567224_18808\\",\\"sold_product_567224_16809, sold_product_567224_18808\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"14.211, 10.078\\",\\"28.984, 20.984\\",\\"16,809, 18,808\\",\\"Rucksack - black, Rucksack - black/cognac\\",\\"Rucksack - black, Rucksack - black/cognac\\",\\"1, 1\\",\\"ZO0128501285, ZO0606306063\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0128501285, ZO0606306063\\",\\"49.969\\",\\"49.969\\",2,2,order,recip +2wMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Kim\\",\\"Diane Kim\\",FEMALE,22,Kim,Kim,\\"(empty)\\",Tuesday,1,\\"diane@kim-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Pyramidustries active\\",\\"Low Tide Media, Pyramidustries active\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567252,\\"sold_product_567252_16632, sold_product_567252_16333\\",\\"sold_product_567252_16632, sold_product_567252_16333\\",\\"42, 24.984\\",\\"42, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries active\\",\\"Low Tide Media, Pyramidustries active\\",\\"19.313, 12\\",\\"42, 24.984\\",\\"16,632, 16,333\\",\\"Slip-ons - mud, Long sleeved top - black \\",\\"Slip-ons - mud, Long sleeved top - black \\",\\"1, 1\\",\\"ZO0369803698, ZO0220502205\\",\\"0, 0\\",\\"42, 24.984\\",\\"42, 24.984\\",\\"0, 0\\",\\"ZO0369803698, ZO0220502205\\",67,67,2,2,order,diane +\\"-AMtOW0BH63Xcmy45GjD\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Thad,Thad,\\"Thad Bowers\\",\\"Thad Bowers\\",MALE,30,Bowers,Bowers,\\"(empty)\\",Tuesday,1,\\"thad@bowers-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567735,\\"sold_product_567735_14414, sold_product_567735_20047\\",\\"sold_product_567735_14414, sold_product_567735_20047\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"4.148, 11.5\\",\\"7.988, 24.984\\",\\"14,414, 20,047\\",\\"3 PACK - Socks - black/white, Slip-ons - navy\\",\\"3 PACK - Socks - black/white, Slip-ons - navy\\",\\"1, 1\\",\\"ZO0129701297, ZO0518705187\\",\\"0, 0\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"0, 0\\",\\"ZO0129701297, ZO0518705187\\",\\"32.969\\",\\"32.969\\",2,2,order,thad +BQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Rice\\",\\"Diane Rice\\",FEMALE,22,Rice,Rice,\\"(empty)\\",Tuesday,1,\\"diane@rice-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567822,\\"sold_product_567822_5501, sold_product_567822_25039\\",\\"sold_product_567822_5501, sold_product_567822_25039\\",\\"75, 33\\",\\"75, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"40.5, 17.813\\",\\"75, 33\\",\\"5,501, 25,039\\",\\"Ankle boots - Midnight Blue, Shirt - Lemon Chiffon\\",\\"Ankle boots - Midnight Blue, Shirt - Lemon Chiffon\\",\\"1, 1\\",\\"ZO0244802448, ZO0346303463\\",\\"0, 0\\",\\"75, 33\\",\\"75, 33\\",\\"0, 0\\",\\"ZO0244802448, ZO0346303463\\",108,108,2,2,order,diane +BgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Youssef,Youssef,\\"Youssef Baker\\",\\"Youssef Baker\\",MALE,31,Baker,Baker,\\"(empty)\\",Tuesday,1,\\"youssef@baker-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567852,\\"sold_product_567852_12928, sold_product_567852_11153\\",\\"sold_product_567852_12928, sold_product_567852_11153\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9.656, 5.172\\",\\"20.984, 10.992\\",\\"12,928, 11,153\\",\\"Shirt - black /grey, Cap - black/black\\",\\"Shirt - black /grey, Cap - black/black\\",\\"1, 1\\",\\"ZO0523805238, ZO0596505965\\",\\"0, 0\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"0, 0\\",\\"ZO0523805238, ZO0596505965\\",\\"31.984\\",\\"31.984\\",2,2,order,youssef +JwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Hicham,Hicham,\\"Hicham Carpenter\\",\\"Hicham Carpenter\\",MALE,8,Carpenter,Carpenter,\\"(empty)\\",Tuesday,1,\\"hicham@carpenter-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566861,\\"sold_product_566861_1978, sold_product_566861_11748\\",\\"sold_product_566861_1978, sold_product_566861_11748\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"27.484, 8.328\\",\\"50, 16.984\\",\\"1,978, 11,748\\",\\"Lace-up boots - black, Wallet - grey\\",\\"Lace-up boots - black, Wallet - grey\\",\\"1, 1\\",\\"ZO0520305203, ZO0462204622\\",\\"0, 0\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"0, 0\\",\\"ZO0520305203, ZO0462204622\\",67,67,2,2,order,hicham +KAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Reyes\\",\\"Gwen Reyes\\",FEMALE,26,Reyes,Reyes,\\"(empty)\\",Tuesday,1,\\"gwen@reyes-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567042,\\"sold_product_567042_23822, sold_product_567042_11786\\",\\"sold_product_567042_23822, sold_product_567042_11786\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"32.375, 11.117\\",\\"60, 20.984\\",\\"23,822, 11,786\\",\\"Sandals - Midnight Blue, Print T-shirt - black\\",\\"Sandals - Midnight Blue, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0243002430, ZO0103901039\\",\\"0, 0\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"0, 0\\",\\"ZO0243002430, ZO0103901039\\",81,81,2,2,order,gwen +SAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Cook\\",\\"Elyssa Cook\\",FEMALE,27,Cook,Cook,\\"(empty)\\",Tuesday,1,\\"elyssa@cook-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Gnomehouse, Tigress Enterprises\\",\\"Pyramidustries, Gnomehouse, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",731037,\\"sold_product_731037_17669, sold_product_731037_9413, sold_product_731037_8035, sold_product_731037_24229\\",\\"sold_product_731037_17669, sold_product_731037_9413, sold_product_731037_8035, sold_product_731037_24229\\",\\"13.992, 50, 13.992, 29.984\\",\\"13.992, 50, 13.992, 29.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Gnomehouse, Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Gnomehouse, Pyramidustries, Tigress Enterprises\\",\\"6.441, 22.5, 7, 15.289\\",\\"13.992, 50, 13.992, 29.984\\",\\"17,669, 9,413, 8,035, 24,229\\",\\"Pencil skirt - black, Summer dress - Pale Violet Red, Jersey dress - black, Trousers - black\\",\\"Pencil skirt - black, Summer dress - Pale Violet Red, Jersey dress - black, Trousers - black\\",\\"1, 1, 1, 1\\",\\"ZO0148801488, ZO0335003350, ZO0155301553, ZO0074300743\\",\\"0, 0, 0, 0\\",\\"13.992, 50, 13.992, 29.984\\",\\"13.992, 50, 13.992, 29.984\\",\\"0, 0, 0, 0\\",\\"ZO0148801488, ZO0335003350, ZO0155301553, ZO0074300743\\",\\"107.938\\",\\"107.938\\",4,4,order,elyssa +gQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Morgan\\",\\"Sultan Al Morgan\\",MALE,19,Morgan,Morgan,\\"(empty)\\",Tuesday,1,\\"sultan al@morgan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567729,\\"sold_product_567729_1196, sold_product_567729_13331\\",\\"sold_product_567729_1196, sold_product_567729_13331\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"20.156, 9.656\\",\\"42, 20.984\\",\\"1,196, 13,331\\",\\"Trainers - white, Jumper - black\\",\\"Trainers - white, Jumper - black\\",\\"1, 1\\",\\"ZO0395103951, ZO0296102961\\",\\"0, 0\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"0, 0\\",\\"ZO0395103951, ZO0296102961\\",\\"62.969\\",\\"62.969\\",2,2,order,sultan +iQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Carpenter\\",\\"Jim Carpenter\\",MALE,41,Carpenter,Carpenter,\\"(empty)\\",Tuesday,1,\\"jim@carpenter-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567384,\\"sold_product_567384_22462, sold_product_567384_21856\\",\\"sold_product_567384_22462, sold_product_567384_21856\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"14.852, 12.742\\",\\"33, 24.984\\",\\"22,462, 21,856\\",\\"Slim fit jeans - dark grey , Pyjama set - grey\\",\\"Slim fit jeans - dark grey , Pyjama set - grey\\",\\"1, 1\\",\\"ZO0426704267, ZO0612006120\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0426704267, ZO0612006120\\",\\"57.969\\",\\"57.969\\",2,2,order,jim +kwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Goodman\\",\\"Fitzgerald Goodman\\",MALE,11,Goodman,Goodman,\\"(empty)\\",Tuesday,1,\\"fitzgerald@goodman-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566690,\\"sold_product_566690_11851, sold_product_566690_18257\\",\\"sold_product_566690_11851, sold_product_566690_18257\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"13.922, 7.051\\",\\"28.984, 14.992\\",\\"11,851, 18,257\\",\\"Jumper - dark blue, Print T-shirt - black\\",\\"Jumper - dark blue, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0449004490, ZO0118501185\\",\\"0, 0\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"0, 0\\",\\"ZO0449004490, ZO0118501185\\",\\"43.969\\",\\"43.969\\",2,2,order,fuzzy +lAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Frances,Frances,\\"Frances Mullins\\",\\"Frances Mullins\\",FEMALE,49,Mullins,Mullins,\\"(empty)\\",Tuesday,1,\\"frances@mullins-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566951,\\"sold_product_566951_2269, sold_product_566951_14250\\",\\"sold_product_566951_2269, sold_product_566951_14250\\",\\"50, 33\\",\\"50, 33\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"23, 15.508\\",\\"50, 33\\",\\"2,269, 14,250\\",\\"Boots - Slate Gray, High-top trainers - grey\\",\\"Boots - Slate Gray, High-top trainers - grey\\",\\"1, 1\\",\\"ZO0406604066, ZO0517405174\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0406604066, ZO0517405174\\",83,83,2,2,order,frances +lQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Washington\\",\\"Diane Washington\\",FEMALE,22,Washington,Washington,\\"(empty)\\",Tuesday,1,\\"diane@washington-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566982,\\"sold_product_566982_13852, sold_product_566982_21858\\",\\"sold_product_566982_13852, sold_product_566982_21858\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"7.648, 8.156\\",\\"16.984, 16.984\\",\\"13,852, 21,858\\",\\"A-line skirt - black/white, Nightie - off white\\",\\"A-line skirt - black/white, Nightie - off white\\",\\"1, 1\\",\\"ZO0149301493, ZO0099800998\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0149301493, ZO0099800998\\",\\"33.969\\",\\"33.969\\",2,2,order,diane +lgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Phil,Phil,\\"Phil Bailey\\",\\"Phil Bailey\\",MALE,50,Bailey,Bailey,\\"(empty)\\",Tuesday,1,\\"phil@bailey-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566725,\\"sold_product_566725_17721, sold_product_566725_19679\\",\\"sold_product_566725_17721, sold_product_566725_19679\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"7.988, 15.648\\",\\"16.984, 28.984\\",\\"17,721, 19,679\\",\\"Polo shirt - light grey multicolor, Hoodie - black/dark blue/white\\",\\"Polo shirt - light grey multicolor, Hoodie - black/dark blue/white\\",\\"1, 1\\",\\"ZO0444404444, ZO0584205842\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0444404444, ZO0584205842\\",\\"45.969\\",\\"45.969\\",2,2,order,phil +wgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Fletcher\\",\\"Yasmine Fletcher\\",FEMALE,43,Fletcher,Fletcher,\\"(empty)\\",Tuesday,1,\\"yasmine@fletcher-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566856,\\"sold_product_566856_10829, sold_product_566856_25007\\",\\"sold_product_566856_10829, sold_product_566856_25007\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"15.07, 26.484\\",\\"28.984, 50\\",\\"10,829, 25,007\\",\\"Sports shoes - black/pink, Jumpsuit - Pale Violet Red\\",\\"Sports shoes - black/pink, Jumpsuit - Pale Violet Red\\",\\"1, 1\\",\\"ZO0216502165, ZO0327503275\\",\\"0, 0\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"0, 0\\",\\"ZO0216502165, ZO0327503275\\",79,79,2,2,order,yasmine +wwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Moss\\",\\"Selena Moss\\",FEMALE,42,Moss,Moss,\\"(empty)\\",Tuesday,1,\\"selena@moss-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567039,\\"sold_product_567039_16085, sold_product_567039_16220\\",\\"sold_product_567039_16085, sold_product_567039_16220\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Pyramidustries, Spherecords Curvy\\",\\"11.75, 7.789\\",\\"24.984, 14.992\\",\\"16,085, 16,220\\",\\"Jeans Skinny Fit - dark blue denim, Vest - white\\",\\"Jeans Skinny Fit - dark blue denim, Vest - white\\",\\"1, 1\\",\\"ZO0184101841, ZO0711207112\\",\\"0, 0\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"0, 0\\",\\"ZO0184101841, ZO0711207112\\",\\"39.969\\",\\"39.969\\",2,2,order,selena +xAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Greene\\",\\"Wilhemina St. Greene\\",FEMALE,17,Greene,Greene,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@greene-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Spherecords Curvy\\",\\"Tigress Enterprises, Spherecords Curvy\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567068,\\"sold_product_567068_13637, sold_product_567068_21700\\",\\"sold_product_567068_13637, sold_product_567068_21700\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords Curvy\\",\\"Tigress Enterprises, Spherecords Curvy\\",\\"13.633, 7.051\\",\\"28.984, 14.992\\",\\"13,637, 21,700\\",\\"Jersey dress - multicolor, Basic T-shirt - black\\",\\"Jersey dress - multicolor, Basic T-shirt - black\\",\\"1, 1\\",\\"ZO0038000380, ZO0711007110\\",\\"0, 0\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"0, 0\\",\\"ZO0038000380, ZO0711007110\\",\\"43.969\\",\\"43.969\\",2,2,order,wilhemina +0wMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Cunningham\\",\\"Rabbia Al Cunningham\\",FEMALE,5,Cunningham,Cunningham,\\"(empty)\\",Tuesday,1,\\"rabbia al@cunningham-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Pyramidustries, Angeldale, Oceanavigations\\",\\"Pyramidustries, Angeldale, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",732229,\\"sold_product_732229_21857, sold_product_732229_23802, sold_product_732229_12401, sold_product_732229_21229\\",\\"sold_product_732229_21857, sold_product_732229_23802, sold_product_732229_12401, sold_product_732229_21229\\",\\"20.984, 20.984, 65, 80\\",\\"20.984, 20.984, 65, 80\\",\\"Women's Clothing, Women's Clothing, Women's Accessories, Women's Shoes\\",\\"Women's Clothing, Women's Clothing, Women's Accessories, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Pyramidustries, Angeldale, Oceanavigations\\",\\"Pyramidustries, Pyramidustries, Angeldale, Oceanavigations\\",\\"10.078, 11.539, 31.203, 40.781\\",\\"20.984, 20.984, 65, 80\\",\\"21,857, 23,802, 12,401, 21,229\\",\\"Cardigan - black/white, Long sleeved top - off white, Handbag - black, Boots - navy\\",\\"Cardigan - black/white, Long sleeved top - off white, Handbag - black, Boots - navy\\",\\"1, 1, 1, 1\\",\\"ZO0175701757, ZO0163801638, ZO0697506975, ZO0245602456\\",\\"0, 0, 0, 0\\",\\"20.984, 20.984, 65, 80\\",\\"20.984, 20.984, 65, 80\\",\\"0, 0, 0, 0\\",\\"ZO0175701757, ZO0163801638, ZO0697506975, ZO0245602456\\",187,187,4,4,order,rabbia +1AMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Ball\\",\\"Rabbia Al Ball\\",FEMALE,5,Ball,Ball,\\"(empty)\\",Tuesday,1,\\"rabbia al@ball-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spherecords, Tigress Enterprises, Angeldale\\",\\"Spherecords, Tigress Enterprises, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",724806,\\"sold_product_724806_13062, sold_product_724806_12709, sold_product_724806_19614, sold_product_724806_21000\\",\\"sold_product_724806_13062, sold_product_724806_12709, sold_product_724806_19614, sold_product_724806_21000\\",\\"11.992, 28.984, 60, 20.984\\",\\"11.992, 28.984, 60, 20.984\\",\\"Women's Clothing, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Tigress Enterprises, Angeldale, Spherecords\\",\\"Spherecords, Tigress Enterprises, Angeldale, Spherecords\\",\\"6.23, 14.781, 27, 11.539\\",\\"11.992, 28.984, 60, 20.984\\",\\"13,062, 12,709, 19,614, 21,000\\",\\"Long sleeved top - dark green, Pleated skirt - Blue Violety, Tote bag - terracotta, Shirt - light blue\\",\\"Long sleeved top - dark green, Pleated skirt - Blue Violety, Tote bag - terracotta, Shirt - light blue\\",\\"1, 1, 1, 1\\",\\"ZO0643106431, ZO0033300333, ZO0696206962, ZO0651206512\\",\\"0, 0, 0, 0\\",\\"11.992, 28.984, 60, 20.984\\",\\"11.992, 28.984, 60, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0643106431, ZO0033300333, ZO0696206962, ZO0651206512\\",\\"121.938\\",\\"121.938\\",4,4,order,rabbia +8QMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Graham\\",\\"Abd Graham\\",MALE,52,Graham,Graham,\\"(empty)\\",Tuesday,1,\\"abd@graham-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567769,\\"sold_product_567769_24888, sold_product_567769_16104\\",\\"sold_product_567769_24888, sold_product_567769_16104\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"14.211, 9.117\\",\\"28.984, 18.984\\",\\"24,888, 16,104\\",\\"Formal shirt - blue, Swimming shorts - blue atol\\",\\"Formal shirt - blue, Swimming shorts - blue atol\\",\\"1, 1\\",\\"ZO0414004140, ZO0630106301\\",\\"0, 0\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"0, 0\\",\\"ZO0414004140, ZO0630106301\\",\\"47.969\\",\\"47.969\\",2,2,order,abd +AgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Potter\\",\\"Abigail Potter\\",FEMALE,46,Potter,Potter,\\"(empty)\\",Tuesday,1,\\"abigail@potter-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566772,\\"sold_product_566772_17102, sold_product_566772_7361\\",\\"sold_product_566772_17102, sold_product_566772_7361\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"10.703, 13.633\\",\\"20.984, 28.984\\",\\"17,102, 7,361\\",\\"Jersey dress - black/white, Ankle boots - black\\",\\"Jersey dress - black/white, Ankle boots - black\\",\\"1, 1\\",\\"ZO0152901529, ZO0019100191\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0152901529, ZO0019100191\\",\\"49.969\\",\\"49.969\\",2,2,order,abigail +2gMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Palmer\\",\\"Kamal Palmer\\",MALE,39,Palmer,Palmer,\\"(empty)\\",Tuesday,1,\\"kamal@palmer-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567318,\\"sold_product_567318_16500, sold_product_567318_1539\\",\\"sold_product_567318_16500, sold_product_567318_1539\\",\\"33, 60\\",\\"33, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"16.813, 30\\",\\"33, 60\\",\\"16,500, 1,539\\",\\"Casual Cuffed Pants, Lace-up boots - black\\",\\"Casual Cuffed Pants, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0421104211, ZO0256202562\\",\\"0, 0\\",\\"33, 60\\",\\"33, 60\\",\\"0, 0\\",\\"ZO0421104211, ZO0256202562\\",93,93,2,2,order,kamal +OQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Potter\\",\\"Stephanie Potter\\",FEMALE,6,Potter,Potter,\\"(empty)\\",Tuesday,1,\\"stephanie@potter-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567615,\\"sold_product_567615_21067, sold_product_567615_16863\\",\\"sold_product_567615_21067, sold_product_567615_16863\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"25.484, 13.922\\",\\"50, 28.984\\",\\"21,067, 16,863\\",\\"Lace-up boots - brown, Bomber Jacket - black\\",\\"Lace-up boots - brown, Bomber Jacket - black\\",\\"1, 1\\",\\"ZO0013500135, ZO0174501745\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0013500135, ZO0174501745\\",79,79,2,2,order,stephanie +QgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Muniz,Muniz,\\"Muniz Weber\\",\\"Muniz Weber\\",MALE,37,Weber,Weber,\\"(empty)\\",Tuesday,1,\\"muniz@weber-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567316,\\"sold_product_567316_13588, sold_product_567316_24014\\",\\"sold_product_567316_13588, sold_product_567316_24014\\",\\"60, 50\\",\\"60, 50\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"28.797, 24.5\\",\\"60, 50\\",\\"13,588, 24,014\\",\\"Lace-ups - cognac, Boots - saphire\\",\\"Lace-ups - cognac, Boots - saphire\\",\\"1, 1\\",\\"ZO0390403904, ZO0403004030\\",\\"0, 0\\",\\"60, 50\\",\\"60, 50\\",\\"0, 0\\",\\"ZO0390403904, ZO0403004030\\",110,110,2,2,order,muniz +RQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Mary,Mary,\\"Mary Kelley\\",\\"Mary Kelley\\",FEMALE,20,Kelley,Kelley,\\"(empty)\\",Tuesday,1,\\"mary@kelley-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566896,\\"sold_product_566896_16021, sold_product_566896_17331\\",\\"sold_product_566896_16021, sold_product_566896_17331\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"23, 10.492\\",\\"50, 20.984\\",\\"16,021, 17,331\\",\\"High heeled sandals - electric blue, Tote bag - Blue Violety\\",\\"High heeled sandals - electric blue, Tote bag - Blue Violety\\",\\"1, 1\\",\\"ZO0242702427, ZO0090000900\\",\\"0, 0\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"0, 0\\",\\"ZO0242702427, ZO0090000900\\",71,71,2,2,order,mary +WAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Henderson\\",\\"Phil Henderson\\",MALE,50,Henderson,Henderson,\\"(empty)\\",Tuesday,1,\\"phil@henderson-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567418,\\"sold_product_567418_22276, sold_product_567418_18190\\",\\"sold_product_567418_22276, sold_product_567418_18190\\",\\"75, 110\\",\\"75, 110\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"36.75, 58.281\\",\\"75, 110\\",\\"22,276, 18,190\\",\\"Lace-up boots - cognac, Ski jacket - bright white\\",\\"Lace-up boots - cognac, Ski jacket - bright white\\",\\"1, 1\\",\\"ZO0400404004, ZO0625006250\\",\\"0, 0\\",\\"75, 110\\",\\"75, 110\\",\\"0, 0\\",\\"ZO0400404004, ZO0625006250\\",185,185,2,2,order,phil +WQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Duncan\\",\\"Selena Duncan\\",FEMALE,42,Duncan,Duncan,\\"(empty)\\",Tuesday,1,\\"selena@duncan-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Spherecords Curvy\\",\\"Spherecords, Spherecords Curvy\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567462,\\"sold_product_567462_9295, sold_product_567462_18220\\",\\"sold_product_567462_9295, sold_product_567462_18220\\",\\"7.988, 16.984\\",\\"7.988, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spherecords Curvy\\",\\"Spherecords, Spherecords Curvy\\",\\"3.6, 8.656\\",\\"7.988, 16.984\\",\\"9,295, 18,220\\",\\"Print T-shirt - dark grey/white, Jersey dress - dark blue\\",\\"Print T-shirt - dark grey/white, Jersey dress - dark blue\\",\\"1, 1\\",\\"ZO0644406444, ZO0709307093\\",\\"0, 0\\",\\"7.988, 16.984\\",\\"7.988, 16.984\\",\\"0, 0\\",\\"ZO0644406444, ZO0709307093\\",\\"24.984\\",\\"24.984\\",2,2,order,selena +XwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Perkins\\",\\"George Perkins\\",MALE,32,Perkins,Perkins,\\"(empty)\\",Tuesday,1,\\"george@perkins-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,Oceanavigations,Oceanavigations,\\"Jun 24, 2019 @ 00:00:00.000\\",567667,\\"sold_product_567667_22878, sold_product_567667_19733\\",\\"sold_product_567667_22878, sold_product_567667_19733\\",\\"75, 33\\",\\"75, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"34.5, 16.813\\",\\"75, 33\\",\\"22,878, 19,733\\",\\"Suit jacket - dark blue, Sweatshirt - black\\",\\"Suit jacket - dark blue, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0273802738, ZO0300303003\\",\\"0, 0\\",\\"75, 33\\",\\"75, 33\\",\\"0, 0\\",\\"ZO0273802738, ZO0300303003\\",108,108,2,2,order,george +YAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Carr\\",\\"Elyssa Carr\\",FEMALE,27,Carr,Carr,\\"(empty)\\",Tuesday,1,\\"elyssa@carr-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567703,\\"sold_product_567703_11574, sold_product_567703_16709\\",\\"sold_product_567703_11574, sold_product_567703_16709\\",\\"42, 42\\",\\"42, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"19.313, 21.828\\",\\"42, 42\\",\\"11,574, 16,709\\",\\"Maxi dress - multicolor, Lace-up boots - Amethyst\\",\\"Maxi dress - multicolor, Lace-up boots - Amethyst\\",\\"1, 1\\",\\"ZO0037900379, ZO0134901349\\",\\"0, 0\\",\\"42, 42\\",\\"42, 42\\",\\"0, 0\\",\\"ZO0037900379, ZO0134901349\\",84,84,2,2,order,elyssa +iwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Powell\\",\\"Gwen Powell\\",FEMALE,26,Powell,Powell,\\"(empty)\\",Tuesday,1,\\"gwen@powell-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567260,\\"sold_product_567260_9302, sold_product_567260_7402\\",\\"sold_product_567260_9302, sold_product_567260_7402\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"16.172, 34.5\\",\\"33, 75\\",\\"9,302, 7,402\\",\\"Cardigan - red, Ankle boots - black \\",\\"Cardigan - red, Ankle boots - black \\",\\"1, 1\\",\\"ZO0068100681, ZO0674106741\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0068100681, ZO0674106741\\",108,108,2,2,order,gwen +jAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Washington\\",\\"Rabbia Al Washington\\",FEMALE,5,Washington,Washington,\\"(empty)\\",Tuesday,1,\\"rabbia al@washington-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spherecords Maternity, Oceanavigations, Pyramidustries active, Gnomehouse\\",\\"Spherecords Maternity, Oceanavigations, Pyramidustries active, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",724844,\\"sold_product_724844_19797, sold_product_724844_13322, sold_product_724844_10099, sold_product_724844_8107\\",\\"sold_product_724844_19797, sold_product_724844_13322, sold_product_724844_10099, sold_product_724844_8107\\",\\"20.984, 65, 20.984, 33\\",\\"20.984, 65, 20.984, 33\\",\\"Women's Clothing, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords Maternity, Oceanavigations, Pyramidustries active, Gnomehouse\\",\\"Spherecords Maternity, Oceanavigations, Pyramidustries active, Gnomehouse\\",\\"10.703, 33.781, 9.453, 17.484\\",\\"20.984, 65, 20.984, 33\\",\\"19,797, 13,322, 10,099, 8,107\\",\\"Shirt - white, High heeled ankle boots - black, Sweatshirt - black, Blouse - off-white\\",\\"Shirt - white, High heeled ankle boots - black, Sweatshirt - black, Blouse - off-white\\",\\"1, 1, 1, 1\\",\\"ZO0707507075, ZO0246402464, ZO0226802268, ZO0343503435\\",\\"0, 0, 0, 0\\",\\"20.984, 65, 20.984, 33\\",\\"20.984, 65, 20.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0707507075, ZO0246402464, ZO0226802268, ZO0343503435\\",140,140,4,4,order,rabbia +qAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Chapman\\",\\"Pia Chapman\\",FEMALE,45,Chapman,Chapman,\\"(empty)\\",Tuesday,1,\\"pia@chapman-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567308,\\"sold_product_567308_16474, sold_product_567308_18779\\",\\"sold_product_567308_16474, sold_product_567308_18779\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"9.344, 15.648\\",\\"16.984, 28.984\\",\\"16,474, 18,779\\",\\"Sweatshirt - grey multicolor, High heeled sandals - silver\\",\\"Sweatshirt - grey multicolor, High heeled sandals - silver\\",\\"1, 1\\",\\"ZO0181601816, ZO0011000110\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0181601816, ZO0011000110\\",\\"45.969\\",\\"45.969\\",2,2,order,pia +7gMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Morrison\\",\\"Abd Morrison\\",MALE,52,Morrison,Morrison,\\"(empty)\\",Tuesday,1,\\"abd@morrison-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567404,\\"sold_product_567404_22845, sold_product_567404_21489\\",\\"sold_product_567404_22845, sold_product_567404_21489\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"25.984, 13.633\\",\\"50, 28.984\\",\\"22,845, 21,489\\",\\"High-top trainers - red, Jeans Tapered Fit - blue denim\\",\\"High-top trainers - red, Jeans Tapered Fit - blue denim\\",\\"1, 1\\",\\"ZO0107101071, ZO0537905379\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0107101071, ZO0537905379\\",79,79,2,2,order,abd +PgMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Hopkins\\",\\"Youssef Hopkins\\",MALE,31,Hopkins,Hopkins,\\"(empty)\\",Tuesday,1,\\"youssef@hopkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567538,\\"sold_product_567538_16200, sold_product_567538_17404\\",\\"sold_product_567538_16200, sold_product_567538_17404\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.281, 27.594\\",\\"10.992, 60\\",\\"16,200, 17,404\\",\\"Hat - grey, Colorful Cardigan\\",\\"Hat - grey, Colorful Cardigan\\",\\"1, 1\\",\\"ZO0596905969, ZO0450804508\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0596905969, ZO0450804508\\",71,71,2,2,order,youssef +PwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Abigail,Abigail,\\"Abigail Perry\\",\\"Abigail Perry\\",FEMALE,46,Perry,Perry,\\"(empty)\\",Tuesday,1,\\"abigail@perry-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567593,\\"sold_product_567593_25072, sold_product_567593_17024\\",\\"sold_product_567593_25072, sold_product_567593_17024\\",\\"18.984, 24.984\\",\\"18.984, 24.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"8.93, 12.992\\",\\"18.984, 24.984\\",\\"25,072, 17,024\\",\\"Jumper - off white, Across body bag - black\\",\\"Jumper - off white, Across body bag - black\\",\\"1, 1\\",\\"ZO0655306553, ZO0208902089\\",\\"0, 0\\",\\"18.984, 24.984\\",\\"18.984, 24.984\\",\\"0, 0\\",\\"ZO0655306553, ZO0208902089\\",\\"43.969\\",\\"43.969\\",2,2,order,abigail +fQMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Williams\\",\\"Wagdi Williams\\",MALE,15,Williams,Williams,\\"(empty)\\",Tuesday,1,\\"wagdi@williams-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567294,\\"sold_product_567294_21723, sold_product_567294_20325\\",\\"sold_product_567294_21723, sold_product_567294_20325\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"12.992, 10.078\\",\\"24.984, 20.984\\",\\"21,723, 20,325\\",\\"SET - Hat - Medium Slate Blue, Sweatshirt - dark blue\\",\\"SET - Hat - Medium Slate Blue, Sweatshirt - dark blue\\",\\"1, 1\\",\\"ZO0317403174, ZO0457204572\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0317403174, ZO0457204572\\",\\"45.969\\",\\"45.969\\",2,2,order,wagdi +kQMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Underwood\\",\\"Wilhemina St. Underwood\\",FEMALE,17,Underwood,Underwood,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@underwood-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Low Tide Media, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Jun 24, 2019 @ 00:00:00.000\\",728256,\\"sold_product_728256_17123, sold_product_728256_19925, sold_product_728256_23613, sold_product_728256_17666\\",\\"sold_product_728256_17123, sold_product_728256_19925, sold_product_728256_23613, sold_product_728256_17666\\",\\"42, 33, 33, 37\\",\\"42, 33, 33, 37\\",\\"Women's Shoes, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Low Tide Media, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"22.672, 15.18, 17.156, 19.234\\",\\"42, 33, 33, 37\\",\\"17,123, 19,925, 23,613, 17,666\\",\\"Sandals - black, Jumper - Lemon Chiffon, Platform sandals - black, Summer dress - peacoat\\",\\"Sandals - black, Jumper - Lemon Chiffon, Platform sandals - black, Summer dress - peacoat\\",\\"1, 1, 1, 1\\",\\"ZO0371903719, ZO0352803528, ZO0137501375, ZO0229202292\\",\\"0, 0, 0, 0\\",\\"42, 33, 33, 37\\",\\"42, 33, 33, 37\\",\\"0, 0, 0, 0\\",\\"ZO0371903719, ZO0352803528, ZO0137501375, ZO0229202292\\",145,145,4,4,order,wilhemina +wgMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Miller\\",\\"Thad Miller\\",MALE,30,Miller,Miller,\\"(empty)\\",Tuesday,1,\\"thad@miller-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567544,\\"sold_product_567544_18963, sold_product_567544_19459\\",\\"sold_product_567544_18963, sold_product_567544_19459\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"10.078, 7.988\\",\\"20.984, 16.984\\",\\"18,963, 19,459\\",\\"Sweatshirt - white, Long sleeved top - Dark Salmon\\",\\"Sweatshirt - white, Long sleeved top - Dark Salmon\\",\\"1, 1\\",\\"ZO0585005850, ZO0120301203\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0585005850, ZO0120301203\\",\\"37.969\\",\\"37.969\\",2,2,order,thad +wwMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Stewart\\",\\"Jim Stewart\\",MALE,41,Stewart,Stewart,\\"(empty)\\",Tuesday,1,\\"jim@stewart-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567592,\\"sold_product_567592_2843, sold_product_567592_16403\\",\\"sold_product_567592_2843, sold_product_567592_16403\\",\\"28.984, 200\\",\\"28.984, 200\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"13.344, 98\\",\\"28.984, 200\\",\\"2,843, 16,403\\",\\"Jeans Tapered Fit - washed black, Short coat - light grey\\",\\"Jeans Tapered Fit - washed black, Short coat - light grey\\",\\"1, 1\\",\\"ZO0535405354, ZO0291302913\\",\\"0, 0\\",\\"28.984, 200\\",\\"28.984, 200\\",\\"0, 0\\",\\"ZO0535405354, ZO0291302913\\",229,229,2,2,order,jim +ywMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Farmer\\",\\"Betty Farmer\\",FEMALE,44,Farmer,Farmer,\\"(empty)\\",Tuesday,1,\\"betty@farmer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566942,\\"sold_product_566942_14928, sold_product_566942_23534\\",\\"sold_product_566942_14928, sold_product_566942_23534\\",\\"11.992, 22.984\\",\\"11.992, 22.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"6, 11.719\\",\\"11.992, 22.984\\",\\"14,928, 23,534\\",\\"Scarf - red, Jumper dress - dark green\\",\\"Scarf - red, Jumper dress - dark green\\",\\"1, 1\\",\\"ZO0084000840, ZO0636606366\\",\\"0, 0\\",\\"11.992, 22.984\\",\\"11.992, 22.984\\",\\"0, 0\\",\\"ZO0084000840, ZO0636606366\\",\\"34.969\\",\\"34.969\\",2,2,order,betty +zAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Foster\\",\\"Youssef Foster\\",MALE,31,Foster,Foster,\\"(empty)\\",Tuesday,1,\\"youssef@foster-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567015,\\"sold_product_567015_22305, sold_product_567015_11284\\",\\"sold_product_567015_22305, sold_product_567015_11284\\",\\"11.992, 20.984\\",\\"11.992, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.879, 10.078\\",\\"11.992, 20.984\\",\\"22,305, 11,284\\",\\"Print T-shirt - white, Chinos - dark blue\\",\\"Print T-shirt - white, Chinos - dark blue\\",\\"1, 1\\",\\"ZO0558605586, ZO0527805278\\",\\"0, 0\\",\\"11.992, 20.984\\",\\"11.992, 20.984\\",\\"0, 0\\",\\"ZO0558605586, ZO0527805278\\",\\"32.969\\",\\"32.969\\",2,2,order,youssef +zQMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Hopkins\\",\\"Sonya Hopkins\\",FEMALE,28,Hopkins,Hopkins,\\"(empty)\\",Tuesday,1,\\"sonya@hopkins-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",567081,\\"sold_product_567081_25066, sold_product_567081_13016\\",\\"sold_product_567081_25066, sold_product_567081_13016\\",\\"13.992, 24.984\\",\\"13.992, 24.984\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"7.41, 11.75\\",\\"13.992, 24.984\\",\\"25,066, 13,016\\",\\"Across body bag - red, Tote bag - cognac\\",\\"Across body bag - red, Tote bag - cognac\\",\\"1, 1\\",\\"ZO0209702097, ZO0186301863\\",\\"0, 0\\",\\"13.992, 24.984\\",\\"13.992, 24.984\\",\\"0, 0\\",\\"ZO0209702097, ZO0186301863\\",\\"38.969\\",\\"38.969\\",2,2,order,sonya +SgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Hayes\\",\\"Irwin Hayes\\",MALE,14,Hayes,Hayes,\\"(empty)\\",Tuesday,1,\\"irwin@hayes-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567475,\\"sold_product_567475_21824, sold_product_567475_23277\\",\\"sold_product_567475_21824, sold_product_567475_23277\\",\\"20.984, 42\\",\\"20.984, 42\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.906, 20.578\\",\\"20.984, 42\\",\\"21,824, 23,277\\",\\"Jumper - black, Boots - black\\",\\"Jumper - black, Boots - black\\",\\"1, 1\\",\\"ZO0578805788, ZO0520405204\\",\\"0, 0\\",\\"20.984, 42\\",\\"20.984, 42\\",\\"0, 0\\",\\"ZO0578805788, ZO0520405204\\",\\"62.969\\",\\"62.969\\",2,2,order,irwin +SwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Adams\\",\\"Abigail Adams\\",FEMALE,46,Adams,Adams,\\"(empty)\\",Tuesday,1,\\"abigail@adams-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567631,\\"sold_product_567631_18119, sold_product_567631_5772\\",\\"sold_product_567631_18119, sold_product_567631_5772\\",\\"6.988, 65\\",\\"6.988, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"3.289, 33.781\\",\\"6.988, 65\\",\\"18,119, 5,772\\",\\"2 PACK - Socks - red/grey, Classic heels - nude\\",\\"2 PACK - Socks - red/grey, Classic heels - nude\\",\\"1, 1\\",\\"ZO0101101011, ZO0667406674\\",\\"0, 0\\",\\"6.988, 65\\",\\"6.988, 65\\",\\"0, 0\\",\\"ZO0101101011, ZO0667406674\\",72,72,2,2,order,abigail +oAMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Gilbert\\",\\"Mary Gilbert\\",FEMALE,20,Gilbert,Gilbert,\\"(empty)\\",Tuesday,1,\\"mary@gilbert-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567454,\\"sold_product_567454_22330, sold_product_567454_8083\\",\\"sold_product_567454_22330, sold_product_567454_8083\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.52, 7.691\\",\\"11.992, 13.992\\",\\"22,330, 8,083\\",\\"Long sleeved top - off white/navy, Long sleeved top - light blue\\",\\"Long sleeved top - off white/navy, Long sleeved top - light blue\\",\\"1, 1\\",\\"ZO0645406454, ZO0166001660\\",\\"0, 0\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"0, 0\\",\\"ZO0645406454, ZO0166001660\\",\\"25.984\\",\\"25.984\\",2,2,order,mary +4wMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Gilbert\\",\\"Sonya Gilbert\\",FEMALE,28,Gilbert,Gilbert,\\"(empty)\\",Tuesday,1,\\"sonya@gilbert-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567855,\\"sold_product_567855_12032, sold_product_567855_11434\\",\\"sold_product_567855_12032, sold_product_567855_11434\\",\\"21.984, 11.992\\",\\"21.984, 11.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"10.781, 6.23\\",\\"21.984, 11.992\\",\\"12,032, 11,434\\",\\"Jeggings - grey denim, Snood - black\\",\\"Jeggings - grey denim, Snood - black\\",\\"1, 1\\",\\"ZO0657106571, ZO0084800848\\",\\"0, 0\\",\\"21.984, 11.992\\",\\"21.984, 11.992\\",\\"0, 0\\",\\"ZO0657106571, ZO0084800848\\",\\"33.969\\",\\"33.969\\",2,2,order,sonya +UwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Palmer\\",\\"Fitzgerald Palmer\\",MALE,11,Palmer,Palmer,\\"(empty)\\",Tuesday,1,\\"fitzgerald@palmer-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567835,\\"sold_product_567835_12431, sold_product_567835_12612\\",\\"sold_product_567835_12431, sold_product_567835_12612\\",\\"24.984, 165\\",\\"24.984, 165\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"11.25, 89.063\\",\\"24.984, 165\\",\\"12,431, 12,612\\",\\"Hoodie - white, Boots - taupe\\",\\"Hoodie - white, Boots - taupe\\",\\"1, 1\\",\\"ZO0589405894, ZO0483304833\\",\\"0, 0\\",\\"24.984, 165\\",\\"24.984, 165\\",\\"0, 0\\",\\"ZO0589405894, ZO0483304833\\",190,190,2,2,order,fuzzy +VAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robert,Robert,\\"Robert Stewart\\",\\"Robert Stewart\\",MALE,29,Stewart,Stewart,\\"(empty)\\",Tuesday,1,\\"robert@stewart-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567889,\\"sold_product_567889_14775, sold_product_567889_15520\\",\\"sold_product_567889_14775, sold_product_567889_15520\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"14.211, 20.156\\",\\"28.984, 42\\",\\"14,775, 15,520\\",\\"Chinos - black, Smart lace-ups - black\\",\\"Chinos - black, Smart lace-ups - black\\",\\"1, 1\\",\\"ZO0282202822, ZO0393003930\\",\\"0, 0\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"0, 0\\",\\"ZO0282202822, ZO0393003930\\",71,71,2,2,order,robert +dAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Frances,Frances,\\"Frances Goodwin\\",\\"Frances Goodwin\\",FEMALE,49,Goodwin,Goodwin,\\"(empty)\\",Tuesday,1,\\"frances@goodwin-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566852,\\"sold_product_566852_1709, sold_product_566852_11513\\",\\"sold_product_566852_1709, sold_product_566852_11513\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"35.094, 10.078\\",\\"65, 20.984\\",\\"1,709, 11,513\\",\\"Boots - black, Tracksuit top - bordeaux multicolor\\",\\"Boots - black, Tracksuit top - bordeaux multicolor\\",\\"1, 1\\",\\"ZO0257002570, ZO0455404554\\",\\"0, 0\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"0, 0\\",\\"ZO0257002570, ZO0455404554\\",86,86,2,2,order,frances +dQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Mccarthy\\",\\"Rabbia Al Mccarthy\\",FEMALE,5,Mccarthy,Mccarthy,\\"(empty)\\",Tuesday,1,\\"rabbia al@mccarthy-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567037,\\"sold_product_567037_16060, sold_product_567037_11158\\",\\"sold_product_567037_16060, sold_product_567037_11158\\",\\"20.984, 42\\",\\"20.984, 42\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"9.867, 22.672\\",\\"20.984, 42\\",\\"16,060, 11,158\\",\\"Clutch - gold, Classic heels - yellow\\",\\"Clutch - gold, Classic heels - yellow\\",\\"1, 1\\",\\"ZO0206402064, ZO0365903659\\",\\"0, 0\\",\\"20.984, 42\\",\\"20.984, 42\\",\\"0, 0\\",\\"ZO0206402064, ZO0365903659\\",\\"62.969\\",\\"62.969\\",2,2,order,rabbia +mAMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Harper\\",\\"Jackson Harper\\",MALE,13,Harper,Harper,\\"(empty)\\",Tuesday,1,\\"jackson@harper-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media, Elitelligence, (empty)\\",\\"Low Tide Media, Elitelligence, (empty)\\",\\"Jun 24, 2019 @ 00:00:00.000\\",721778,\\"sold_product_721778_1710, sold_product_721778_1718, sold_product_721778_12836, sold_product_721778_21677\\",\\"sold_product_721778_1710, sold_product_721778_1718, sold_product_721778_12836, sold_product_721778_21677\\",\\"65, 28.984, 165, 42\\",\\"65, 28.984, 165, 42\\",\\"Men's Shoes, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, (empty), Elitelligence\\",\\"Low Tide Media, Elitelligence, (empty), Elitelligence\\",\\"35.094, 15.359, 80.875, 22.25\\",\\"65, 28.984, 165, 42\\",\\"1,710, 1,718, 12,836, 21,677\\",\\"Boots - cognac, Lace-up boots - black, Lace-ups - brown, Light jacket - black\\",\\"Boots - cognac, Lace-up boots - black, Lace-ups - brown, Light jacket - black\\",\\"1, 1, 1, 1\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\",\\"0, 0, 0, 0\\",\\"65, 28.984, 165, 42\\",\\"65, 28.984, 165, 42\\",\\"0, 0, 0, 0\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\",301,301,4,4,order,jackson +2QMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Eddie,Eddie,\\"Eddie Foster\\",\\"Eddie Foster\\",MALE,38,Foster,Foster,\\"(empty)\\",Tuesday,1,\\"eddie@foster-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567143,\\"sold_product_567143_11605, sold_product_567143_16593\\",\\"sold_product_567143_11605, sold_product_567143_16593\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.75, 9.453\\",\\"24.984, 20.984\\",\\"11,605, 16,593\\",\\"Jumper - navy/offwhite/black, Wallet - brown\\",\\"Jumper - navy/offwhite/black, Wallet - brown\\",\\"1, 1\\",\\"ZO0573005730, ZO0313203132\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0573005730, ZO0313203132\\",\\"45.969\\",\\"45.969\\",2,2,order,eddie +2gMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Love\\",\\"Fitzgerald Love\\",MALE,11,Love,Love,\\"(empty)\\",Tuesday,1,\\"fitzgerald@love-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567191,\\"sold_product_567191_20587, sold_product_567191_16436\\",\\"sold_product_567191_20587, sold_product_567191_16436\\",\\"42, 13.992\\",\\"42, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"22.672, 6.578\\",\\"42, 13.992\\",\\"20,587, 16,436\\",\\"Slim fit jeans - black denim, Pyjama bottoms - blue\\",\\"Slim fit jeans - black denim, Pyjama bottoms - blue\\",\\"1, 1\\",\\"ZO0113901139, ZO0478904789\\",\\"0, 0\\",\\"42, 13.992\\",\\"42, 13.992\\",\\"0, 0\\",\\"ZO0113901139, ZO0478904789\\",\\"55.969\\",\\"55.969\\",2,2,order,fuzzy +IQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Graves\\",\\"Wagdi Graves\\",MALE,15,Graves,Graves,\\"(empty)\\",Tuesday,1,\\"wagdi@graves-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567135,\\"sold_product_567135_24487, sold_product_567135_13221\\",\\"sold_product_567135_24487, sold_product_567135_13221\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.906, 4.309\\",\\"20.984, 7.988\\",\\"24,487, 13,221\\",\\"Chinos - grey, Print T-shirt - white/dark blue\\",\\"Chinos - grey, Print T-shirt - white/dark blue\\",\\"1, 1\\",\\"ZO0528305283, ZO0549305493\\",\\"0, 0\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"0, 0\\",\\"ZO0528305283, ZO0549305493\\",\\"28.984\\",\\"28.984\\",2,2,order,wagdi +UQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Martin\\",\\"Elyssa Martin\\",FEMALE,27,Martin,Martin,\\"(empty)\\",Tuesday,1,\\"elyssa@martin-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Spherecords Curvy, Gnomehouse\\",\\"Tigress Enterprises, Spherecords Curvy, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",727730,\\"sold_product_727730_17183, sold_product_727730_23436, sold_product_727730_25006, sold_product_727730_19624\\",\\"sold_product_727730_17183, sold_product_727730_23436, sold_product_727730_25006, sold_product_727730_19624\\",\\"28.984, 14.992, 34, 50\\",\\"28.984, 14.992, 34, 50\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Spherecords Curvy, Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Spherecords Curvy, Tigress Enterprises, Gnomehouse\\",\\"13.922, 7.199, 17, 27.484\\",\\"28.984, 14.992, 34, 50\\",\\"17,183, 23,436, 25,006, 19,624\\",\\"Shift dress - black/gold, Blouse - grey, Boots - cognac, Dress - inca gold\\",\\"Shift dress - black/gold, Blouse - grey, Boots - cognac, Dress - inca gold\\",\\"1, 1, 1, 1\\",\\"ZO0050600506, ZO0710907109, ZO0023300233, ZO0334603346\\",\\"0, 0, 0, 0\\",\\"28.984, 14.992, 34, 50\\",\\"28.984, 14.992, 34, 50\\",\\"0, 0, 0, 0\\",\\"ZO0050600506, ZO0710907109, ZO0023300233, ZO0334603346\\",\\"127.938\\",\\"127.938\\",4,4,order,elyssa +ywMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Jimenez\\",\\"Tariq Jimenez\\",MALE,25,Jimenez,Jimenez,\\"(empty)\\",Tuesday,1,\\"tariq@jimenez-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567939,\\"sold_product_567939_12984, sold_product_567939_3061\\",\\"sold_product_567939_12984, sold_product_567939_3061\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"6.352, 12\\",\\"11.992, 24.984\\",\\"12,984, 3,061\\",\\"Scarf - black/grey, Jeans Skinny Fit - dark blue\\",\\"Scarf - black/grey, Jeans Skinny Fit - dark blue\\",\\"1, 1\\",\\"ZO0127201272, ZO0425504255\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0127201272, ZO0425504255\\",\\"36.969\\",\\"36.969\\",2,2,order,tariq +zAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Baker\\",\\"Irwin Baker\\",MALE,14,Baker,Baker,\\"(empty)\\",Tuesday,1,\\"irwin@baker-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567970,\\"sold_product_567970_23856, sold_product_567970_21614\\",\\"sold_product_567970_23856, sold_product_567970_21614\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"5.398, 31.844\\",\\"11.992, 65\\",\\"23,856, 21,614\\",\\"Polo shirt - dark grey multicolor, Casual lace-ups - taupe\\",\\"Polo shirt - dark grey multicolor, Casual lace-ups - taupe\\",\\"1, 1\\",\\"ZO0441504415, ZO0691606916\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0441504415, ZO0691606916\\",77,77,2,2,order,irwin +HgMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Garner\\",\\"Robbie Garner\\",MALE,48,Garner,Garner,\\"(empty)\\",Tuesday,1,\\"robbie@garner-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567301,\\"sold_product_567301_15025, sold_product_567301_24034\\",\\"sold_product_567301_15025, sold_product_567301_24034\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"12.992, 5.711\\",\\"24.984, 10.992\\",\\"15,025, 24,034\\",\\"Jumper - black, Print T-shirt - blue/dark blue\\",\\"Jumper - black, Print T-shirt - blue/dark blue\\",\\"1, 1\\",\\"ZO0577605776, ZO0438104381\\",\\"0, 0\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"0, 0\\",\\"ZO0577605776, ZO0438104381\\",\\"35.969\\",\\"35.969\\",2,2,order,robbie +TgMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Allison\\",\\"Yuri Allison\\",MALE,21,Allison,Allison,\\"(empty)\\",Tuesday,1,\\"yuri@allison-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566801,\\"sold_product_566801_10990, sold_product_566801_11992\\",\\"sold_product_566801_10990, sold_product_566801_11992\\",\\"25.984, 22.984\\",\\"25.984, 22.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.508, 10.813\\",\\"25.984, 22.984\\",\\"10,990, 11,992\\",\\"Shirt - aubergine, Jumper - grey multicolor\\",\\"Shirt - aubergine, Jumper - grey multicolor\\",\\"1, 1\\",\\"ZO0279702797, ZO0573705737\\",\\"0, 0\\",\\"25.984, 22.984\\",\\"25.984, 22.984\\",\\"0, 0\\",\\"ZO0279702797, ZO0573705737\\",\\"48.969\\",\\"48.969\\",2,2,order,yuri +WgMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Goodwin\\",\\"Yuri Goodwin\\",MALE,21,Goodwin,Goodwin,\\"(empty)\\",Tuesday,1,\\"yuri@goodwin-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566685,\\"sold_product_566685_18957, sold_product_566685_20093\\",\\"sold_product_566685_18957, sold_product_566685_20093\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"11.75, 9.656\\",\\"24.984, 20.984\\",\\"18,957, 20,093\\",\\"Jumper - black, Tracksuit bottoms - mottled light grey\\",\\"Jumper - black, Tracksuit bottoms - mottled light grey\\",\\"1, 1\\",\\"ZO0296902969, ZO0530205302\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0296902969, ZO0530205302\\",\\"45.969\\",\\"45.969\\",2,2,order,yuri +WwMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Hansen\\",\\"Mary Hansen\\",FEMALE,20,Hansen,Hansen,\\"(empty)\\",Tuesday,1,\\"mary@hansen-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566924,\\"sold_product_566924_17824, sold_product_566924_24036\\",\\"sold_product_566924_17824, sold_product_566924_24036\\",\\"75, 13.992\\",\\"75, 13.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"35.25, 6.301\\",\\"75, 13.992\\",\\"17,824, 24,036\\",\\"Ankle boots - light brown, Print T-shirt - light grey multicolor\\",\\"Ankle boots - light brown, Print T-shirt - light grey multicolor\\",\\"1, 1\\",\\"ZO0673606736, ZO0161801618\\",\\"0, 0\\",\\"75, 13.992\\",\\"75, 13.992\\",\\"0, 0\\",\\"ZO0673606736, ZO0161801618\\",89,89,2,2,order,mary +cQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Lambert\\",\\"Fitzgerald Lambert\\",MALE,11,Lambert,Lambert,\\"(empty)\\",Tuesday,1,\\"fitzgerald@lambert-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567662,\\"sold_product_567662_24046, sold_product_567662_19131\\",\\"sold_product_567662_24046, sold_product_567662_19131\\",\\"11.992, 33\\",\\"11.992, 33\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"5.762, 16.172\\",\\"11.992, 33\\",\\"24,046, 19,131\\",\\"Hat - black, Neutral running shoes - black/yellow\\",\\"Hat - black, Neutral running shoes - black/yellow\\",\\"1, 1\\",\\"ZO0308903089, ZO0614306143\\",\\"0, 0\\",\\"11.992, 33\\",\\"11.992, 33\\",\\"0, 0\\",\\"ZO0308903089, ZO0614306143\\",\\"44.969\\",\\"44.969\\",2,2,order,fuzzy +cgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Mary,Mary,\\"Mary Reese\\",\\"Mary Reese\\",FEMALE,20,Reese,Reese,\\"(empty)\\",Tuesday,1,\\"mary@reese-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567708,\\"sold_product_567708_21991, sold_product_567708_14420\\",\\"sold_product_567708_21991, sold_product_567708_14420\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"12.492, 19.313\\",\\"24.984, 42\\",\\"21,991, 14,420\\",\\"Rucksack - black, Across body bag - black\\",\\"Rucksack - black, Across body bag - black\\",\\"1, 1\\",\\"ZO0090500905, ZO0466204662\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0090500905, ZO0466204662\\",67,67,2,2,order,mary +yQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Dennis\\",\\"Gwen Dennis\\",FEMALE,26,Dennis,Dennis,\\"(empty)\\",Tuesday,1,\\"gwen@dennis-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567573,\\"sold_product_567573_18097, sold_product_567573_23199\\",\\"sold_product_567573_18097, sold_product_567573_23199\\",\\"11.992, 42\\",\\"11.992, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"5.879, 20.156\\",\\"11.992, 42\\",\\"18,097, 23,199\\",\\"7 PACK - Socks - multicoloured, Dress - navy blazer\\",\\"7 PACK - Socks - multicoloured, Dress - navy blazer\\",\\"1, 1\\",\\"ZO0215602156, ZO0336803368\\",\\"0, 0\\",\\"11.992, 42\\",\\"11.992, 42\\",\\"0, 0\\",\\"ZO0215602156, ZO0336803368\\",\\"53.969\\",\\"53.969\\",2,2,order,gwen +AQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Banks\\",\\"Jackson Banks\\",MALE,13,Banks,Banks,\\"(empty)\\",Tuesday,1,\\"jackson@banks-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Angeldale, Elitelligence, Low Tide Media\\",\\"Angeldale, Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",717603,\\"sold_product_717603_12011, sold_product_717603_6533, sold_product_717603_6991, sold_product_717603_6182\\",\\"sold_product_717603_12011, sold_product_717603_6533, sold_product_717603_6991, sold_product_717603_6182\\",\\"55, 28.984, 38, 10.992\\",\\"55, 28.984, 38, 10.992\\",\\"Men's Shoes, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Elitelligence, Low Tide Media, Elitelligence\\",\\"Angeldale, Elitelligence, Low Tide Media, Elitelligence\\",\\"28.047, 13.344, 20.125, 5.82\\",\\"55, 28.984, 38, 10.992\\",\\"12,011, 6,533, 6,991, 6,182\\",\\"Slip-ons - black, Sweatshirt - black/white/mottled grey, Jumper - dark blue, Print T-shirt - white\\",\\"Slip-ons - black, Sweatshirt - black/white/mottled grey, Jumper - dark blue, Print T-shirt - white\\",\\"1, 1, 1, 1\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\",\\"0, 0, 0, 0\\",\\"55, 28.984, 38, 10.992\\",\\"55, 28.984, 38, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\",133,133,4,4,order,jackson +HQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Padilla\\",\\"Wilhemina St. Padilla\\",FEMALE,17,Padilla,Padilla,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@padilla-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566986,\\"sold_product_566986_11438, sold_product_566986_5014\\",\\"sold_product_566986_11438, sold_product_566986_5014\\",\\"75, 33\\",\\"75, 33\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"39.75, 15.18\\",\\"75, 33\\",\\"11,438, 5,014\\",\\"High heeled sandals - Midnight Blue, Boots - cognac\\",\\"High heeled sandals - Midnight Blue, Boots - cognac\\",\\"1, 1\\",\\"ZO0360903609, ZO0030100301\\",\\"0, 0\\",\\"75, 33\\",\\"75, 33\\",\\"0, 0\\",\\"ZO0360903609, ZO0030100301\\",108,108,2,2,order,wilhemina +HgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Rice\\",\\"Clarice Rice\\",FEMALE,18,Rice,Rice,\\"(empty)\\",Tuesday,1,\\"clarice@rice-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566735,\\"sold_product_566735_24785, sold_product_566735_19239\\",\\"sold_product_566735_24785, sold_product_566735_19239\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"9.172, 12.992\\",\\"16.984, 24.984\\",\\"24,785, 19,239\\",\\"Tracksuit bottoms - dark grey multicolor, Long sleeved top - black\\",\\"Tracksuit bottoms - dark grey multicolor, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0632406324, ZO0060300603\\",\\"0, 0\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"0, 0\\",\\"ZO0632406324, ZO0060300603\\",\\"41.969\\",\\"41.969\\",2,2,order,clarice +HwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Mostafa,Mostafa,\\"Mostafa Conner\\",\\"Mostafa Conner\\",MALE,9,Conner,Conner,\\"(empty)\\",Tuesday,1,\\"mostafa@conner-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567082,\\"sold_product_567082_18373, sold_product_567082_15037\\",\\"sold_product_567082_18373, sold_product_567082_15037\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.492, 12.992\\",\\"24.984, 24.984\\",\\"18,373, 15,037\\",\\"Shirt - grey, Trainers - dusty blue\\",\\"Shirt - grey, Trainers - dusty blue\\",\\"1, 1\\",\\"ZO0278802788, ZO0515605156\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0278802788, ZO0515605156\\",\\"49.969\\",\\"49.969\\",2,2,order,mostafa +IAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Potter\\",\\"Irwin Potter\\",MALE,14,Potter,Potter,\\"(empty)\\",Tuesday,1,\\"irwin@potter-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566881,\\"sold_product_566881_16129, sold_product_566881_19224\\",\\"sold_product_566881_16129, sold_product_566881_19224\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"12.492, 8.094\\",\\"24.984, 14.992\\",\\"16,129, 19,224\\",\\"Trousers - navy, Long sleeved top - white/blue/red\\",\\"Trousers - navy, Long sleeved top - white/blue/red\\",\\"1, 1\\",\\"ZO0419604196, ZO0559705597\\",\\"0, 0\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"0, 0\\",\\"ZO0419604196, ZO0559705597\\",\\"39.969\\",\\"39.969\\",2,2,order,irwin +YwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Reese\\",\\"Mary Reese\\",FEMALE,20,Reese,Reese,\\"(empty)\\",Tuesday,1,\\"mary@reese-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Spherecords\\",\\"Angeldale, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566790,\\"sold_product_566790_18851, sold_product_566790_22361\\",\\"sold_product_566790_18851, sold_product_566790_22361\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spherecords\\",\\"Angeldale, Spherecords\\",\\"31.844, 4.949\\",\\"65, 10.992\\",\\"18,851, 22,361\\",\\"Tote bag - black, Long sleeved top - black\\",\\"Tote bag - black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0699206992, ZO0641306413\\",\\"0, 0\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"0, 0\\",\\"ZO0699206992, ZO0641306413\\",76,76,2,2,order,mary +bwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Gomez\\",\\"Eddie Gomez\\",MALE,38,Gomez,Gomez,\\"(empty)\\",Tuesday,1,\\"eddie@gomez-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566706,\\"sold_product_566706_1717, sold_product_566706_17829\\",\\"sold_product_566706_1717, sold_product_566706_17829\\",\\"46, 10.992\\",\\"46, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"23.453, 5.602\\",\\"46, 10.992\\",\\"1,717, 17,829\\",\\"Boots - grey, 3 PACK - Socks - khaki/grey\\",\\"Boots - grey, 3 PACK - Socks - khaki/grey\\",\\"1, 1\\",\\"ZO0521505215, ZO0130501305\\",\\"0, 0\\",\\"46, 10.992\\",\\"46, 10.992\\",\\"0, 0\\",\\"ZO0521505215, ZO0130501305\\",\\"56.969\\",\\"56.969\\",2,2,order,eddie +cAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Phil,Phil,\\"Phil Boone\\",\\"Phil Boone\\",MALE,50,Boone,Boone,\\"(empty)\\",Tuesday,1,\\"phil@boone-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566935,\\"sold_product_566935_7024, sold_product_566935_20507\\",\\"sold_product_566935_7024, sold_product_566935_20507\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"9, 15.938\\",\\"16.984, 28.984\\",\\"7,024, 20,507\\",\\"3 PACK - Basic T-shirt - white/black/grey, Jumper - dark green\\",\\"3 PACK - Basic T-shirt - white/black/grey, Jumper - dark green\\",\\"1, 1\\",\\"ZO0473704737, ZO0121501215\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0473704737, ZO0121501215\\",\\"45.969\\",\\"45.969\\",2,2,order,phil +cQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Burton\\",\\"Selena Burton\\",FEMALE,42,Burton,Burton,\\"(empty)\\",Tuesday,1,\\"selena@burton-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566985,\\"sold_product_566985_18522, sold_product_566985_22213\\",\\"sold_product_566985_18522, sold_product_566985_22213\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"25.484, 12.742\\",\\"50, 24.984\\",\\"18,522, 22,213\\",\\"Cocktail dress / Party dress - taupe, Sweatshirt - blue\\",\\"Cocktail dress / Party dress - taupe, Sweatshirt - blue\\",\\"1, 1\\",\\"ZO0044700447, ZO0502105021\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0044700447, ZO0502105021\\",75,75,2,2,order,selena +cgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Clayton\\",\\"Eddie Clayton\\",MALE,38,Clayton,Clayton,\\"(empty)\\",Tuesday,1,\\"eddie@clayton-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566729,\\"sold_product_566729_23918, sold_product_566729_11251\\",\\"sold_product_566729_23918, sold_product_566729_11251\\",\\"7.988, 28.984\\",\\"7.988, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"4.148, 13.633\\",\\"7.988, 28.984\\",\\"23,918, 11,251\\",\\"Print T-shirt - red, Shirt - red/black\\",\\"Print T-shirt - red, Shirt - red/black\\",\\"1, 1\\",\\"ZO0557305573, ZO0110401104\\",\\"0, 0\\",\\"7.988, 28.984\\",\\"7.988, 28.984\\",\\"0, 0\\",\\"ZO0557305573, ZO0110401104\\",\\"36.969\\",\\"36.969\\",2,2,order,eddie +cwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Gwen,Gwen,\\"Gwen Weber\\",\\"Gwen Weber\\",FEMALE,26,Weber,Weber,\\"(empty)\\",Tuesday,1,\\"gwen@weber-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567095,\\"sold_product_567095_18015, sold_product_567095_16489\\",\\"sold_product_567095_18015, sold_product_567095_16489\\",\\"60, 16.984\\",\\"60, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"30, 7.82\\",\\"60, 16.984\\",\\"18,015, 16,489\\",\\"Summer dress - blue fog, Clutch - red \\",\\"Summer dress - blue fog, Clutch - red \\",\\"1, 1\\",\\"ZO0339803398, ZO0098200982\\",\\"0, 0\\",\\"60, 16.984\\",\\"60, 16.984\\",\\"0, 0\\",\\"ZO0339803398, ZO0098200982\\",77,77,2,2,order,gwen +igMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Shaw\\",\\"Elyssa Shaw\\",FEMALE,27,Shaw,Shaw,\\"(empty)\\",Tuesday,1,\\"elyssa@shaw-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Champion Arts, Spherecords, Gnomehouse, Angeldale\\",\\"Champion Arts, Spherecords, Gnomehouse, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",724326,\\"sold_product_724326_10916, sold_product_724326_19683, sold_product_724326_24375, sold_product_724326_22263\\",\\"sold_product_724326_10916, sold_product_724326_19683, sold_product_724326_24375, sold_product_724326_22263\\",\\"20.984, 10.992, 42, 75\\",\\"20.984, 10.992, 42, 75\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Champion Arts, Spherecords, Gnomehouse, Angeldale\\",\\"Champion Arts, Spherecords, Gnomehouse, Angeldale\\",\\"10.906, 5.82, 22.672, 35.25\\",\\"20.984, 10.992, 42, 75\\",\\"10,916, 19,683, 24,375, 22,263\\",\\"Sweatshirt - black, 2 PACK - Vest - black/white, Summer dress - soft pink, Platform boots - black\\",\\"Sweatshirt - black, 2 PACK - Vest - black/white, Summer dress - soft pink, Platform boots - black\\",\\"1, 1, 1, 1\\",\\"ZO0499404994, ZO0641606416, ZO0334303343, ZO0676706767\\",\\"0, 0, 0, 0\\",\\"20.984, 10.992, 42, 75\\",\\"20.984, 10.992, 42, 75\\",\\"0, 0, 0, 0\\",\\"ZO0499404994, ZO0641606416, ZO0334303343, ZO0676706767\\",149,149,4,4,order,elyssa +DAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Cunningham\\",\\"Ahmed Al Cunningham\\",MALE,4,Cunningham,Cunningham,\\"(empty)\\",Tuesday,1,\\"ahmed al@cunningham-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567806,\\"sold_product_567806_17139, sold_product_567806_14215\\",\\"sold_product_567806_17139, sold_product_567806_14215\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.328, 5.641\\",\\"20.984, 11.992\\",\\"17,139, 14,215\\",\\"Trainers - grey, Print T-shirt - black\\",\\"Trainers - grey, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0517705177, ZO0569305693\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0517705177, ZO0569305693\\",\\"32.969\\",\\"32.969\\",2,2,order,ahmed +fAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Clarice,Clarice,\\"Clarice Walters\\",\\"Clarice Walters\\",FEMALE,18,Walters,Walters,\\"(empty)\\",Tuesday,1,\\"clarice@walters-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567973,\\"sold_product_567973_24178, sold_product_567973_13294\\",\\"sold_product_567973_24178, sold_product_567973_13294\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"5.762, 34.438\\",\\"11.992, 65\\",\\"24,178, 13,294\\",\\"Print T-shirt - white, Tote bag - Blue Violety\\",\\"Print T-shirt - white, Tote bag - Blue Violety\\",\\"1, 1\\",\\"ZO0495104951, ZO0305903059\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0495104951, ZO0305903059\\",77,77,2,2,order,clarice +qQMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Harper\\",\\"Rabbia Al Harper\\",FEMALE,5,Harper,Harper,\\"(empty)\\",Tuesday,1,\\"rabbia al@harper-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Pyramidustries active\\",\\"Angeldale, Pyramidustries active\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567341,\\"sold_product_567341_5526, sold_product_567341_18975\\",\\"sold_product_567341_5526, sold_product_567341_18975\\",\\"90, 17.984\\",\\"90, 17.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries active\\",\\"Angeldale, Pyramidustries active\\",\\"47.688, 8.992\\",\\"90, 17.984\\",\\"5,526, 18,975\\",\\"Boots - black, Long sleeved top - black\\",\\"Boots - black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0674506745, ZO0219202192\\",\\"0, 0\\",\\"90, 17.984\\",\\"90, 17.984\\",\\"0, 0\\",\\"ZO0674506745, ZO0219202192\\",108,108,2,2,order,rabbia +tQMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Shaw\\",\\"Kamal Shaw\\",MALE,39,Shaw,Shaw,\\"(empty)\\",Tuesday,1,\\"kamal@shaw-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567492,\\"sold_product_567492_14648, sold_product_567492_12310\\",\\"sold_product_567492_14648, sold_product_567492_12310\\",\\"13.992, 17.984\\",\\"13.992, 17.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"6.719, 9.352\\",\\"13.992, 17.984\\",\\"14,648, 12,310\\",\\"Tie - dark grey, Polo shirt - grey\\",\\"Tie - dark grey, Polo shirt - grey\\",\\"1, 1\\",\\"ZO0277302773, ZO0443004430\\",\\"0, 0\\",\\"13.992, 17.984\\",\\"13.992, 17.984\\",\\"0, 0\\",\\"ZO0277302773, ZO0443004430\\",\\"31.984\\",\\"31.984\\",2,2,order,kamal +tgMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Jenkins\\",\\"Irwin Jenkins\\",MALE,14,Jenkins,Jenkins,\\"(empty)\\",Tuesday,1,\\"irwin@jenkins-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567654,\\"sold_product_567654_22409, sold_product_567654_1312\\",\\"sold_product_567654_22409, sold_product_567654_1312\\",\\"11.992, 50\\",\\"11.992, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"5.762, 24\\",\\"11.992, 50\\",\\"22,409, 1,312\\",\\"Basic T-shirt - Dark Salmon, Lace-up boots - black\\",\\"Basic T-shirt - Dark Salmon, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0121301213, ZO0399403994\\",\\"0, 0\\",\\"11.992, 50\\",\\"11.992, 50\\",\\"0, 0\\",\\"ZO0121301213, ZO0399403994\\",\\"61.969\\",\\"61.969\\",2,2,order,irwin +uAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Rivera\\",\\"Betty Rivera\\",FEMALE,44,Rivera,Rivera,\\"(empty)\\",Tuesday,1,\\"betty@rivera-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567403,\\"sold_product_567403_20386, sold_product_567403_23991\\",\\"sold_product_567403_20386, sold_product_567403_23991\\",\\"60, 42\\",\\"60, 42\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"30, 19.313\\",\\"60, 42\\",\\"20,386, 23,991\\",\\"Over-the-knee boots - cognac, Trousers - black\\",\\"Over-the-knee boots - cognac, Trousers - black\\",\\"1, 1\\",\\"ZO0138601386, ZO0259202592\\",\\"0, 0\\",\\"60, 42\\",\\"60, 42\\",\\"0, 0\\",\\"ZO0138601386, ZO0259202592\\",102,102,2,2,order,betty +DgMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Hampton\\",\\"Mary Hampton\\",FEMALE,20,Hampton,Hampton,\\"(empty)\\",Tuesday,1,\\"mary@hampton-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Microlutions\\",\\"Tigress Enterprises, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567207,\\"sold_product_567207_17489, sold_product_567207_14916\\",\\"sold_product_567207_17489, sold_product_567207_14916\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Microlutions\\",\\"Tigress Enterprises, Microlutions\\",\\"12, 28.203\\",\\"24.984, 60\\",\\"17,489, 14,916\\",\\"Denim skirt - dark blue denim, Bomber Jacket - black\\",\\"Denim skirt - dark blue denim, Bomber Jacket - black\\",\\"1, 1\\",\\"ZO0033600336, ZO0109401094\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0033600336, ZO0109401094\\",85,85,2,2,order,mary +DwMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Hopkins\\",\\"Jackson Hopkins\\",MALE,13,Hopkins,Hopkins,\\"(empty)\\",Tuesday,1,\\"jackson@hopkins-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567356,\\"sold_product_567356_13525, sold_product_567356_11169\\",\\"sold_product_567356_13525, sold_product_567356_11169\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"24.5, 5.602\\",\\"50, 10.992\\",\\"13,525, 11,169\\",\\"Weekend bag - sand, Tie - grey\\",\\"Weekend bag - sand, Tie - grey\\",\\"1, 1\\",\\"ZO0319503195, ZO0409904099\\",\\"0, 0\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"0, 0\\",\\"ZO0319503195, ZO0409904099\\",\\"60.969\\",\\"60.969\\",2,2,order,jackson +0wMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Rios\\",\\"Oliver Rios\\",MALE,7,Rios,Rios,\\"(empty)\\",Monday,0,\\"oliver@rios-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565855,\\"sold_product_565855_19919, sold_product_565855_24502\\",\\"sold_product_565855_19919, sold_product_565855_24502\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"9.867, 12.492\\",\\"20.984, 24.984\\",\\"19,919, 24,502\\",\\"Shirt - dark blue white, Slim fit jeans - raw blue\\",\\"Shirt - dark blue white, Slim fit jeans - raw blue\\",\\"1, 1\\",\\"ZO0417504175, ZO0535205352\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0417504175, ZO0535205352\\",\\"45.969\\",\\"45.969\\",2,2,order,oliver +NgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Ball\\",\\"Sultan Al Ball\\",MALE,19,Ball,Ball,\\"(empty)\\",Monday,0,\\"sultan al@ball-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",565915,\\"sold_product_565915_13822, sold_product_565915_13150\\",\\"sold_product_565915_13822, sold_product_565915_13150\\",\\"42, 16.984\\",\\"42, 16.984\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"21, 9\\",\\"42, 16.984\\",\\"13,822, 13,150\\",\\"High-top trainers - black, High-top trainers - brown\\",\\"High-top trainers - black, High-top trainers - brown\\",\\"1, 1\\",\\"ZO0515005150, ZO0509805098\\",\\"0, 0\\",\\"42, 16.984\\",\\"42, 16.984\\",\\"0, 0\\",\\"ZO0515005150, ZO0509805098\\",\\"58.969\\",\\"58.969\\",2,2,order,sultan +SAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Dixon\\",\\"Elyssa Dixon\\",FEMALE,27,Dixon,Dixon,\\"(empty)\\",Monday,0,\\"elyssa@dixon-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566343,\\"sold_product_566343_16050, sold_product_566343_14327\\",\\"sold_product_566343_16050, sold_product_566343_14327\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"14.781, 22.25\\",\\"28.984, 42\\",\\"16,050, 14,327\\",\\"Winter jacket - black, Summer dress - black/Chocolate\\",\\"Winter jacket - black, Summer dress - black/Chocolate\\",\\"1, 1\\",\\"ZO0185101851, ZO0052800528\\",\\"0, 0\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"0, 0\\",\\"ZO0185101851, ZO0052800528\\",71,71,2,2,order,elyssa +SQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Ball\\",\\"Gwen Ball\\",FEMALE,26,Ball,Ball,\\"(empty)\\",Monday,0,\\"gwen@ball-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566400,\\"sold_product_566400_18643, sold_product_566400_24426\\",\\"sold_product_566400_18643, sold_product_566400_24426\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"9.867, 13.633\\",\\"20.984, 28.984\\",\\"18,643, 24,426\\",\\"Handbag - Blue Violety, Slip-ons - nude\\",\\"Handbag - Blue Violety, Slip-ons - nude\\",\\"1, 1\\",\\"ZO0204702047, ZO0009600096\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0204702047, ZO0009600096\\",\\"49.969\\",\\"49.969\\",2,2,order,gwen +aAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Palmer\\",\\"Gwen Palmer\\",FEMALE,26,Palmer,Palmer,\\"(empty)\\",Monday,0,\\"gwen@palmer-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,Gnomehouse,Gnomehouse,\\"Jun 23, 2019 @ 00:00:00.000\\",565776,\\"sold_product_565776_23882, sold_product_565776_8692\\",\\"sold_product_565776_23882, sold_product_565776_8692\\",\\"33, 29.984\\",\\"33, 29.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"16.813, 13.797\\",\\"33, 29.984\\",\\"23,882, 8,692\\",\\"Long sleeved top - chinese red, Blouse - blue fog\\",\\"Long sleeved top - chinese red, Blouse - blue fog\\",\\"1, 1\\",\\"ZO0343103431, ZO0345803458\\",\\"0, 0\\",\\"33, 29.984\\",\\"33, 29.984\\",\\"0, 0\\",\\"ZO0343103431, ZO0345803458\\",\\"62.969\\",\\"62.969\\",2,2,order,gwen +bgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Greer\\",\\"Yuri Greer\\",MALE,21,Greer,Greer,\\"(empty)\\",Monday,0,\\"yuri@greer-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566607,\\"sold_product_566607_3014, sold_product_566607_18884\\",\\"sold_product_566607_3014, sold_product_566607_18884\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.492, 9.656\\",\\"20.984, 20.984\\",\\"3,014, 18,884\\",\\"Cardigan - grey multicolor, Sweatshirt - black /white\\",\\"Cardigan - grey multicolor, Sweatshirt - black /white\\",\\"1, 1\\",\\"ZO0572205722, ZO0585205852\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0572205722, ZO0585205852\\",\\"41.969\\",\\"41.969\\",2,2,order,yuri +jgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Cortez\\",\\"Elyssa Cortez\\",FEMALE,27,Cortez,Cortez,\\"(empty)\\",Monday,0,\\"elyssa@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565452,\\"sold_product_565452_22934, sold_product_565452_13388\\",\\"sold_product_565452_22934, sold_product_565452_13388\\",\\"42, 14.992\\",\\"42, 14.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"22.25, 7.352\\",\\"42, 14.992\\",\\"22,934, 13,388\\",\\"High heels - black, 2 PACK - Vest - white/dark blue/dark blue\\",\\"High heels - black, 2 PACK - Vest - white/dark blue/dark blue\\",\\"1, 1\\",\\"ZO0133601336, ZO0643906439\\",\\"0, 0\\",\\"42, 14.992\\",\\"42, 14.992\\",\\"0, 0\\",\\"ZO0133601336, ZO0643906439\\",\\"56.969\\",\\"56.969\\",2,2,order,elyssa +kQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Smith\\",\\"Abigail Smith\\",FEMALE,46,Smith,Smith,\\"(empty)\\",Monday,0,\\"abigail@smith-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566051,\\"sold_product_566051_16134, sold_product_566051_23328\\",\\"sold_product_566051_16134, sold_product_566051_23328\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"13.492, 26.484\\",\\"24.984, 50\\",\\"16,134, 23,328\\",\\"Cowboy/Biker boots - light grey, Blazer - black\\",\\"Cowboy/Biker boots - light grey, Blazer - black\\",\\"1, 1\\",\\"ZO0025600256, ZO0270202702\\",\\"0, 0\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"0, 0\\",\\"ZO0025600256, ZO0270202702\\",75,75,2,2,order,abigail +qgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Mccarthy\\",\\"Sultan Al Mccarthy\\",MALE,19,Mccarthy,Mccarthy,\\"(empty)\\",Monday,0,\\"sultan al@mccarthy-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565466,\\"sold_product_565466_10951, sold_product_565466_11989\\",\\"sold_product_565466_10951, sold_product_565466_11989\\",\\"42, 45\\",\\"42, 45\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"19.313, 24.734\\",\\"42, 45\\",\\"10,951, 11,989\\",\\"Summer jacket - navy, Light jacket - khaki\\",\\"Summer jacket - navy, Light jacket - khaki\\",\\"1, 1\\",\\"ZO0285402854, ZO0538605386\\",\\"0, 0\\",\\"42, 45\\",\\"42, 45\\",\\"0, 0\\",\\"ZO0285402854, ZO0538605386\\",87,87,2,2,order,sultan +9gMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Riley\\",\\"Mostafa Riley\\",MALE,9,Riley,Riley,\\"(empty)\\",Monday,0,\\"mostafa@riley-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566553,\\"sold_product_566553_18385, sold_product_566553_15343\\",\\"sold_product_566553_18385, sold_product_566553_15343\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"4.07, 32.375\\",\\"7.988, 60\\",\\"18,385, 15,343\\",\\"Basic T-shirt - dark grey multicolor, Parka - khaki\\",\\"Basic T-shirt - dark grey multicolor, Parka - khaki\\",\\"1, 1\\",\\"ZO0435004350, ZO0544005440\\",\\"0, 0\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"0, 0\\",\\"ZO0435004350, ZO0544005440\\",68,68,2,2,order,mostafa +AQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Wolfe\\",\\"Yasmine Wolfe\\",FEMALE,43,Wolfe,Wolfe,\\"(empty)\\",Monday,0,\\"yasmine@wolfe-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565446,\\"sold_product_565446_12090, sold_product_565446_12122\\",\\"sold_product_565446_12090, sold_product_565446_12122\\",\\"11.992, 29.984\\",\\"11.992, 29.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.641, 15.594\\",\\"11.992, 29.984\\",\\"12,090, 12,122\\",\\"Long sleeved top - black, Winter boots - black\\",\\"Long sleeved top - black, Winter boots - black\\",\\"1, 1\\",\\"ZO0643206432, ZO0140101401\\",\\"0, 0\\",\\"11.992, 29.984\\",\\"11.992, 29.984\\",\\"0, 0\\",\\"ZO0643206432, ZO0140101401\\",\\"41.969\\",\\"41.969\\",2,2,order,yasmine +MQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Carpenter\\",\\"Wagdi Carpenter\\",MALE,15,Carpenter,Carpenter,\\"(empty)\\",Monday,0,\\"wagdi@carpenter-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Oceanavigations,Oceanavigations,\\"Jun 23, 2019 @ 00:00:00.000\\",566053,\\"sold_product_566053_2650, sold_product_566053_21018\\",\\"sold_product_566053_2650, sold_product_566053_21018\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"13.344, 9.867\\",\\"28.984, 20.984\\",\\"2,650, 21,018\\",\\"Slim fit jeans - black, Jumper - charcoal\\",\\"Slim fit jeans - black, Jumper - charcoal\\",\\"1, 1\\",\\"ZO0284702847, ZO0299202992\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0284702847, ZO0299202992\\",\\"49.969\\",\\"49.969\\",2,2,order,wagdi +UgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Schultz\\",\\"Jackson Schultz\\",MALE,13,Schultz,Schultz,\\"(empty)\\",Monday,0,\\"jackson@schultz-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565605,\\"sold_product_565605_24934, sold_product_565605_22732\\",\\"sold_product_565605_24934, sold_product_565605_22732\\",\\"50, 33\\",\\"50, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"22.5, 16.172\\",\\"50, 33\\",\\"24,934, 22,732\\",\\"Lace-up boots - resin coffee, Relaxed fit jeans - black denim\\",\\"Lace-up boots - resin coffee, Relaxed fit jeans - black denim\\",\\"1, 1\\",\\"ZO0403504035, ZO0113301133\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0403504035, ZO0113301133\\",83,83,2,2,order,jackson +lAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Phelps\\",\\"Abigail Phelps\\",FEMALE,46,Phelps,Phelps,\\"(empty)\\",Monday,0,\\"abigail@phelps-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Gnomehouse, Karmanite\\",\\"Gnomehouse, Karmanite\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566170,\\"sold_product_566170_7278, sold_product_566170_5214\\",\\"sold_product_566170_7278, sold_product_566170_5214\\",\\"65, 85\\",\\"65, 85\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Karmanite\\",\\"Gnomehouse, Karmanite\\",\\"31.844, 43.344\\",\\"65, 85\\",\\"7,278, 5,214\\",\\"Boots - navy, Ankle boots - wood\\",\\"Boots - navy, Ankle boots - wood\\",\\"1, 1\\",\\"ZO0324803248, ZO0703907039\\",\\"0, 0\\",\\"65, 85\\",\\"65, 85\\",\\"0, 0\\",\\"ZO0324803248, ZO0703907039\\",150,150,2,2,order,abigail +lQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Perkins\\",\\"Abd Perkins\\",MALE,52,Perkins,Perkins,\\"(empty)\\",Monday,0,\\"abd@perkins-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566187,\\"sold_product_566187_12028, sold_product_566187_21937\\",\\"sold_product_566187_12028, sold_product_566187_21937\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.92, 12.742\\",\\"7.988, 24.984\\",\\"12,028, 21,937\\",\\"Vest - light blue multicolor, Sweatshirt - navy multicolor\\",\\"Vest - light blue multicolor, Sweatshirt - navy multicolor\\",\\"1, 1\\",\\"ZO0548905489, ZO0459404594\\",\\"0, 0\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"0, 0\\",\\"ZO0548905489, ZO0459404594\\",\\"32.969\\",\\"32.969\\",2,2,order,abd +lgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Frances,Frances,\\"Frances Love\\",\\"Frances Love\\",FEMALE,49,Love,Love,\\"(empty)\\",Monday,0,\\"frances@love-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566125,\\"sold_product_566125_14168, sold_product_566125_13612\\",\\"sold_product_566125_14168, sold_product_566125_13612\\",\\"100, 11.992\\",\\"100, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"48, 6.469\\",\\"100, 11.992\\",\\"14,168, 13,612\\",\\"Classic coat - grey, Basic T-shirt - light red/white\\",\\"Classic coat - grey, Basic T-shirt - light red/white\\",\\"1, 1\\",\\"ZO0433104331, ZO0549505495\\",\\"0, 0\\",\\"100, 11.992\\",\\"100, 11.992\\",\\"0, 0\\",\\"ZO0433104331, ZO0549505495\\",112,112,2,2,order,frances +lwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Butler\\",\\"Mostafa Butler\\",MALE,9,Butler,Butler,\\"(empty)\\",Monday,0,\\"mostafa@butler-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566156,\\"sold_product_566156_17644, sold_product_566156_17414\\",\\"sold_product_566156_17644, sold_product_566156_17414\\",\\"60, 16.984\\",\\"60, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"29.406, 7.648\\",\\"60, 16.984\\",\\"17,644, 17,414\\",\\"Suit jacket - dark blue, Print T-shirt - black\\",\\"Suit jacket - dark blue, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0424104241, ZO0117901179\\",\\"0, 0\\",\\"60, 16.984\\",\\"60, 16.984\\",\\"0, 0\\",\\"ZO0424104241, ZO0117901179\\",77,77,2,2,order,mostafa +mAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Stephanie,Stephanie,\\"Stephanie Mckenzie\\",\\"Stephanie Mckenzie\\",FEMALE,6,Mckenzie,Mckenzie,\\"(empty)\\",Monday,0,\\"stephanie@mckenzie-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566100,\\"sold_product_566100_15198, sold_product_566100_22284\\",\\"sold_product_566100_15198, sold_product_566100_22284\\",\\"50, 65\\",\\"50, 65\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"25.484, 31.203\\",\\"50, 65\\",\\"15,198, 22,284\\",\\"Boots - taupe, Classic heels - black\\",\\"Boots - taupe, Classic heels - black\\",\\"1, 1\\",\\"ZO0013400134, ZO0667306673\\",\\"0, 0\\",\\"50, 65\\",\\"50, 65\\",\\"0, 0\\",\\"ZO0013400134, ZO0667306673\\",115,115,2,2,order,stephanie +mQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Boone\\",\\"George Boone\\",MALE,32,Boone,Boone,\\"(empty)\\",Monday,0,\\"george@boone-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566280,\\"sold_product_566280_11862, sold_product_566280_11570\\",\\"sold_product_566280_11862, sold_product_566280_11570\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"11.492, 9.172\\",\\"22.984, 16.984\\",\\"11,862, 11,570\\",\\"Jumper - black, Print T-shirt - beige\\",\\"Jumper - black, Print T-shirt - beige\\",\\"1, 1\\",\\"ZO0573205732, ZO0116701167\\",\\"0, 0\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"0, 0\\",\\"ZO0573205732, ZO0116701167\\",\\"39.969\\",\\"39.969\\",2,2,order,george +mgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Youssef,Youssef,\\"Youssef Alvarez\\",\\"Youssef Alvarez\\",MALE,31,Alvarez,Alvarez,\\"(empty)\\",Monday,0,\\"youssef@alvarez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565708,\\"sold_product_565708_24246, sold_product_565708_11444\\",\\"sold_product_565708_24246, sold_product_565708_11444\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"33.781, 13.742\\",\\"65, 24.984\\",\\"24,246, 11,444\\",\\"Lace-up boots - black, Rucksack - black/cognac\\",\\"Lace-up boots - black, Rucksack - black/cognac\\",\\"1, 1\\",\\"ZO0253302533, ZO0605706057\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0253302533, ZO0605706057\\",90,90,2,2,order,youssef +tgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Thad,Thad,\\"Thad Taylor\\",\\"Thad Taylor\\",MALE,30,Taylor,Taylor,\\"(empty)\\",Monday,0,\\"thad@taylor-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",565809,\\"sold_product_565809_18321, sold_product_565809_19707\\",\\"sold_product_565809_18321, sold_product_565809_19707\\",\\"12.992, 20.984\\",\\"12.992, 20.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"7.141, 10.289\\",\\"12.992, 20.984\\",\\"18,321, 19,707\\",\\"Vest - white/grey, Trainers - black\\",\\"Vest - white/grey, Trainers - black\\",\\"1, 1\\",\\"ZO0557905579, ZO0513705137\\",\\"0, 0\\",\\"12.992, 20.984\\",\\"12.992, 20.984\\",\\"0, 0\\",\\"ZO0557905579, ZO0513705137\\",\\"33.969\\",\\"33.969\\",2,2,order,thad +twMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Daniels\\",\\"Clarice Daniels\\",FEMALE,18,Daniels,Daniels,\\"(empty)\\",Monday,0,\\"clarice@daniels-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Pyramidustries active, Angeldale\\",\\"Pyramidustries active, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566256,\\"sold_product_566256_9787, sold_product_566256_18737\\",\\"sold_product_566256_9787, sold_product_566256_18737\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Angeldale\\",\\"Pyramidustries active, Angeldale\\",\\"12.992, 31.844\\",\\"24.984, 65\\",\\"9,787, 18,737\\",\\"Sweatshirt - duffle bag, Lace-ups - black\\",\\"Sweatshirt - duffle bag, Lace-ups - black\\",\\"1, 1\\",\\"ZO0227302273, ZO0668706687\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0227302273, ZO0668706687\\",90,90,2,2,order,clarice +GgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Chapman\\",\\"Elyssa Chapman\\",FEMALE,27,Chapman,Chapman,\\"(empty)\\",Monday,0,\\"elyssa@chapman-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565639,\\"sold_product_565639_15334, sold_product_565639_18810\\",\\"sold_product_565639_15334, sold_product_565639_18810\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"5.762, 6.578\\",\\"11.992, 13.992\\",\\"15,334, 18,810\\",\\"Scarf - bordeaux, Wallet - dark turquoise\\",\\"Scarf - bordeaux, Wallet - dark turquoise\\",\\"1, 1\\",\\"ZO0193901939, ZO0080400804\\",\\"0, 0\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"0, 0\\",\\"ZO0193901939, ZO0080400804\\",\\"25.984\\",\\"25.984\\",2,2,order,elyssa +GwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Roberson\\",\\"Eddie Roberson\\",MALE,38,Roberson,Roberson,\\"(empty)\\",Monday,0,\\"eddie@roberson-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565684,\\"sold_product_565684_11098, sold_product_565684_11488\\",\\"sold_product_565684_11098, sold_product_565684_11488\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"8.656, 5.059\\",\\"16.984, 10.992\\",\\"11,098, 11,488\\",\\"Trainers - Blue Violety, Tie - black\\",\\"Trainers - Blue Violety, Tie - black\\",\\"1, 1\\",\\"ZO0507705077, ZO0409804098\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0507705077, ZO0409804098\\",\\"27.984\\",\\"27.984\\",2,2,order,eddie +ngMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty King\\",\\"Betty King\\",FEMALE,44,King,King,\\"(empty)\\",Monday,0,\\"betty@king-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Oceanavigations,Oceanavigations,\\"Jun 23, 2019 @ 00:00:00.000\\",565945,\\"sold_product_565945_13129, sold_product_565945_14400\\",\\"sold_product_565945_13129, sold_product_565945_14400\\",\\"42, 42\\",\\"42, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"20.578, 22.25\\",\\"42, 42\\",\\"13,129, 14,400\\",\\"Jeans Skinny Fit - dark blue denim, Jumper - white\\",\\"Jeans Skinny Fit - dark blue denim, Jumper - white\\",\\"1, 1\\",\\"ZO0270602706, ZO0269502695\\",\\"0, 0\\",\\"42, 42\\",\\"42, 42\\",\\"0, 0\\",\\"ZO0270602706, ZO0269502695\\",84,84,2,2,order,betty +nwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Harvey\\",\\"Clarice Harvey\\",FEMALE,18,Harvey,Harvey,\\"(empty)\\",Monday,0,\\"clarice@harvey-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565988,\\"sold_product_565988_12794, sold_product_565988_15193\\",\\"sold_product_565988_12794, sold_product_565988_15193\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"16.172, 10.289\\",\\"33, 20.984\\",\\"12,794, 15,193\\",\\"Tote bag - cognac, 3 PACK - Long sleeved top - dark grey multicolor/black/white\\",\\"Tote bag - cognac, 3 PACK - Long sleeved top - dark grey multicolor/black/white\\",\\"1, 1\\",\\"ZO0074700747, ZO0645206452\\",\\"0, 0\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"0, 0\\",\\"ZO0074700747, ZO0645206452\\",\\"53.969\\",\\"53.969\\",2,2,order,clarice +pAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Wagdi,Wagdi,\\"Wagdi Underwood\\",\\"Wagdi Underwood\\",MALE,15,Underwood,Underwood,\\"(empty)\\",Monday,0,\\"wagdi@underwood-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565732,\\"sold_product_565732_16955, sold_product_565732_13808\\",\\"sold_product_565732_16955, sold_product_565732_13808\\",\\"200, 16.984\\",\\"200, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"92, 9.344\\",\\"200, 16.984\\",\\"16,955, 13,808\\",\\"Classic coat - navy, Scarf - red/blue\\",\\"Classic coat - navy, Scarf - red/blue\\",\\"1, 1\\",\\"ZO0291402914, ZO0603006030\\",\\"0, 0\\",\\"200, 16.984\\",\\"200, 16.984\\",\\"0, 0\\",\\"ZO0291402914, ZO0603006030\\",217,217,2,2,order,wagdi +AQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Robert,Robert,\\"Robert Cross\\",\\"Robert Cross\\",MALE,29,Cross,Cross,\\"(empty)\\",Monday,0,\\"robert@cross-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566042,\\"sold_product_566042_2775, sold_product_566042_20500\\",\\"sold_product_566042_2775, sold_product_566042_20500\\",\\"28.984, 29.984\\",\\"28.984, 29.984\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"15.938, 15.594\\",\\"28.984, 29.984\\",\\"2,775, 20,500\\",\\"Jumper - white/dark blue, Rucksack - black\\",\\"Jumper - white/dark blue, Rucksack - black\\",\\"1, 1\\",\\"ZO0451804518, ZO0127901279\\",\\"0, 0\\",\\"28.984, 29.984\\",\\"28.984, 29.984\\",\\"0, 0\\",\\"ZO0451804518, ZO0127901279\\",\\"58.969\\",\\"58.969\\",2,2,order,robert +EwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Swanson\\",\\"Tariq Swanson\\",MALE,25,Swanson,Swanson,\\"(empty)\\",Monday,0,\\"tariq@swanson-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566456,\\"sold_product_566456_14947, sold_product_566456_16714\\",\\"sold_product_566456_14947, sold_product_566456_16714\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"5.93, 11.5\\",\\"10.992, 24.984\\",\\"14,947, 16,714\\",\\"Hat - black, Shorts - ice\\",\\"Hat - black, Shorts - ice\\",\\"1, 1\\",\\"ZO0597105971, ZO0283702837\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0597105971, ZO0283702837\\",\\"35.969\\",\\"35.969\\",2,2,order,tariq +TgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Chandler\\",\\"Diane Chandler\\",FEMALE,22,Chandler,Chandler,\\"(empty)\\",Monday,0,\\"diane@chandler-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565542,\\"sold_product_565542_24084, sold_product_565542_19410\\",\\"sold_product_565542_24084, sold_product_565542_19410\\",\\"16.984, 26.984\\",\\"16.984, 26.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"8.828, 13.492\\",\\"16.984, 26.984\\",\\"24,084, 19,410\\",\\"Tights - black/nasturium, Swimsuit - navy\\",\\"Tights - black/nasturium, Swimsuit - navy\\",\\"1, 1\\",\\"ZO0224302243, ZO0359103591\\",\\"0, 0\\",\\"16.984, 26.984\\",\\"16.984, 26.984\\",\\"0, 0\\",\\"ZO0224302243, ZO0359103591\\",\\"43.969\\",\\"43.969\\",2,2,order,diane +XgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Caldwell\\",\\"Rabbia Al Caldwell\\",FEMALE,5,Caldwell,Caldwell,\\"(empty)\\",Monday,0,\\"rabbia al@caldwell-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566121,\\"sold_product_566121_10723, sold_product_566121_12693\\",\\"sold_product_566121_10723, sold_product_566121_12693\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"10.492, 7.82\\",\\"20.984, 16.984\\",\\"10,723, 12,693\\",\\"Sweatshirt - black, Clutch - red\\",\\"Sweatshirt - black, Clutch - red\\",\\"1, 1\\",\\"ZO0227202272, ZO0357003570\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0227202272, ZO0357003570\\",\\"37.969\\",\\"37.969\\",2,2,order,rabbia +XwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Boris,Boris,\\"Boris Bowers\\",\\"Boris Bowers\\",MALE,36,Bowers,Bowers,\\"(empty)\\",Monday,0,\\"boris@bowers-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Angeldale, Spritechnologies\\",\\"Angeldale, Spritechnologies\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566101,\\"sold_product_566101_738, sold_product_566101_24537\\",\\"sold_product_566101_738, sold_product_566101_24537\\",\\"75, 7.988\\",\\"75, 7.988\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spritechnologies\\",\\"Angeldale, Spritechnologies\\",\\"39.75, 4.309\\",\\"75, 7.988\\",\\"738, 24,537\\",\\"Lace-up boots - azul, Sports shirt - black\\",\\"Lace-up boots - azul, Sports shirt - black\\",\\"1, 1\\",\\"ZO0691406914, ZO0617806178\\",\\"0, 0\\",\\"75, 7.988\\",\\"75, 7.988\\",\\"0, 0\\",\\"ZO0691406914, ZO0617806178\\",83,83,2,2,order,boris +YAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Bryant\\",\\"Elyssa Bryant\\",FEMALE,27,Bryant,Bryant,\\"(empty)\\",Monday,0,\\"elyssa@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Angeldale, Pyramidustries active\\",\\"Angeldale, Pyramidustries active\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566653,\\"sold_product_566653_17818, sold_product_566653_18275\\",\\"sold_product_566653_17818, sold_product_566653_18275\\",\\"65, 28.984\\",\\"65, 28.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries active\\",\\"Angeldale, Pyramidustries active\\",\\"31.203, 15.359\\",\\"65, 28.984\\",\\"17,818, 18,275\\",\\"Classic heels - ginger, Trainers - white\\",\\"Classic heels - ginger, Trainers - white\\",\\"1, 1\\",\\"ZO0666506665, ZO0216602166\\",\\"0, 0\\",\\"65, 28.984\\",\\"65, 28.984\\",\\"0, 0\\",\\"ZO0666506665, ZO0216602166\\",94,94,2,2,order,elyssa +pwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Mullins\\",\\"Sonya Mullins\\",FEMALE,28,Mullins,Mullins,\\"(empty)\\",Monday,0,\\"sonya@mullins-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565838,\\"sold_product_565838_17639, sold_product_565838_16507\\",\\"sold_product_565838_17639, sold_product_565838_16507\\",\\"37, 16.984\\",\\"37, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"18.5, 9.344\\",\\"37, 16.984\\",\\"17,639, 16,507\\",\\"Blouse - black, Across body bag - gunmetal\\",\\"Blouse - black, Across body bag - gunmetal\\",\\"1, 1\\",\\"ZO0343703437, ZO0207102071\\",\\"0, 0\\",\\"37, 16.984\\",\\"37, 16.984\\",\\"0, 0\\",\\"ZO0343703437, ZO0207102071\\",\\"53.969\\",\\"53.969\\",2,2,order,sonya +qQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Larson\\",\\"Stephanie Larson\\",FEMALE,6,Larson,Larson,\\"(empty)\\",Monday,0,\\"stephanie@larson-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565804,\\"sold_product_565804_23705, sold_product_565804_11330\\",\\"sold_product_565804_23705, sold_product_565804_11330\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"12.492, 25.984\\",\\"24.984, 50\\",\\"23,705, 11,330\\",\\"Clutch - Deep Pink, Short coat - dark grey\\",\\"Clutch - Deep Pink, Short coat - dark grey\\",\\"1, 1\\",\\"ZO0306803068, ZO0174601746\\",\\"0, 0\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"0, 0\\",\\"ZO0306803068, ZO0174601746\\",75,75,2,2,order,stephanie +qgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Youssef,Youssef,\\"Youssef Summers\\",\\"Youssef Summers\\",MALE,31,Summers,Summers,\\"(empty)\\",Monday,0,\\"youssef@summers-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566247,\\"sold_product_566247_864, sold_product_566247_24934\\",\\"sold_product_566247_864, sold_product_566247_24934\\",\\"50, 50\\",\\"50, 50\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"23.5, 22.5\\",\\"50, 50\\",\\"864, 24,934\\",\\"Smart lace-ups - brown, Lace-up boots - resin coffee\\",\\"Smart lace-ups - brown, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0384903849, ZO0403504035\\",\\"0, 0\\",\\"50, 50\\",\\"50, 50\\",\\"0, 0\\",\\"ZO0384903849, ZO0403504035\\",100,100,2,2,order,youssef +twMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Muniz,Muniz,\\"Muniz Schultz\\",\\"Muniz Schultz\\",MALE,37,Schultz,Schultz,\\"(empty)\\",Monday,0,\\"muniz@schultz-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566036,\\"sold_product_566036_21739, sold_product_566036_19292\\",\\"sold_product_566036_21739, sold_product_566036_19292\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.117, 12.25\\",\\"20.984, 24.984\\",\\"21,739, 19,292\\",\\"Tracksuit top - mottled grey, Trainers - black\\",\\"Tracksuit top - mottled grey, Trainers - black\\",\\"1, 1\\",\\"ZO0583605836, ZO0510605106\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0583605836, ZO0510605106\\",\\"45.969\\",\\"45.969\\",2,2,order,muniz +1AMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Rodriguez\\",\\"Elyssa Rodriguez\\",FEMALE,27,Rodriguez,Rodriguez,\\"(empty)\\",Monday,0,\\"elyssa@rodriguez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565459,\\"sold_product_565459_18966, sold_product_565459_22336\\",\\"sold_product_565459_18966, sold_product_565459_22336\\",\\"60, 75\\",\\"60, 75\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"31.188, 39.75\\",\\"60, 75\\",\\"18,966, 22,336\\",\\"High heeled sandals - red, Boots - black\\",\\"High heeled sandals - red, Boots - black\\",\\"1, 1\\",\\"ZO0242302423, ZO0676006760\\",\\"0, 0\\",\\"60, 75\\",\\"60, 75\\",\\"0, 0\\",\\"ZO0242302423, ZO0676006760\\",135,135,2,2,order,elyssa +2gMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Hansen\\",\\"Elyssa Hansen\\",FEMALE,27,Hansen,Hansen,\\"(empty)\\",Monday,0,\\"elyssa@hansen-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565819,\\"sold_product_565819_11025, sold_product_565819_20135\\",\\"sold_product_565819_11025, sold_product_565819_20135\\",\\"14.992, 11.992\\",\\"14.992, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"6.75, 6.109\\",\\"14.992, 11.992\\",\\"11,025, 20,135\\",\\"T-bar sandals - black, Vest - red\\",\\"T-bar sandals - black, Vest - red\\",\\"1, 1\\",\\"ZO0031700317, ZO0157701577\\",\\"0, 0\\",\\"14.992, 11.992\\",\\"14.992, 11.992\\",\\"0, 0\\",\\"ZO0031700317, ZO0157701577\\",\\"26.984\\",\\"26.984\\",2,2,order,elyssa +2wMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Mullins\\",\\"Wilhemina St. Mullins\\",FEMALE,17,Mullins,Mullins,\\"(empty)\\",Monday,0,\\"wilhemina st.@mullins-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",731352,\\"sold_product_731352_12880, sold_product_731352_5477, sold_product_731352_13837, sold_product_731352_24675\\",\\"sold_product_731352_12880, sold_product_731352_5477, sold_product_731352_13837, sold_product_731352_24675\\",\\"24.984, 42, 37, 16.984\\",\\"24.984, 42, 37, 16.984\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Tigress Enterprises, Gnomehouse, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises, Gnomehouse, Tigress Enterprises\\",\\"13.492, 22.25, 18.859, 8.492\\",\\"24.984, 42, 37, 16.984\\",\\"12,880, 5,477, 13,837, 24,675\\",\\"Ankle boots - blue, Over-the-knee boots - taupe, Mini skirt - multicoloured, Vest - black\\",\\"Ankle boots - blue, Over-the-knee boots - taupe, Mini skirt - multicoloured, Vest - black\\",\\"1, 1, 1, 1\\",\\"ZO0018200182, ZO0016100161, ZO0329703297, ZO0057800578\\",\\"0, 0, 0, 0\\",\\"24.984, 42, 37, 16.984\\",\\"24.984, 42, 37, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0018200182, ZO0016100161, ZO0329703297, ZO0057800578\\",\\"120.938\\",\\"120.938\\",4,4,order,wilhemina +BwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Graham\\",\\"Fitzgerald Graham\\",MALE,11,Graham,Graham,\\"(empty)\\",Monday,0,\\"fitzgerald@graham-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565667,\\"sold_product_565667_19066, sold_product_565667_22279\\",\\"sold_product_565667_19066, sold_product_565667_22279\\",\\"18.984, 50\\",\\"18.984, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"8.547, 23.5\\",\\"18.984, 50\\",\\"19,066, 22,279\\",\\"Tights - black, Casual lace-ups - Sea Green\\",\\"Tights - black, Casual lace-ups - Sea Green\\",\\"1, 1\\",\\"ZO0618706187, ZO0388503885\\",\\"0, 0\\",\\"18.984, 50\\",\\"18.984, 50\\",\\"0, 0\\",\\"ZO0618706187, ZO0388503885\\",69,69,2,2,order,fuzzy +UgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Sutton\\",\\"Abigail Sutton\\",FEMALE,46,Sutton,Sutton,\\"(empty)\\",Monday,0,\\"abigail@sutton-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565900,\\"sold_product_565900_17711, sold_product_565900_14662\\",\\"sold_product_565900_17711, sold_product_565900_14662\\",\\"34, 16.984\\",\\"34, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"18.016, 8.492\\",\\"34, 16.984\\",\\"17,711, 14,662\\",\\"Blouse - black, Print T-shirt - black\\",\\"Blouse - black, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0266102661, ZO0169701697\\",\\"0, 0\\",\\"34, 16.984\\",\\"34, 16.984\\",\\"0, 0\\",\\"ZO0266102661, ZO0169701697\\",\\"50.969\\",\\"50.969\\",2,2,order,abigail +qgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Rose\\",\\"Boris Rose\\",MALE,36,Rose,Rose,\\"(empty)\\",Monday,0,\\"boris@rose-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566360,\\"sold_product_566360_15319, sold_product_566360_10913\\",\\"sold_product_566360_15319, sold_product_566360_10913\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"15.844, 6.039\\",\\"33, 10.992\\",\\"15,319, 10,913\\",\\"Relaxed fit jeans - grey denim, Long sleeved top - grey/dark blue\\",\\"Relaxed fit jeans - grey denim, Long sleeved top - grey/dark blue\\",\\"1, 1\\",\\"ZO0285102851, ZO0658306583\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0285102851, ZO0658306583\\",\\"43.969\\",\\"43.969\\",2,2,order,boris +qwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Soto\\",\\"Abdulraheem Al Soto\\",MALE,33,Soto,Soto,\\"(empty)\\",Monday,0,\\"abdulraheem al@soto-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566416,\\"sold_product_566416_17928, sold_product_566416_24672\\",\\"sold_product_566416_17928, sold_product_566416_24672\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"23.5, 9.898\\",\\"50, 21.984\\",\\"17,928, 24,672\\",\\"Boots - dark brown, Across body bag - black/cognac\\",\\"Boots - dark brown, Across body bag - black/cognac\\",\\"1, 1\\",\\"ZO0396903969, ZO0607906079\\",\\"0, 0\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"0, 0\\",\\"ZO0396903969, ZO0607906079\\",72,72,2,2,order,abdulraheem +IgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Hansen\\",\\"Abigail Hansen\\",FEMALE,46,Hansen,Hansen,\\"(empty)\\",Monday,0,\\"abigail@hansen-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565796,\\"sold_product_565796_11879, sold_product_565796_8405\\",\\"sold_product_565796_11879, sold_product_565796_8405\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"4.23, 14.852\\",\\"7.988, 33\\",\\"11,879, 8,405\\",\\"Snood - offwhite/red/black, Long sleeved top - alison white\\",\\"Snood - offwhite/red/black, Long sleeved top - alison white\\",\\"1, 1\\",\\"ZO0081500815, ZO0342603426\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0081500815, ZO0342603426\\",\\"40.969\\",\\"40.969\\",2,2,order,abigail +IwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Sherman\\",\\"Samir Sherman\\",MALE,34,Sherman,Sherman,\\"(empty)\\",Monday,0,\\"samir@sherman-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566261,\\"sold_product_566261_20514, sold_product_566261_13193\\",\\"sold_product_566261_20514, sold_product_566261_13193\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.5, 42.5\\",\\"24.984, 85\\",\\"20,514, 13,193\\",\\"Jumper - black, Parka - black\\",\\"Jumper - black, Parka - black\\",\\"1, 1\\",\\"ZO0577105771, ZO0289302893\\",\\"0, 0\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"0, 0\\",\\"ZO0577105771, ZO0289302893\\",110,110,2,2,order,samir +QgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Daniels\\",\\"Robbie Daniels\\",MALE,48,Daniels,Daniels,\\"(empty)\\",Monday,0,\\"robbie@daniels-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565567,\\"sold_product_565567_18531, sold_product_565567_11331\\",\\"sold_product_565567_18531, sold_product_565567_11331\\",\\"11.992, 18.984\\",\\"11.992, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"5.398, 8.93\\",\\"11.992, 18.984\\",\\"18,531, 11,331\\",\\"Basic T-shirt - tan, Tracksuit bottoms - black\\",\\"Basic T-shirt - tan, Tracksuit bottoms - black\\",\\"1, 1\\",\\"ZO0437604376, ZO0618906189\\",\\"0, 0\\",\\"11.992, 18.984\\",\\"11.992, 18.984\\",\\"0, 0\\",\\"ZO0437604376, ZO0618906189\\",\\"30.984\\",\\"30.984\\",2,2,order,robbie +QwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Byrd\\",\\"Brigitte Byrd\\",FEMALE,12,Byrd,Byrd,\\"(empty)\\",Monday,0,\\"brigitte@byrd-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565596,\\"sold_product_565596_19599, sold_product_565596_13051\\",\\"sold_product_565596_19599, sold_product_565596_13051\\",\\"50, 13.992\\",\\"50, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"25.484, 7\\",\\"50, 13.992\\",\\"19,599, 13,051\\",\\"Maxi dress - Pale Violet Red, Print T-shirt - black\\",\\"Maxi dress - Pale Violet Red, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0332903329, ZO0159401594\\",\\"0, 0\\",\\"50, 13.992\\",\\"50, 13.992\\",\\"0, 0\\",\\"ZO0332903329, ZO0159401594\\",\\"63.969\\",\\"63.969\\",2,2,order,brigitte +VgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",EUR,Abd,Abd,\\"Abd Foster\\",\\"Abd Foster\\",MALE,52,Foster,Foster,\\"(empty)\\",Monday,0,\\"abd@foster-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence, Angeldale\\",\\"Low Tide Media, Elitelligence, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",717206,\\"sold_product_717206_13588, sold_product_717206_16372, sold_product_717206_20757, sold_product_717206_22434\\",\\"sold_product_717206_13588, sold_product_717206_16372, sold_product_717206_20757, sold_product_717206_22434\\",\\"60, 24.984, 80, 60\\",\\"60, 24.984, 80, 60\\",\\"Men's Shoes, Women's Accessories, Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Women's Accessories, Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, Angeldale, Low Tide Media\\",\\"Low Tide Media, Elitelligence, Angeldale, Low Tide Media\\",\\"28.797, 12.742, 40.781, 30\\",\\"60, 24.984, 80, 60\\",\\"13,588, 16,372, 20,757, 22,434\\",\\"Lace-ups - cognac, Rucksack - black, Lace-up boots - dark brown, Casual lace-ups - cognac\\",\\"Lace-ups - cognac, Rucksack - black, Lace-up boots - dark brown, Casual lace-ups - cognac\\",\\"1, 1, 1, 1\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\",\\"0, 0, 0, 0\\",\\"60, 24.984, 80, 60\\",\\"60, 24.984, 80, 60\\",\\"0, 0, 0, 0\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\",225,225,4,4,order,abd +ggMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Bailey\\",\\"Abd Bailey\\",MALE,52,Bailey,Bailey,\\"(empty)\\",Monday,0,\\"abd@bailey-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",715081,\\"sold_product_715081_20855, sold_product_715081_15922, sold_product_715081_6851, sold_product_715081_1808\\",\\"sold_product_715081_20855, sold_product_715081_15922, sold_product_715081_6851, sold_product_715081_1808\\",\\"65, 65, 24.984, 50\\",\\"65, 65, 24.984, 50\\",\\"Men's Shoes, Men's Shoes, Men's Clothing, Men's Shoes\\",\\"Men's Shoes, Men's Shoes, Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Low Tide Media, Low Tide Media, Low Tide Media\\",\\"Angeldale, Low Tide Media, Low Tide Media, Low Tide Media\\",\\"29.906, 32.5, 12.492, 23\\",\\"65, 65, 24.984, 50\\",\\"20,855, 15,922, 6,851, 1,808\\",\\"Lace-up boots - black, Lace-up boots - cognac, SLIM FIT - Formal shirt - dark blue, Lace-up boots - black\\",\\"Lace-up boots - black, Lace-up boots - cognac, SLIM FIT - Formal shirt - dark blue, Lace-up boots - black\\",\\"1, 1, 1, 1\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\",\\"0, 0, 0, 0\\",\\"65, 65, 24.984, 50\\",\\"65, 65, 24.984, 50\\",\\"0, 0, 0, 0\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\",205,205,4,4,order,abd +mwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Davidson\\",\\"Mary Davidson\\",FEMALE,20,Davidson,Davidson,\\"(empty)\\",Monday,0,\\"mary@davidson-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566428,\\"sold_product_566428_20712, sold_product_566428_18581\\",\\"sold_product_566428_20712, sold_product_566428_18581\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"15.07, 24\\",\\"28.984, 50\\",\\"20,712, 18,581\\",\\"Trainers - black, Summer dress - red ochre\\",\\"Trainers - black, Summer dress - red ochre\\",\\"1, 1\\",\\"ZO0136501365, ZO0339103391\\",\\"0, 0\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"0, 0\\",\\"ZO0136501365, ZO0339103391\\",79,79,2,2,order,mary +zQMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Pope\\",\\"Pia Pope\\",FEMALE,45,Pope,Pope,\\"(empty)\\",Monday,0,\\"pia@pope-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566334,\\"sold_product_566334_17905, sold_product_566334_24273\\",\\"sold_product_566334_17905, sold_product_566334_24273\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"14.781, 6.469\\",\\"28.984, 11.992\\",\\"17,905, 24,273\\",\\"High heeled sandals - Rosy Brown, Jersey dress - beige\\",\\"High heeled sandals - Rosy Brown, Jersey dress - beige\\",\\"1, 1\\",\\"ZO0010800108, ZO0635706357\\",\\"0, 0\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"0, 0\\",\\"ZO0010800108, ZO0635706357\\",\\"40.969\\",\\"40.969\\",2,2,order,pia +zgMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Jacobs\\",\\"Elyssa Jacobs\\",FEMALE,27,Jacobs,Jacobs,\\"(empty)\\",Monday,0,\\"elyssa@jacobs-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566391,\\"sold_product_566391_15927, sold_product_566391_15841\\",\\"sold_product_566391_15927, sold_product_566391_15841\\",\\"33, 13.992\\",\\"33, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"15.18, 6.719\\",\\"33, 13.992\\",\\"15,927, 15,841\\",\\"Jersey dress - peacoat, Long sleeved top - black\\",\\"Jersey dress - peacoat, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0228302283, ZO0167501675\\",\\"0, 0\\",\\"33, 13.992\\",\\"33, 13.992\\",\\"0, 0\\",\\"ZO0228302283, ZO0167501675\\",\\"46.969\\",\\"46.969\\",2,2,order,elyssa +IQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Adams\\",\\"Sultan Al Adams\\",MALE,19,Adams,Adams,\\"(empty)\\",Monday,0,\\"sultan al@adams-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",715133,\\"sold_product_715133_22059, sold_product_715133_13763, sold_product_715133_19774, sold_product_715133_15185\\",\\"sold_product_715133_22059, sold_product_715133_13763, sold_product_715133_19774, sold_product_715133_15185\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"Men's Clothing, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Elitelligence, Microlutions\\",\\"Elitelligence, Elitelligence, Elitelligence, Microlutions\\",\\"15.07, 9.344, 5.879, 11.5\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"22,059, 13,763, 19,774, 15,185\\",\\"Relaxed fit jeans - black, Trainers - dark brown, Print T-shirt - black/orange, Tracksuit bottoms - mottled grey\\",\\"Relaxed fit jeans - black, Trainers - dark brown, Print T-shirt - black/orange, Tracksuit bottoms - mottled grey\\",\\"1, 1, 1, 1\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\",\\"0, 0, 0, 0\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\",\\"82.938\\",\\"82.938\\",4,4,order,sultan +QAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Barnes\\",\\"Abd Barnes\\",MALE,52,Barnes,Barnes,\\"(empty)\\",Monday,0,\\"abd@barnes-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",717057,\\"sold_product_717057_18764, sold_product_717057_1195, sold_product_717057_13086, sold_product_717057_13470\\",\\"sold_product_717057_18764, sold_product_717057_1195, sold_product_717057_13086, sold_product_717057_13470\\",\\"65, 60, 50, 15.992\\",\\"65, 60, 50, 15.992\\",\\"Men's Clothing, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spritechnologies, Low Tide Media, Low Tide Media, Low Tide Media\\",\\"Spritechnologies, Low Tide Media, Low Tide Media, Low Tide Media\\",\\"30.547, 28.203, 23, 8.313\\",\\"65, 60, 50, 15.992\\",\\"18,764, 1,195, 13,086, 13,470\\",\\"Winter jacket - rubber, Lace-up boots - cognac, Casual lace-ups - light brown, 4 PACK - Shorts - grey\\",\\"Winter jacket - rubber, Lace-up boots - cognac, Casual lace-ups - light brown, 4 PACK - Shorts - grey\\",\\"1, 1, 1, 1\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\",\\"0, 0, 0, 0\\",\\"65, 60, 50, 15.992\\",\\"65, 60, 50, 15.992\\",\\"0, 0, 0, 0\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\",191,191,4,4,order,abd +SQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Diane,Diane,\\"Diane Parker\\",\\"Diane Parker\\",FEMALE,22,Parker,Parker,\\"(empty)\\",Monday,0,\\"diane@parker-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Karmanite, Pyramidustries\\",\\"Karmanite, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566315,\\"sold_product_566315_11724, sold_product_566315_18465\\",\\"sold_product_566315_11724, sold_product_566315_18465\\",\\"65, 42\\",\\"65, 42\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Karmanite, Pyramidustries\\",\\"Karmanite, Pyramidustries\\",\\"33.125, 19.313\\",\\"65, 42\\",\\"11,724, 18,465\\",\\"Sandals - black, Boots - black\\",\\"Sandals - black, Boots - black\\",\\"1, 1\\",\\"ZO0703707037, ZO0139601396\\",\\"0, 0\\",\\"65, 42\\",\\"65, 42\\",\\"0, 0\\",\\"ZO0703707037, ZO0139601396\\",107,107,2,2,order,diane +SgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Cross\\",\\"Abigail Cross\\",FEMALE,46,Cross,Cross,\\"(empty)\\",Monday,0,\\"abigail@cross-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565698,\\"sold_product_565698_13951, sold_product_565698_21969\\",\\"sold_product_565698_13951, sold_product_565698_21969\\",\\"50, 7.988\\",\\"50, 7.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"26.484, 3.68\\",\\"50, 7.988\\",\\"13,951, 21,969\\",\\"Summer dress - black, Vest - bordeaux\\",\\"Summer dress - black, Vest - bordeaux\\",\\"1, 1\\",\\"ZO0336503365, ZO0637006370\\",\\"0, 0\\",\\"50, 7.988\\",\\"50, 7.988\\",\\"0, 0\\",\\"ZO0336503365, ZO0637006370\\",\\"57.969\\",\\"57.969\\",2,2,order,abigail +UQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Valdez\\",\\"Wagdi Valdez\\",MALE,15,Valdez,Valdez,\\"(empty)\\",Monday,0,\\"wagdi@valdez-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566167,\\"sold_product_566167_3499, sold_product_566167_13386\\",\\"sold_product_566167_3499, sold_product_566167_13386\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"28.203, 11.75\\",\\"60, 24.984\\",\\"3,499, 13,386\\",\\"Hardshell jacket - jet black, Trousers - black\\",\\"Hardshell jacket - jet black, Trousers - black\\",\\"1, 1\\",\\"ZO0623006230, ZO0419304193\\",\\"0, 0\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"0, 0\\",\\"ZO0623006230, ZO0419304193\\",85,85,2,2,order,wagdi +UgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Rivera\\",\\"Mostafa Rivera\\",MALE,9,Rivera,Rivera,\\"(empty)\\",Monday,0,\\"mostafa@rivera-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566215,\\"sold_product_566215_864, sold_product_566215_23260\\",\\"sold_product_566215_864, sold_product_566215_23260\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"23.5, 13.742\\",\\"50, 24.984\\",\\"864, 23,260\\",\\"Smart lace-ups - brown, Jumper - khaki\\",\\"Smart lace-ups - brown, Jumper - khaki\\",\\"1, 1\\",\\"ZO0384903849, ZO0579305793\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0384903849, ZO0579305793\\",75,75,2,2,order,mostafa +UwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Underwood\\",\\"Mary Underwood\\",FEMALE,20,Underwood,Underwood,\\"(empty)\\",Monday,0,\\"mary@underwood-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566070,\\"sold_product_566070_23447, sold_product_566070_17406\\",\\"sold_product_566070_23447, sold_product_566070_17406\\",\\"33, 33\\",\\"33, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"17.813, 16.813\\",\\"33, 33\\",\\"23,447, 17,406\\",\\"Cocktail dress / Party dress - black, Summer dress - black\\",\\"Cocktail dress / Party dress - black, Summer dress - black\\",\\"1, 1\\",\\"ZO0046100461, ZO0151201512\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0046100461, ZO0151201512\\",66,66,2,2,order,mary +VAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Jason,Jason,\\"Jason Jimenez\\",\\"Jason Jimenez\\",MALE,16,Jimenez,Jimenez,\\"(empty)\\",Monday,0,\\"jason@jimenez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566621,\\"sold_product_566621_21825, sold_product_566621_21628\\",\\"sold_product_566621_21825, sold_product_566621_21628\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.906, 33.75\\",\\"20.984, 75\\",\\"21,825, 21,628\\",\\"Jumper - khaki, Weekend bag - black\\",\\"Jumper - khaki, Weekend bag - black\\",\\"1, 1\\",\\"ZO0579605796, ZO0315803158\\",\\"0, 0\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"0, 0\\",\\"ZO0579605796, ZO0315803158\\",96,96,2,2,order,jason +VQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Miller\\",\\"Youssef Miller\\",MALE,31,Miller,Miller,\\"(empty)\\",Monday,0,\\"youssef@miller-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566284,\\"sold_product_566284_6763, sold_product_566284_11234\\",\\"sold_product_566284_6763, sold_product_566284_11234\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9, 21.828\\",\\"16.984, 42\\",\\"6,763, 11,234\\",\\"Jumper - black, Tracksuit top - black\\",\\"Jumper - black, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0541405414, ZO0588205882\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0541405414, ZO0588205882\\",\\"58.969\\",\\"58.969\\",2,2,order,youssef +VgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Byrd\\",\\"Thad Byrd\\",MALE,30,Byrd,Byrd,\\"(empty)\\",Monday,0,\\"thad@byrd-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566518,\\"sold_product_566518_22342, sold_product_566518_14729\\",\\"sold_product_566518_22342, sold_product_566518_14729\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.762, 5.641\\",\\"11.992, 11.992\\",\\"22,342, 14,729\\",\\"Long sleeved top - mottled grey black, Long sleeved top - black\\",\\"Long sleeved top - mottled grey black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0554605546, ZO0569005690\\",\\"0, 0\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"0, 0\\",\\"ZO0554605546, ZO0569005690\\",\\"23.984\\",\\"23.984\\",2,2,order,thad +agMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Tariq,Tariq,\\"Tariq Byrd\\",\\"Tariq Byrd\\",MALE,25,Byrd,Byrd,\\"(empty)\\",Monday,0,\\"tariq@byrd-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565580,\\"sold_product_565580_1927, sold_product_565580_12828\\",\\"sold_product_565580_1927, sold_product_565580_12828\\",\\"60, 60\\",\\"60, 60\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"28.203, 29.406\\",\\"60, 60\\",\\"1,927, 12,828\\",\\"High-top trainers - nyco, Lace-ups - marron\\",\\"High-top trainers - nyco, Lace-ups - marron\\",\\"1, 1\\",\\"ZO0395303953, ZO0386703867\\",\\"0, 0\\",\\"60, 60\\",\\"60, 60\\",\\"0, 0\\",\\"ZO0395303953, ZO0386703867\\",120,120,2,2,order,tariq +cwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Valdez\\",\\"rania Valdez\\",FEMALE,24,Valdez,Valdez,\\"(empty)\\",Monday,0,\\"rania@valdez-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565830,\\"sold_product_565830_17256, sold_product_565830_23136\\",\\"sold_product_565830_17256, sold_product_565830_23136\\",\\"7.988, 7.988\\",\\"7.988, 7.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"4.148, 4.309\\",\\"7.988, 7.988\\",\\"17,256, 23,136\\",\\"3 PACK - Socks - off white/pink, Basic T-shirt - purple\\",\\"3 PACK - Socks - off white/pink, Basic T-shirt - purple\\",\\"1, 1\\",\\"ZO0215702157, ZO0638806388\\",\\"0, 0\\",\\"7.988, 7.988\\",\\"7.988, 7.988\\",\\"0, 0\\",\\"ZO0215702157, ZO0638806388\\",\\"15.977\\",\\"15.977\\",2,2,order,rani +GQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jason,Jason,\\"Jason Morrison\\",\\"Jason Morrison\\",MALE,16,Morrison,Morrison,\\"(empty)\\",Monday,0,\\"jason@morrison-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566454,\\"sold_product_566454_15937, sold_product_566454_1557\\",\\"sold_product_566454_15937, sold_product_566454_1557\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.84, 31.188\\",\\"7.988, 60\\",\\"15,937, 1,557\\",\\"Basic T-shirt - dark grey, Lace-up boots - brown\\",\\"Basic T-shirt - dark grey, Lace-up boots - brown\\",\\"1, 1\\",\\"ZO0547405474, ZO0401104011\\",\\"0, 0\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"0, 0\\",\\"ZO0547405474, ZO0401104011\\",68,68,2,2,order,jason +GgMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Thad,Thad,\\"Thad Larson\\",\\"Thad Larson\\",MALE,30,Larson,Larson,\\"(empty)\\",Monday,0,\\"thad@larson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566506,\\"sold_product_566506_12060, sold_product_566506_16803\\",\\"sold_product_566506_12060, sold_product_566506_16803\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"25.984, 8.492\\",\\"50, 16.984\\",\\"12,060, 16,803\\",\\"Lace-ups - black/red, Rucksack - grey/black\\",\\"Lace-ups - black/red, Rucksack - grey/black\\",\\"1, 1\\",\\"ZO0680806808, ZO0609306093\\",\\"0, 0\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"0, 0\\",\\"ZO0680806808, ZO0609306093\\",67,67,2,2,order,thad +HAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Romero\\",\\"Diane Romero\\",FEMALE,22,Romero,Romero,\\"(empty)\\",Monday,0,\\"diane@romero-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565948,\\"sold_product_565948_18390, sold_product_565948_24310\\",\\"sold_product_565948_18390, sold_product_565948_24310\\",\\"10.992, 22.984\\",\\"10.992, 22.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"5.93, 10.578\\",\\"10.992, 22.984\\",\\"18,390, 24,310\\",\\"Wallet - black, Jumper - light grey multicolor\\",\\"Wallet - black, Jumper - light grey multicolor\\",\\"1, 1\\",\\"ZO0190701907, ZO0654806548\\",\\"0, 0\\",\\"10.992, 22.984\\",\\"10.992, 22.984\\",\\"0, 0\\",\\"ZO0190701907, ZO0654806548\\",\\"33.969\\",\\"33.969\\",2,2,order,diane +HQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Morrison\\",\\"Gwen Morrison\\",FEMALE,26,Morrison,Morrison,\\"(empty)\\",Monday,0,\\"gwen@morrison-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565998,\\"sold_product_565998_15531, sold_product_565998_8992\\",\\"sold_product_565998_15531, sold_product_565998_8992\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"29.906, 10.703\\",\\"65, 20.984\\",\\"15,531, 8,992\\",\\"Classic heels - black, Blouse - black\\",\\"Classic heels - black, Blouse - black\\",\\"1, 1\\",\\"ZO0238802388, ZO0066600666\\",\\"0, 0\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"0, 0\\",\\"ZO0238802388, ZO0066600666\\",86,86,2,2,order,gwen +kAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Reese\\",\\"Elyssa Reese\\",FEMALE,27,Reese,Reese,\\"(empty)\\",Monday,0,\\"elyssa@reese-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565401,\\"sold_product_565401_24966, sold_product_565401_14951\\",\\"sold_product_565401_24966, sold_product_565401_14951\\",\\"42, 24.984\\",\\"42, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"21.828, 11.75\\",\\"42, 24.984\\",\\"24,966, 14,951\\",\\"High heeled boots - black, Jersey dress - black\\",\\"High heeled boots - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0014800148, ZO0154501545\\",\\"0, 0\\",\\"42, 24.984\\",\\"42, 24.984\\",\\"0, 0\\",\\"ZO0014800148, ZO0154501545\\",67,67,2,2,order,elyssa +MQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Hopkins\\",\\"Elyssa Hopkins\\",FEMALE,27,Hopkins,Hopkins,\\"(empty)\\",Monday,0,\\"elyssa@hopkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565728,\\"sold_product_565728_22660, sold_product_565728_17747\\",\\"sold_product_565728_22660, sold_product_565728_17747\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"11.117, 38.25\\",\\"20.984, 75\\",\\"22,660, 17,747\\",\\"Tracksuit bottoms - dark grey multicolor, Ankle boots - black\\",\\"Tracksuit bottoms - dark grey multicolor, Ankle boots - black\\",\\"1, 1\\",\\"ZO0486404864, ZO0248602486\\",\\"0, 0\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"0, 0\\",\\"ZO0486404864, ZO0248602486\\",96,96,2,2,order,elyssa +DQMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Craig\\",\\"Rabbia Al Craig\\",FEMALE,5,Craig,Craig,\\"(empty)\\",Monday,0,\\"rabbia al@craig-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565489,\\"sold_product_565489_17610, sold_product_565489_23396\\",\\"sold_product_565489_17610, sold_product_565489_23396\\",\\"13.992, 7.988\\",\\"13.992, 7.988\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"7.41, 3.6\\",\\"13.992, 7.988\\",\\"17,610, 23,396\\",\\"Belt - black, Vest - black\\",\\"Belt - black, Vest - black\\",\\"1, 1\\",\\"ZO0077200772, ZO0643006430\\",\\"0, 0\\",\\"13.992, 7.988\\",\\"13.992, 7.988\\",\\"0, 0\\",\\"ZO0077200772, ZO0643006430\\",\\"21.984\\",\\"21.984\\",2,2,order,rabbia +EAMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Padilla\\",\\"Abdulraheem Al Padilla\\",MALE,33,Padilla,Padilla,\\"(empty)\\",Monday,0,\\"abdulraheem al@padilla-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565366,\\"sold_product_565366_2077, sold_product_565366_14547\\",\\"sold_product_565366_2077, sold_product_565366_14547\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"37.5, 12.25\\",\\"75, 24.984\\",\\"2,077, 14,547\\",\\"Trainers - black, Jumper - camel/black\\",\\"Trainers - black, Jumper - camel/black\\",\\"1, 1\\",\\"ZO0684906849, ZO0575905759\\",\\"0, 0\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"0, 0\\",\\"ZO0684906849, ZO0575905759\\",100,100,2,2,order,abdulraheem +xwMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Gilbert\\",\\"Tariq Gilbert\\",MALE,25,Gilbert,Gilbert,\\"(empty)\\",Monday,0,\\"tariq@gilbert-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",720445,\\"sold_product_720445_22855, sold_product_720445_19704, sold_product_720445_12699, sold_product_720445_13347\\",\\"sold_product_720445_22855, sold_product_720445_19704, sold_product_720445_12699, sold_product_720445_13347\\",\\"22.984, 13.992, 42, 11.992\\",\\"22.984, 13.992, 42, 11.992\\",\\"Men's Clothing, Men's Clothing, Women's Accessories, Women's Accessories\\",\\"Men's Clothing, Men's Clothing, Women's Accessories, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Oceanavigations, Oceanavigations, Oceanavigations\\",\\"Low Tide Media, Oceanavigations, Oceanavigations, Oceanavigations\\",\\"10.813, 6.859, 22.672, 6.23\\",\\"22.984, 13.992, 42, 11.992\\",\\"22,855, 19,704, 12,699, 13,347\\",\\"Shorts - black, Print T-shirt - grey multicolor, Weekend bag - dessert, Sunglasses - black\\",\\"Shorts - black, Print T-shirt - grey multicolor, Weekend bag - dessert, Sunglasses - black\\",\\"1, 1, 1, 1\\",\\"ZO0423004230, ZO0292702927, ZO0320003200, ZO0318303183\\",\\"0, 0, 0, 0\\",\\"22.984, 13.992, 42, 11.992\\",\\"22.984, 13.992, 42, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0423004230, ZO0292702927, ZO0320003200, ZO0318303183\\",\\"90.938\\",\\"90.938\\",4,4,order,tariq +0wMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Graham\\",\\"Youssef Graham\\",MALE,31,Graham,Graham,\\"(empty)\\",Monday,0,\\"youssef@graham-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565768,\\"sold_product_565768_19338, sold_product_565768_19206\\",\\"sold_product_565768_19338, sold_product_565768_19206\\",\\"22.984, 33\\",\\"22.984, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"12.18, 15.18\\",\\"22.984, 33\\",\\"19,338, 19,206\\",\\"Sweatshirt - dark grey multicolor, Suit trousers - navy\\",\\"Sweatshirt - dark grey multicolor, Suit trousers - navy\\",\\"1, 1\\",\\"ZO0458004580, ZO0273402734\\",\\"0, 0\\",\\"22.984, 33\\",\\"22.984, 33\\",\\"0, 0\\",\\"ZO0458004580, ZO0273402734\\",\\"55.969\\",\\"55.969\\",2,2,order,youssef +7gMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Harvey\\",\\"Gwen Harvey\\",FEMALE,26,Harvey,Harvey,\\"(empty)\\",Monday,0,\\"gwen@harvey-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Champion Arts, Low Tide Media\\",\\"Champion Arts, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565538,\\"sold_product_565538_23676, sold_product_565538_16054\\",\\"sold_product_565538_23676, sold_product_565538_16054\\",\\"24.984, 55\\",\\"24.984, 55\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Low Tide Media\\",\\"Champion Arts, Low Tide Media\\",\\"12.25, 25.297\\",\\"24.984, 55\\",\\"23,676, 16,054\\",\\"Slim fit jeans - brown, Platform sandals - black\\",\\"Slim fit jeans - brown, Platform sandals - black\\",\\"1, 1\\",\\"ZO0486804868, ZO0371603716\\",\\"0, 0\\",\\"24.984, 55\\",\\"24.984, 55\\",\\"0, 0\\",\\"ZO0486804868, ZO0371603716\\",80,80,2,2,order,gwen +\\"-wMtOW0BH63Xcmy45Wq4\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Gilbert\\",\\"Brigitte Gilbert\\",FEMALE,12,Gilbert,Gilbert,\\"(empty)\\",Monday,0,\\"brigitte@gilbert-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565404,\\"sold_product_565404_23482, sold_product_565404_19328\\",\\"sold_product_565404_23482, sold_product_565404_19328\\",\\"42, 33\\",\\"42, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"22.672, 17.813\\",\\"42, 33\\",\\"23,482, 19,328\\",\\"Cocktail dress / Party dress - pomegranate/black, Shift dress - black/champagne\\",\\"Cocktail dress / Party dress - pomegranate/black, Shift dress - black/champagne\\",\\"1, 1\\",\\"ZO0048900489, ZO0228702287\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0048900489, ZO0228702287\\",75,75,2,2,order,brigitte +EwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Jimenez\\",\\"Sultan Al Jimenez\\",MALE,19,Jimenez,Jimenez,\\"(empty)\\",Monday,0,\\"sultan al@jimenez-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",715961,\\"sold_product_715961_18507, sold_product_715961_19182, sold_product_715961_17545, sold_product_715961_15806\\",\\"sold_product_715961_18507, sold_product_715961_19182, sold_product_715961_17545, sold_product_715961_15806\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Oceanavigations, Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Oceanavigations, Low Tide Media, Low Tide Media\\",\\"11.25, 8.156, 4.148, 7.27\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"18,507, 19,182, 17,545, 15,806\\",\\"Vibrant Pattern Polo, Print T-shirt - light grey multicolor, Basic T-shirt - blue multicolor, Belt - dark brown\\",\\"Vibrant Pattern Polo, Print T-shirt - light grey multicolor, Basic T-shirt - blue multicolor, Belt - dark brown\\",\\"1, 1, 1, 1\\",\\"ZO0444904449, ZO0292502925, ZO0434604346, ZO0461804618\\",\\"0, 0, 0, 0\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"0, 0, 0, 0\\",\\"ZO0444904449, ZO0292502925, ZO0434604346, ZO0461804618\\",\\"63.969\\",\\"63.969\\",4,4,order,sultan +VwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Wise\\",\\"Rabbia Al Wise\\",FEMALE,5,Wise,Wise,\\"(empty)\\",Monday,0,\\"rabbia al@wise-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566382,\\"sold_product_566382_15477, sold_product_566382_20551\\",\\"sold_product_566382_15477, sold_product_566382_20551\\",\\"18.984, 65\\",\\"18.984, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"9.68, 33.781\\",\\"18.984, 65\\",\\"15,477, 20,551\\",\\"Sweatshirt - black, Lace-ups - Purple\\",\\"Sweatshirt - black, Lace-ups - Purple\\",\\"1, 1\\",\\"ZO0503505035, ZO0240302403\\",\\"0, 0\\",\\"18.984, 65\\",\\"18.984, 65\\",\\"0, 0\\",\\"ZO0503505035, ZO0240302403\\",84,84,2,2,order,rabbia +XgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Frances,Frances,\\"Frances Salazar\\",\\"Frances Salazar\\",FEMALE,49,Salazar,Salazar,\\"(empty)\\",Monday,0,\\"frances@salazar-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",Microlutions,Microlutions,\\"Jun 23, 2019 @ 00:00:00.000\\",565877,\\"sold_product_565877_20689, sold_product_565877_19983\\",\\"sold_product_565877_20689, sold_product_565877_19983\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Microlutions\\",\\"Microlutions, Microlutions\\",\\"15.18, 15.07\\",\\"33, 28.984\\",\\"20,689, 19,983\\",\\"Sweatshirt - light grey, Sweatshirt - black\\",\\"Sweatshirt - light grey, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0125401254, ZO0123701237\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0125401254, ZO0123701237\\",\\"61.969\\",\\"61.969\\",2,2,order,frances +bgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Farmer\\",\\"Robbie Farmer\\",MALE,48,Farmer,Farmer,\\"(empty)\\",Monday,0,\\"robbie@farmer-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566364,\\"sold_product_566364_15434, sold_product_566364_15384\\",\\"sold_product_566364_15434, sold_product_566364_15384\\",\\"33, 33\\",\\"33, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"16.813, 17.156\\",\\"33, 33\\",\\"15,434, 15,384\\",\\"High-top trainers - black, Denim jacket - grey\\",\\"High-top trainers - black, Denim jacket - grey\\",\\"1, 1\\",\\"ZO0512505125, ZO0525005250\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0512505125, ZO0525005250\\",66,66,2,2,order,robbie +vwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Robbie,Robbie,\\"Robbie Holland\\",\\"Robbie Holland\\",MALE,48,Holland,Holland,\\"(empty)\\",Monday,0,\\"robbie@holland-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565479,\\"sold_product_565479_16738, sold_product_565479_14474\\",\\"sold_product_565479_16738, sold_product_565479_14474\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.539, 34.438\\",\\"20.984, 65\\",\\"16,738, 14,474\\",\\"Tracksuit top - red, Briefcase - dark brown\\",\\"Tracksuit top - red, Briefcase - dark brown\\",\\"1, 1\\",\\"ZO0588805888, ZO0314903149\\",\\"0, 0\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"0, 0\\",\\"ZO0588805888, ZO0314903149\\",86,86,2,2,order,robbie +wwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Butler\\",\\"Mostafa Butler\\",MALE,9,Butler,Butler,\\"(empty)\\",Monday,0,\\"mostafa@butler-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565360,\\"sold_product_565360_11937, sold_product_565360_6497\\",\\"sold_product_565360_11937, sold_product_565360_6497\\",\\"33, 60\\",\\"33, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"18.141, 31.188\\",\\"33, 60\\",\\"11,937, 6,497\\",\\"Jumper - navy, Colorful Cardigan\\",\\"Jumper - navy, Colorful Cardigan\\",\\"1, 1\\",\\"ZO0448604486, ZO0450704507\\",\\"0, 0\\",\\"33, 60\\",\\"33, 60\\",\\"0, 0\\",\\"ZO0448604486, ZO0450704507\\",93,93,2,2,order,mostafa +zwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Perkins\\",\\"Kamal Perkins\\",MALE,39,Perkins,Perkins,\\"(empty)\\",Monday,0,\\"kamal@perkins-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565734,\\"sold_product_565734_23476, sold_product_565734_15158\\",\\"sold_product_565734_23476, sold_product_565734_15158\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"12.492, 33.125\\",\\"24.984, 65\\",\\"23,476, 15,158\\",\\"High-top trainers - allblack, Boots - grey\\",\\"High-top trainers - allblack, Boots - grey\\",\\"1, 1\\",\\"ZO0513205132, ZO0258202582\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0513205132, ZO0258202582\\",90,90,2,2,order,kamal +gAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Powell\\",\\"Sultan Al Powell\\",MALE,19,Powell,Powell,\\"(empty)\\",Monday,0,\\"sultan al@powell-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566514,\\"sold_product_566514_6827, sold_product_566514_11745\\",\\"sold_product_566514_6827, sold_product_566514_11745\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"17.156, 5.281\\",\\"33, 10.992\\",\\"6,827, 11,745\\",\\"Denim jacket - black denim, T-bar sandals - black/orange\\",\\"Denim jacket - black denim, T-bar sandals - black/orange\\",\\"1, 1\\",\\"ZO0539305393, ZO0522305223\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0539305393, ZO0522305223\\",\\"43.969\\",\\"43.969\\",2,2,order,sultan +gQMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Summers\\",\\"Clarice Summers\\",FEMALE,18,Summers,Summers,\\"(empty)\\",Monday,0,\\"clarice@summers-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565970,\\"sold_product_565970_25000, sold_product_565970_20678\\",\\"sold_product_565970_25000, sold_product_565970_20678\\",\\"85, 16.984\\",\\"85, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"40.813, 7.82\\",\\"85, 16.984\\",\\"25,000, 20,678\\",\\"Ankle boots - setter, Long sleeved top - black\\",\\"Ankle boots - setter, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0673406734, ZO0165601656\\",\\"0, 0\\",\\"85, 16.984\\",\\"85, 16.984\\",\\"0, 0\\",\\"ZO0673406734, ZO0165601656\\",102,102,2,2,order,clarice +kgMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Richards\\",\\"Elyssa Richards\\",FEMALE,27,Richards,Richards,\\"(empty)\\",Monday,0,\\"elyssa@richards-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Spherecords, Tigress Enterprises\\",\\"Oceanavigations, Spherecords, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",723242,\\"sold_product_723242_5979, sold_product_723242_12451, sold_product_723242_13462, sold_product_723242_14976\\",\\"sold_product_723242_5979, sold_product_723242_12451, sold_product_723242_13462, sold_product_723242_14976\\",\\"75, 7.988, 24.984, 16.984\\",\\"75, 7.988, 24.984, 16.984\\",\\"Women's Shoes, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Spherecords, Tigress Enterprises, Spherecords\\",\\"Oceanavigations, Spherecords, Tigress Enterprises, Spherecords\\",\\"33.75, 3.68, 11.75, 9.172\\",\\"75, 7.988, 24.984, 16.984\\",\\"5,979, 12,451, 13,462, 14,976\\",\\"Ankle boots - Antique White, Vest - black, Handbag - cognac , Mini skirt - dark blue\\",\\"Ankle boots - Antique White, Vest - black, Handbag - cognac , Mini skirt - dark blue\\",\\"1, 1, 1, 1\\",\\"ZO0249702497, ZO0643306433, ZO0088900889, ZO0634406344\\",\\"0, 0, 0, 0\\",\\"75, 7.988, 24.984, 16.984\\",\\"75, 7.988, 24.984, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0249702497, ZO0643306433, ZO0088900889, ZO0634406344\\",\\"124.938\\",\\"124.938\\",4,4,order,elyssa +mAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Cook\\",\\"Abd Cook\\",MALE,52,Cook,Cook,\\"(empty)\\",Monday,0,\\"abd@cook-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",720399,\\"sold_product_720399_11133, sold_product_720399_24282, sold_product_720399_1435, sold_product_720399_13054\\",\\"sold_product_720399_11133, sold_product_720399_24282, sold_product_720399_1435, sold_product_720399_13054\\",\\"24.984, 7.988, 75, 24.984\\",\\"24.984, 7.988, 75, 24.984\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence, Low Tide Media, Elitelligence\\",\\"12.25, 4.148, 34.5, 13.742\\",\\"24.984, 7.988, 75, 24.984\\",\\"11,133, 24,282, 1,435, 13,054\\",\\"Smart lace-ups - black, Print T-shirt - bordeaux, Lace-up boots - Peru, Sweatshirt - black/red/white\\",\\"Smart lace-ups - black, Print T-shirt - bordeaux, Lace-up boots - Peru, Sweatshirt - black/red/white\\",\\"1, 1, 1, 1\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\",\\"0, 0, 0, 0\\",\\"24.984, 7.988, 75, 24.984\\",\\"24.984, 7.988, 75, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\",133,133,4,4,order,abd +vQMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Hopkins\\",\\"Hicham Hopkins\\",MALE,8,Hopkins,Hopkins,\\"(empty)\\",Monday,0,\\"hicham@hopkins-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566580,\\"sold_product_566580_19404, sold_product_566580_16718\\",\\"sold_product_566580_19404, sold_product_566580_16718\\",\\"33, 33\\",\\"33, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"17.484, 17.813\\",\\"33, 33\\",\\"19,404, 16,718\\",\\"Shirt - olive, Tracksuit top - black\\",\\"Shirt - olive, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0417304173, ZO0123001230\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0417304173, ZO0123001230\\",66,66,2,2,order,hicham +ygMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Moran\\",\\"Robbie Moran\\",MALE,48,Moran,Moran,\\"(empty)\\",Monday,0,\\"robbie@moran-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566671,\\"sold_product_566671_22991, sold_product_566671_17752\\",\\"sold_product_566671_22991, sold_product_566671_17752\\",\\"50, 37\\",\\"50, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"23, 17.391\\",\\"50, 37\\",\\"22,991, 17,752\\",\\"SOLID - Summer jacket - mustard, Slim fit jeans - black denim\\",\\"SOLID - Summer jacket - mustard, Slim fit jeans - black denim\\",\\"1, 1\\",\\"ZO0427604276, ZO0113801138\\",\\"0, 0\\",\\"50, 37\\",\\"50, 37\\",\\"0, 0\\",\\"ZO0427604276, ZO0113801138\\",87,87,2,2,order,robbie +zgMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Watkins\\",\\"Abd Watkins\\",MALE,52,Watkins,Watkins,\\"(empty)\\",Monday,0,\\"abd@watkins-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566176,\\"sold_product_566176_15205, sold_product_566176_7038\\",\\"sold_product_566176_15205, sold_product_566176_7038\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"13.242, 44.188\\",\\"24.984, 85\\",\\"15,205, 7,038\\",\\"Briefcase - black , Parka - mustard\\",\\"Briefcase - black , Parka - mustard\\",\\"1, 1\\",\\"ZO0607206072, ZO0431404314\\",\\"0, 0\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"0, 0\\",\\"ZO0607206072, ZO0431404314\\",110,110,2,2,order,abd +zwMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Carr\\",\\"rania Carr\\",FEMALE,24,Carr,Carr,\\"(empty)\\",Monday,0,\\"rania@carr-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566146,\\"sold_product_566146_24862, sold_product_566146_22163\\",\\"sold_product_566146_24862, sold_product_566146_22163\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.5, 10.703\\",\\"10.992, 20.984\\",\\"24,862, 22,163\\",\\"Print T-shirt - dark blue/off white, Leggings - black\\",\\"Print T-shirt - dark blue/off white, Leggings - black\\",\\"1, 1\\",\\"ZO0646206462, ZO0146201462\\",\\"0, 0\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"0, 0\\",\\"ZO0646206462, ZO0146201462\\",\\"31.984\\",\\"31.984\\",2,2,order,rani +kgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Dawson\\",\\"Abigail Dawson\\",FEMALE,46,Dawson,Dawson,\\"(empty)\\",Monday,0,\\"abigail@dawson-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Champion Arts, Pyramidustries active\\",\\"Champion Arts, Pyramidustries active\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565760,\\"sold_product_565760_21930, sold_product_565760_9980\\",\\"sold_product_565760_21930, sold_product_565760_9980\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Pyramidustries active\\",\\"Champion Arts, Pyramidustries active\\",\\"22.5, 9.867\\",\\"50, 20.984\\",\\"21,930, 9,980\\",\\"Classic coat - black/white, Tights - poseidon\\",\\"Classic coat - black/white, Tights - poseidon\\",\\"1, 1\\",\\"ZO0504505045, ZO0223802238\\",\\"0, 0\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"0, 0\\",\\"ZO0504505045, ZO0223802238\\",71,71,2,2,order,abigail +mAMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Lloyd\\",\\"Diane Lloyd\\",FEMALE,22,Lloyd,Lloyd,\\"(empty)\\",Monday,0,\\"diane@lloyd-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords, Crystal Lighting\\",\\"Spherecords, Crystal Lighting\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565521,\\"sold_product_565521_12423, sold_product_565521_11487\\",\\"sold_product_565521_12423, sold_product_565521_11487\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Crystal Lighting\\",\\"Spherecords, Crystal Lighting\\",\\"6.898, 38.25\\",\\"14.992, 85\\",\\"12,423, 11,487\\",\\"Nightie - black/off white, Snowboard jacket - coralle/grey multicolor\\",\\"Nightie - black/off white, Snowboard jacket - coralle/grey multicolor\\",\\"1, 1\\",\\"ZO0660406604, ZO0484504845\\",\\"0, 0\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"0, 0\\",\\"ZO0660406604, ZO0484504845\\",100,100,2,2,order,diane +nQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Martin\\",\\"Mary Martin\\",FEMALE,20,Martin,Martin,\\"(empty)\\",Monday,0,\\"mary@martin-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises Curvy, Spherecords\\",\\"Tigress Enterprises Curvy, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566320,\\"sold_product_566320_14149, sold_product_566320_23774\\",\\"sold_product_566320_14149, sold_product_566320_23774\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Spherecords\\",\\"Tigress Enterprises Curvy, Spherecords\\",\\"13.492, 7.941\\",\\"24.984, 14.992\\",\\"14,149, 23,774\\",\\"Blouse - Medium Sea Green, Cardigan - dark blue\\",\\"Blouse - Medium Sea Green, Cardigan - dark blue\\",\\"1, 1\\",\\"ZO0105001050, ZO0652306523\\",\\"0, 0\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"0, 0\\",\\"ZO0105001050, ZO0652306523\\",\\"39.969\\",\\"39.969\\",2,2,order,mary +ngMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Cortez\\",\\"Stephanie Cortez\\",FEMALE,6,Cortez,Cortez,\\"(empty)\\",Monday,0,\\"stephanie@cortez-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566357,\\"sold_product_566357_14019, sold_product_566357_14225\\",\\"sold_product_566357_14019, sold_product_566357_14225\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"13.242, 7.82\\",\\"24.984, 16.984\\",\\"14,019, 14,225\\",\\"Vest - black, Sweatshirt - dark grey multicolor\\",\\"Vest - black, Sweatshirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0061600616, ZO0180701807\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0061600616, ZO0180701807\\",\\"41.969\\",\\"41.969\\",2,2,order,stephanie +nwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,rania,rania,\\"rania Howell\\",\\"rania Howell\\",FEMALE,24,Howell,Howell,\\"(empty)\\",Monday,0,\\"rania@howell-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566415,\\"sold_product_566415_18928, sold_product_566415_17913\\",\\"sold_product_566415_18928, sold_product_566415_17913\\",\\"50, 75\\",\\"50, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"25.984, 36.75\\",\\"50, 75\\",\\"18,928, 17,913\\",\\"Summer dress - black/red, Wedges - white\\",\\"Summer dress - black/red, Wedges - white\\",\\"1, 1\\",\\"ZO0261102611, ZO0667106671\\",\\"0, 0\\",\\"50, 75\\",\\"50, 75\\",\\"0, 0\\",\\"ZO0261102611, ZO0667106671\\",125,125,2,2,order,rani +wQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Jackson\\",\\"Mostafa Jackson\\",MALE,9,Jackson,Jackson,\\"(empty)\\",Monday,0,\\"mostafa@jackson-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566044,\\"sold_product_566044_19539, sold_product_566044_19704\\",\\"sold_product_566044_19539, sold_product_566044_19704\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"5.059, 6.859\\",\\"10.992, 13.992\\",\\"19,539, 19,704\\",\\"Print T-shirt - white, Print T-shirt - grey multicolor\\",\\"Print T-shirt - white, Print T-shirt - grey multicolor\\",\\"1, 1\\",\\"ZO0552605526, ZO0292702927\\",\\"0, 0\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"0, 0\\",\\"ZO0552605526, ZO0292702927\\",\\"24.984\\",\\"24.984\\",2,2,order,mostafa +8QMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Diane,Diane,\\"Diane Reese\\",\\"Diane Reese\\",FEMALE,22,Reese,Reese,\\"(empty)\\",Monday,0,\\"diane@reese-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565473,\\"sold_product_565473_13838, sold_product_565473_13437\\",\\"sold_product_565473_13838, sold_product_565473_13437\\",\\"42, 50\\",\\"42, 50\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"19.734, 22.5\\",\\"42, 50\\",\\"13,838, 13,437\\",\\"Ballet pumps - cognac, Ballet pumps - black\\",\\"Ballet pumps - cognac, Ballet pumps - black\\",\\"1, 1\\",\\"ZO0365303653, ZO0235802358\\",\\"0, 0\\",\\"42, 50\\",\\"42, 50\\",\\"0, 0\\",\\"ZO0365303653, ZO0235802358\\",92,92,2,2,order,diane +9AMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Mccormick\\",\\"Clarice Mccormick\\",FEMALE,18,Mccormick,Mccormick,\\"(empty)\\",Monday,0,\\"clarice@mccormick-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565339,\\"sold_product_565339_21573, sold_product_565339_15153\\",\\"sold_product_565339_21573, sold_product_565339_15153\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"17.156, 39\\",\\"33, 75\\",\\"21,573, 15,153\\",\\"Print T-shirt - Yellow, Ankle boots - black\\",\\"Print T-shirt - Yellow, Ankle boots - black\\",\\"1, 1\\",\\"ZO0346503465, ZO0678406784\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0346503465, ZO0678406784\\",108,108,2,2,order,clarice +ZgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Bryant\\",\\"Irwin Bryant\\",MALE,14,Bryant,Bryant,\\"(empty)\\",Monday,0,\\"irwin@bryant-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565591,\\"sold_product_565591_1910, sold_product_565591_12445\\",\\"sold_product_565591_1910, sold_product_565591_12445\\",\\"65, 42\\",\\"65, 42\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"31.844, 21.406\\",\\"65, 42\\",\\"1,910, 12,445\\",\\"Smart lace-ups - black, Waistcoat - light grey\\",\\"Smart lace-ups - black, Waistcoat - light grey\\",\\"1, 1\\",\\"ZO0683806838, ZO0429204292\\",\\"0, 0\\",\\"65, 42\\",\\"65, 42\\",\\"0, 0\\",\\"ZO0683806838, ZO0429204292\\",107,107,2,2,order,irwin +eAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Maldonado\\",\\"Rabbia Al Maldonado\\",FEMALE,5,Maldonado,Maldonado,\\"(empty)\\",Monday,0,\\"rabbia al@maldonado-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Champion Arts, Pyramidustries, Primemaster, Angeldale\\",\\"Champion Arts, Pyramidustries, Primemaster, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",730725,\\"sold_product_730725_17276, sold_product_730725_15007, sold_product_730725_5421, sold_product_730725_16594\\",\\"sold_product_730725_17276, sold_product_730725_15007, sold_product_730725_5421, sold_product_730725_16594\\",\\"20.984, 11.992, 185, 65\\",\\"20.984, 11.992, 185, 65\\",\\"Women's Clothing, Women's Accessories, Women's Shoes, Women's Accessories\\",\\"Women's Clothing, Women's Accessories, Women's Shoes, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Champion Arts, Pyramidustries, Primemaster, Angeldale\\",\\"Champion Arts, Pyramidustries, Primemaster, Angeldale\\",\\"10.078, 5.52, 83.25, 29.906\\",\\"20.984, 11.992, 185, 65\\",\\"17,276, 15,007, 5,421, 16,594\\",\\"Jumper - blue multicolor, Watch - grey, High heeled boots - brown, Handbag - black\\",\\"Jumper - blue multicolor, Watch - grey, High heeled boots - brown, Handbag - black\\",\\"1, 1, 1, 1\\",\\"ZO0501605016, ZO0189601896, ZO0363003630, ZO0699306993\\",\\"0, 0, 0, 0\\",\\"20.984, 11.992, 185, 65\\",\\"20.984, 11.992, 185, 65\\",\\"0, 0, 0, 0\\",\\"ZO0501605016, ZO0189601896, ZO0363003630, ZO0699306993\\",283,283,4,4,order,rabbia +1wMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Craig\\",\\"Pia Craig\\",FEMALE,45,Craig,Craig,\\"(empty)\\",Monday,0,\\"pia@craig-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566443,\\"sold_product_566443_22619, sold_product_566443_24107\\",\\"sold_product_566443_22619, sold_product_566443_24107\\",\\"17.984, 33\\",\\"17.984, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"8.102, 15.18\\",\\"17.984, 33\\",\\"22,619, 24,107\\",\\"Long sleeved top - black, Jumper dress - grey multicolor\\",\\"Long sleeved top - black, Jumper dress - grey multicolor\\",\\"1, 1\\",\\"ZO0160201602, ZO0261502615\\",\\"0, 0\\",\\"17.984, 33\\",\\"17.984, 33\\",\\"0, 0\\",\\"ZO0160201602, ZO0261502615\\",\\"50.969\\",\\"50.969\\",2,2,order,pia +2AMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Little\\",\\"Marwan Little\\",MALE,51,Little,Little,\\"(empty)\\",Monday,0,\\"marwan@little-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566498,\\"sold_product_566498_17075, sold_product_566498_11878\\",\\"sold_product_566498_17075, sold_product_566498_11878\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"31.797, 5.059\\",\\"60, 10.992\\",\\"17,075, 11,878\\",\\"Smart lace-ups - cognac, Long sleeved top - bordeaux\\",\\"Smart lace-ups - cognac, Long sleeved top - bordeaux\\",\\"1, 1\\",\\"ZO0387103871, ZO0550005500\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0387103871, ZO0550005500\\",71,71,2,2,order,marwan +2wMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Perkins\\",\\"Abdulraheem Al Perkins\\",MALE,33,Perkins,Perkins,\\"(empty)\\",Monday,0,\\"abdulraheem al@perkins-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565985,\\"sold_product_565985_22376, sold_product_565985_6969\\",\\"sold_product_565985_22376, sold_product_565985_6969\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"5.602, 12.742\\",\\"10.992, 24.984\\",\\"22,376, 6,969\\",\\"Long sleeved top - white, Shirt - blue\\",\\"Long sleeved top - white, Shirt - blue\\",\\"1, 1\\",\\"ZO0436604366, ZO0280302803\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0436604366, ZO0280302803\\",\\"35.969\\",\\"35.969\\",2,2,order,abdulraheem +3QMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Dawson\\",\\"Abigail Dawson\\",FEMALE,46,Dawson,Dawson,\\"(empty)\\",Monday,0,\\"abigail@dawson-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565640,\\"sold_product_565640_11983, sold_product_565640_18500\\",\\"sold_product_565640_11983, sold_product_565640_18500\\",\\"24.984, 44\\",\\"24.984, 44\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"12.492, 22\\",\\"24.984, 44\\",\\"11,983, 18,500\\",\\"Summer dress - red, Jersey dress - black/grey\\",\\"Summer dress - red, Jersey dress - black/grey\\",\\"1, 1\\",\\"ZO0631606316, ZO0045300453\\",\\"0, 0\\",\\"24.984, 44\\",\\"24.984, 44\\",\\"0, 0\\",\\"ZO0631606316, ZO0045300453\\",69,69,2,2,order,abigail +3gMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Frances,Frances,\\"Frances Morrison\\",\\"Frances Morrison\\",FEMALE,49,Morrison,Morrison,\\"(empty)\\",Monday,0,\\"frances@morrison-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565683,\\"sold_product_565683_11862, sold_product_565683_16135\\",\\"sold_product_565683_11862, sold_product_565683_16135\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.492, 8.656\\",\\"22.984, 16.984\\",\\"11,862, 16,135\\",\\"Jumper - black, Belt - dark brown\\",\\"Jumper - black, Belt - dark brown\\",\\"1, 1\\",\\"ZO0573205732, ZO0310303103\\",\\"0, 0\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"0, 0\\",\\"ZO0573205732, ZO0310303103\\",\\"39.969\\",\\"39.969\\",2,2,order,frances +\\"-QMtOW0BH63Xcmy4524Z\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Wise\\",\\"Yuri Wise\\",MALE,21,Wise,Wise,\\"(empty)\\",Monday,0,\\"yuri@wise-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565767,\\"sold_product_565767_18958, sold_product_565767_24243\\",\\"sold_product_565767_18958, sold_product_565767_24243\\",\\"26.984, 24.984\\",\\"26.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"14.031, 13.242\\",\\"26.984, 24.984\\",\\"18,958, 24,243\\",\\"Formal shirt - white, Slim fit jeans - dirty denim\\",\\"Formal shirt - white, Slim fit jeans - dirty denim\\",\\"1, 1\\",\\"ZO0414304143, ZO0425204252\\",\\"0, 0\\",\\"26.984, 24.984\\",\\"26.984, 24.984\\",\\"0, 0\\",\\"ZO0414304143, ZO0425204252\\",\\"51.969\\",\\"51.969\\",2,2,order,yuri +IAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Salazar\\",\\"Sonya Salazar\\",FEMALE,28,Salazar,Salazar,\\"(empty)\\",Monday,0,\\"sonya@salazar-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566452,\\"sold_product_566452_11504, sold_product_566452_16385\\",\\"sold_product_566452_11504, sold_product_566452_16385\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"5.879, 13.047\\",\\"11.992, 28.984\\",\\"11,504, 16,385\\",\\"Basic T-shirt - darkblue/white, Sandals - gold\\",\\"Basic T-shirt - darkblue/white, Sandals - gold\\",\\"1, 1\\",\\"ZO0706307063, ZO0011300113\\",\\"0, 0\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"0, 0\\",\\"ZO0706307063, ZO0011300113\\",\\"40.969\\",\\"40.969\\",2,2,order,sonya +IgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Jackson,Jackson,\\"Jackson Willis\\",\\"Jackson Willis\\",MALE,13,Willis,Willis,\\"(empty)\\",Monday,0,\\"jackson@willis-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565982,\\"sold_product_565982_15828, sold_product_565982_15722\\",\\"sold_product_565982_15828, sold_product_565982_15722\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"5.172, 7.41\\",\\"10.992, 13.992\\",\\"15,828, 15,722\\",\\"Tie - black, Belt - brown\\",\\"Tie - black, Belt - brown\\",\\"1, 1\\",\\"ZO0410804108, ZO0309303093\\",\\"0, 0\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"0, 0\\",\\"ZO0410804108, ZO0309303093\\",\\"24.984\\",\\"24.984\\",2,2,order,jackson +UAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Simpson\\",\\"Rabbia Al Simpson\\",FEMALE,5,Simpson,Simpson,\\"(empty)\\",Monday,0,\\"rabbia al@simpson-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Pyramidustries, Spherecords, Tigress Enterprises MAMA\\",\\"Pyramidustries, Spherecords, Tigress Enterprises MAMA\\",\\"Jun 23, 2019 @ 00:00:00.000\\",726754,\\"sold_product_726754_17171, sold_product_726754_25083, sold_product_726754_21081, sold_product_726754_13554\\",\\"sold_product_726754_17171, sold_product_726754_25083, sold_product_726754_21081, sold_product_726754_13554\\",\\"33, 10.992, 16.984, 24.984\\",\\"33, 10.992, 16.984, 24.984\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Spherecords, Pyramidustries, Tigress Enterprises MAMA\\",\\"Pyramidustries, Spherecords, Pyramidustries, Tigress Enterprises MAMA\\",\\"16.813, 5.172, 8.156, 12.25\\",\\"33, 10.992, 16.984, 24.984\\",\\"17,171, 25,083, 21,081, 13,554\\",\\"Platform sandals - black, Basic T-shirt - dark blue, Cape - black/offwhite, Jersey dress - black\\",\\"Platform sandals - black, Basic T-shirt - dark blue, Cape - black/offwhite, Jersey dress - black\\",\\"1, 1, 1, 1\\",\\"ZO0138001380, ZO0648006480, ZO0193501935, ZO0228402284\\",\\"0, 0, 0, 0\\",\\"33, 10.992, 16.984, 24.984\\",\\"33, 10.992, 16.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0138001380, ZO0648006480, ZO0193501935, ZO0228402284\\",\\"85.938\\",\\"85.938\\",4,4,order,rabbia +YAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,rania,rania,\\"rania Nash\\",\\"rania Nash\\",FEMALE,24,Nash,Nash,\\"(empty)\\",Monday,0,\\"rania@nash-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Oceanavigations,Oceanavigations,\\"Jun 23, 2019 @ 00:00:00.000\\",565723,\\"sold_product_565723_15629, sold_product_565723_18709\\",\\"sold_product_565723_15629, sold_product_565723_18709\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"15.18, 39.75\\",\\"33, 75\\",\\"15,629, 18,709\\",\\"Watch - gold-coloured, Boots - nude\\",\\"Watch - gold-coloured, Boots - nude\\",\\"1, 1\\",\\"ZO0302303023, ZO0246602466\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0302303023, ZO0246602466\\",108,108,2,2,order,rani +agMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Hayes\\",\\"Youssef Hayes\\",MALE,31,Hayes,Hayes,\\"(empty)\\",Monday,0,\\"youssef@hayes-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565896,\\"sold_product_565896_13186, sold_product_565896_15296\\",\\"sold_product_565896_13186, sold_product_565896_15296\\",\\"42, 18.984\\",\\"42, 18.984\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"21.828, 9.117\\",\\"42, 18.984\\",\\"13,186, 15,296\\",\\"Across body bag - navy, Polo shirt - red\\",\\"Across body bag - navy, Polo shirt - red\\",\\"1, 1\\",\\"ZO0466104661, ZO0444104441\\",\\"0, 0\\",\\"42, 18.984\\",\\"42, 18.984\\",\\"0, 0\\",\\"ZO0466104661, ZO0444104441\\",\\"60.969\\",\\"60.969\\",2,2,order,youssef +jgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Summers\\",\\"Abd Summers\\",MALE,52,Summers,Summers,\\"(empty)\\",Monday,0,\\"abd@summers-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Microlutions, Oceanavigations, Elitelligence\\",\\"Microlutions, Oceanavigations, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",718085,\\"sold_product_718085_20302, sold_product_718085_15787, sold_product_718085_11532, sold_product_718085_13238\\",\\"sold_product_718085_20302, sold_product_718085_15787, sold_product_718085_11532, sold_product_718085_13238\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"Men's Clothing, Men's Accessories, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Microlutions, Oceanavigations, Elitelligence, Elitelligence\\",\\"Microlutions, Oceanavigations, Elitelligence, Elitelligence\\",\\"7.27, 8.469, 3.76, 4.949\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"20,302, 15,787, 11,532, 13,238\\",\\"3 PACK - Shorts - khaki/camo, Belt - black, Basic T-shirt - khaki, Print T-shirt - beige\\",\\"3 PACK - Shorts - khaki/camo, Belt - black, Basic T-shirt - khaki, Print T-shirt - beige\\",\\"1, 1, 1, 1\\",\\"ZO0129001290, ZO0310103101, ZO0547805478, ZO0560805608\\",\\"0, 0, 0, 0\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0129001290, ZO0310103101, ZO0547805478, ZO0560805608\\",\\"48.969\\",\\"48.969\\",4,4,order,abd +zQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Bryant\\",\\"Rabbia Al Bryant\\",FEMALE,5,Bryant,Bryant,\\"(empty)\\",Monday,0,\\"rabbia al@bryant-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566248,\\"sold_product_566248_14303, sold_product_566248_14542\\",\\"sold_product_566248_14303, sold_product_566248_14542\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"36, 13.242\\",\\"75, 24.984\\",\\"14,303, 14,542\\",\\"Ankle boots - black, Tote bag - black\\",\\"Ankle boots - black, Tote bag - black\\",\\"1, 1\\",\\"ZO0678806788, ZO0186101861\\",\\"0, 0\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"0, 0\\",\\"ZO0678806788, ZO0186101861\\",100,100,2,2,order,rabbia +2QMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Alvarez\\",\\"Fitzgerald Alvarez\\",MALE,11,Alvarez,Alvarez,\\"(empty)\\",Monday,0,\\"fitzgerald@alvarez-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565560,\\"sold_product_565560_23771, sold_product_565560_18408\\",\\"sold_product_565560_23771, sold_product_565560_18408\\",\\"10.992, 11.992\\",\\"10.992, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.5, 6.352\\",\\"10.992, 11.992\\",\\"23,771, 18,408\\",\\"Basic T-shirt - Medium Slate Blue, Polo shirt - black\\",\\"Basic T-shirt - Medium Slate Blue, Polo shirt - black\\",\\"1, 1\\",\\"ZO0567505675, ZO0442104421\\",\\"0, 0\\",\\"10.992, 11.992\\",\\"10.992, 11.992\\",\\"0, 0\\",\\"ZO0567505675, ZO0442104421\\",\\"22.984\\",\\"22.984\\",2,2,order,fuzzy +IQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Hale\\",\\"Hicham Hale\\",MALE,8,Hale,Hale,\\"(empty)\\",Monday,0,\\"hicham@hale-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566186,\\"sold_product_566186_24868, sold_product_566186_23962\\",\\"sold_product_566186_24868, sold_product_566186_23962\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.703, 11.5\\",\\"20.984, 24.984\\",\\"24,868, 23,962\\",\\"Walking sandals - white/grey/black, Sweatshirt - navy multicolor \\",\\"Walking sandals - white/grey/black, Sweatshirt - navy multicolor \\",\\"1, 1\\",\\"ZO0522105221, ZO0459104591\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0522105221, ZO0459104591\\",\\"45.969\\",\\"45.969\\",2,2,order,hicham +IgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Foster\\",\\"Wilhemina St. Foster\\",FEMALE,17,Foster,Foster,\\"(empty)\\",Monday,0,\\"wilhemina st.@foster-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Champion Arts, Pyramidustries\\",\\"Champion Arts, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566155,\\"sold_product_566155_13946, sold_product_566155_21158\\",\\"sold_product_566155_13946, sold_product_566155_21158\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Pyramidustries\\",\\"Champion Arts, Pyramidustries\\",\\"9.656, 12.25\\",\\"20.984, 24.984\\",\\"13,946, 21,158\\",\\"Hoodie - dark grey multicolor, Pyjamas - light pink\\",\\"Hoodie - dark grey multicolor, Pyjamas - light pink\\",\\"1, 1\\",\\"ZO0501005010, ZO0214002140\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0501005010, ZO0214002140\\",\\"45.969\\",\\"45.969\\",2,2,order,wilhemina +IwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Dawson\\",\\"Sonya Dawson\\",FEMALE,28,Dawson,Dawson,\\"(empty)\\",Monday,0,\\"sonya@dawson-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566628,\\"sold_product_566628_11077, sold_product_566628_19514\\",\\"sold_product_566628_11077, sold_product_566628_19514\\",\\"24.984, 11.992\\",\\"24.984, 11.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"12.492, 6.352\\",\\"24.984, 11.992\\",\\"11,077, 19,514\\",\\"Tote bag - cognac, 3 PACK - Shorts - teal/dark purple/black\\",\\"Tote bag - cognac, 3 PACK - Shorts - teal/dark purple/black\\",\\"1, 1\\",\\"ZO0195601956, ZO0098900989\\",\\"0, 0\\",\\"24.984, 11.992\\",\\"24.984, 11.992\\",\\"0, 0\\",\\"ZO0195601956, ZO0098900989\\",\\"36.969\\",\\"36.969\\",2,2,order,sonya +JAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Phillips\\",\\"Mostafa Phillips\\",MALE,9,Phillips,Phillips,\\"(empty)\\",Monday,0,\\"mostafa@phillips-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Angeldale, Microlutions\\",\\"Angeldale, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566519,\\"sold_product_566519_21909, sold_product_566519_12714\\",\\"sold_product_566519_21909, sold_product_566519_12714\\",\\"16.984, 85\\",\\"16.984, 85\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Microlutions\\",\\"Angeldale, Microlutions\\",\\"9.172, 40.813\\",\\"16.984, 85\\",\\"21,909, 12,714\\",\\"Belt - black, Classic coat - black\\",\\"Belt - black, Classic coat - black\\",\\"1, 1\\",\\"ZO0700907009, ZO0115801158\\",\\"0, 0\\",\\"16.984, 85\\",\\"16.984, 85\\",\\"0, 0\\",\\"ZO0700907009, ZO0115801158\\",102,102,2,2,order,mostafa +JQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Powell\\",\\"Stephanie Powell\\",FEMALE,6,Powell,Powell,\\"(empty)\\",Monday,0,\\"stephanie@powell-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Champion Arts, Spherecords\\",\\"Champion Arts, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565697,\\"sold_product_565697_11530, sold_product_565697_17565\\",\\"sold_product_565697_11530, sold_product_565697_17565\\",\\"16.984, 11.992\\",\\"16.984, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Spherecords\\",\\"Champion Arts, Spherecords\\",\\"8.156, 6\\",\\"16.984, 11.992\\",\\"11,530, 17,565\\",\\"Hoodie - dark red, 2 PACK - Vest - black/nude\\",\\"Hoodie - dark red, 2 PACK - Vest - black/nude\\",\\"1, 1\\",\\"ZO0498904989, ZO0641706417\\",\\"0, 0\\",\\"16.984, 11.992\\",\\"16.984, 11.992\\",\\"0, 0\\",\\"ZO0498904989, ZO0641706417\\",\\"28.984\\",\\"28.984\\",2,2,order,stephanie +JgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Pia,Pia,\\"Pia Ramsey\\",\\"Pia Ramsey\\",FEMALE,45,Ramsey,Ramsey,\\"(empty)\\",Monday,0,\\"pia@ramsey-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566417,\\"sold_product_566417_14379, sold_product_566417_13936\\",\\"sold_product_566417_14379, sold_product_566417_13936\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"6.469, 5.52\\",\\"11.992, 11.992\\",\\"14,379, 13,936\\",\\"Snood - grey, Scarf - bordeaux\\",\\"Snood - grey, Scarf - bordeaux\\",\\"1, 1\\",\\"ZO0084900849, ZO0194701947\\",\\"0, 0\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"0, 0\\",\\"ZO0084900849, ZO0194701947\\",\\"23.984\\",\\"23.984\\",2,2,order,pia +fwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Mccarthy\\",\\"Pia Mccarthy\\",FEMALE,45,Mccarthy,Mccarthy,\\"(empty)\\",Monday,0,\\"pia@mccarthy-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565722,\\"sold_product_565722_12551, sold_product_565722_22941\\",\\"sold_product_565722_12551, sold_product_565722_22941\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"8.328, 5.82\\",\\"16.984, 10.992\\",\\"12,551, 22,941\\",\\"Cardigan - light grey multicolor, Print T-shirt - dark blue/red\\",\\"Cardigan - light grey multicolor, Print T-shirt - dark blue/red\\",\\"1, 1\\",\\"ZO0656406564, ZO0495504955\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0656406564, ZO0495504955\\",\\"27.984\\",\\"27.984\\",2,2,order,pia +lAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Foster\\",\\"Boris Foster\\",MALE,36,Foster,Foster,\\"(empty)\\",Monday,0,\\"boris@foster-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Spritechnologies,Spritechnologies,\\"Jun 23, 2019 @ 00:00:00.000\\",565330,\\"sold_product_565330_16276, sold_product_565330_24760\\",\\"sold_product_565330_16276, sold_product_565330_24760\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Spritechnologies\\",\\"Spritechnologies, Spritechnologies\\",\\"9.453, 26.484\\",\\"20.984, 50\\",\\"16,276, 24,760\\",\\"Tracksuit bottoms - dark grey multicolor, Sweatshirt - black\\",\\"Tracksuit bottoms - dark grey multicolor, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0621606216, ZO0628806288\\",\\"0, 0\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"0, 0\\",\\"ZO0621606216, ZO0628806288\\",71,71,2,2,order,boris +lQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Betty,Betty,\\"Betty Graham\\",\\"Betty Graham\\",FEMALE,44,Graham,Graham,\\"(empty)\\",Monday,0,\\"betty@graham-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565381,\\"sold_product_565381_23349, sold_product_565381_12141\\",\\"sold_product_565381_23349, sold_product_565381_12141\\",\\"16.984, 7.988\\",\\"16.984, 7.988\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"8.328, 4.148\\",\\"16.984, 7.988\\",\\"23,349, 12,141\\",\\"Basic T-shirt - black, Belt - taupe\\",\\"Basic T-shirt - black, Belt - taupe\\",\\"1, 1\\",\\"ZO0060200602, ZO0076300763\\",\\"0, 0\\",\\"16.984, 7.988\\",\\"16.984, 7.988\\",\\"0, 0\\",\\"ZO0060200602, ZO0076300763\\",\\"24.984\\",\\"24.984\\",2,2,order,betty +vQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Riley\\",\\"Kamal Riley\\",MALE,39,Riley,Riley,\\"(empty)\\",Monday,0,\\"kamal@riley-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565564,\\"sold_product_565564_19843, sold_product_565564_10979\\",\\"sold_product_565564_19843, sold_product_565564_10979\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"12.492, 7.988\\",\\"24.984, 16.984\\",\\"19,843, 10,979\\",\\"Cardigan - white/blue/khaki, Print T-shirt - dark green\\",\\"Cardigan - white/blue/khaki, Print T-shirt - dark green\\",\\"1, 1\\",\\"ZO0576305763, ZO0116801168\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0576305763, ZO0116801168\\",\\"41.969\\",\\"41.969\\",2,2,order,kamal +wAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Parker\\",\\"Thad Parker\\",MALE,30,Parker,Parker,\\"(empty)\\",Monday,0,\\"thad@parker-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565392,\\"sold_product_565392_17873, sold_product_565392_14058\\",\\"sold_product_565392_17873, sold_product_565392_14058\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"5.602, 10.492\\",\\"10.992, 20.984\\",\\"17,873, 14,058\\",\\"Sports shirt - Seashell, Sweatshirt - mottled light grey\\",\\"Sports shirt - Seashell, Sweatshirt - mottled light grey\\",\\"1, 1\\",\\"ZO0616606166, ZO0592205922\\",\\"0, 0\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"0, 0\\",\\"ZO0616606166, ZO0592205922\\",\\"31.984\\",\\"31.984\\",2,2,order,thad +wQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Stephanie,Stephanie,\\"Stephanie Henderson\\",\\"Stephanie Henderson\\",FEMALE,6,Henderson,Henderson,\\"(empty)\\",Monday,0,\\"stephanie@henderson-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Karmanite\\",\\"Tigress Enterprises, Karmanite\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565410,\\"sold_product_565410_22028, sold_product_565410_5066\\",\\"sold_product_565410_22028, sold_product_565410_5066\\",\\"33, 100\\",\\"33, 100\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Karmanite\\",\\"Tigress Enterprises, Karmanite\\",\\"15.844, 45\\",\\"33, 100\\",\\"22,028, 5,066\\",\\"Ankle boots - cognac, Boots - black\\",\\"Ankle boots - cognac, Boots - black\\",\\"1, 1\\",\\"ZO0023600236, ZO0704307043\\",\\"0, 0\\",\\"33, 100\\",\\"33, 100\\",\\"0, 0\\",\\"ZO0023600236, ZO0704307043\\",133,133,2,2,order,stephanie +\\"-AMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Walters\\",\\"Elyssa Walters\\",FEMALE,27,Walters,Walters,\\"(empty)\\",Monday,0,\\"elyssa@walters-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565504,\\"sold_product_565504_21839, sold_product_565504_19546\\",\\"sold_product_565504_21839, sold_product_565504_19546\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"11.75, 21\\",\\"24.984, 42\\",\\"21,839, 19,546\\",\\"Jumper - dark grey multicolor, Summer dress - black\\",\\"Jumper - dark grey multicolor, Summer dress - black\\",\\"1, 1\\",\\"ZO0653406534, ZO0049300493\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0653406534, ZO0049300493\\",67,67,2,2,order,elyssa +\\"-wMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Allison\\",\\"Betty Allison\\",FEMALE,44,Allison,Allison,\\"(empty)\\",Monday,0,\\"betty@allison-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565334,\\"sold_product_565334_17565, sold_product_565334_24798\\",\\"sold_product_565334_17565, sold_product_565334_24798\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"6, 35.25\\",\\"11.992, 75\\",\\"17,565, 24,798\\",\\"2 PACK - Vest - black/nude, Lace-up boots - black\\",\\"2 PACK - Vest - black/nude, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0641706417, ZO0382303823\\",\\"0, 0\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"0, 0\\",\\"ZO0641706417, ZO0382303823\\",87,87,2,2,order,betty +IQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Phil,Phil,\\"Phil Strickland\\",\\"Phil Strickland\\",MALE,50,Strickland,Strickland,\\"(empty)\\",Monday,0,\\"phil@strickland-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords, Angeldale\\",\\"Spherecords, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566079,\\"sold_product_566079_22969, sold_product_566079_775\\",\\"sold_product_566079_22969, sold_product_566079_775\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Angeldale\\",\\"Spherecords, Angeldale\\",\\"12.992, 30.594\\",\\"24.984, 60\\",\\"22,969, 775\\",\\"Pyjamas - blue, Boots - black\\",\\"Pyjamas - blue, Boots - black\\",\\"1, 1\\",\\"ZO0663306633, ZO0687306873\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0663306633, ZO0687306873\\",85,85,2,2,order,phil +IgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Gilbert\\",\\"Betty Gilbert\\",FEMALE,44,Gilbert,Gilbert,\\"(empty)\\",Monday,0,\\"betty@gilbert-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566622,\\"sold_product_566622_13554, sold_product_566622_11691\\",\\"sold_product_566622_13554, sold_product_566622_11691\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"12.25, 13.492\\",\\"24.984, 24.984\\",\\"13,554, 11,691\\",\\"Jersey dress - black, Cape - grey multicolor\\",\\"Jersey dress - black, Cape - grey multicolor\\",\\"1, 1\\",\\"ZO0228402284, ZO0082300823\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0228402284, ZO0082300823\\",\\"49.969\\",\\"49.969\\",2,2,order,betty +IwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Long\\",\\"Elyssa Long\\",FEMALE,27,Long,Long,\\"(empty)\\",Monday,0,\\"elyssa@long-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566650,\\"sold_product_566650_20286, sold_product_566650_16948\\",\\"sold_product_566650_20286, sold_product_566650_16948\\",\\"65, 14.992\\",\\"65, 14.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"34.438, 7.941\\",\\"65, 14.992\\",\\"20,286, 16,948\\",\\"Long-sleeved Maxi Dress, Scarf - black\\",\\"Long-sleeved Maxi Dress, Scarf - black\\",\\"1, 1\\",\\"ZO0049100491, ZO0194801948\\",\\"0, 0\\",\\"65, 14.992\\",\\"65, 14.992\\",\\"0, 0\\",\\"ZO0049100491, ZO0194801948\\",80,80,2,2,order,elyssa +JAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Strickland\\",\\"Abigail Strickland\\",FEMALE,46,Strickland,Strickland,\\"(empty)\\",Monday,0,\\"abigail@strickland-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566295,\\"sold_product_566295_17554, sold_product_566295_22815\\",\\"sold_product_566295_17554, sold_product_566295_22815\\",\\"18.984, 24.984\\",\\"18.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"9.313, 13.242\\",\\"18.984, 24.984\\",\\"17,554, 22,815\\",\\"Maxi dress - black, Jersey dress - black\\",\\"Maxi dress - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0635606356, ZO0043100431\\",\\"0, 0\\",\\"18.984, 24.984\\",\\"18.984, 24.984\\",\\"0, 0\\",\\"ZO0635606356, ZO0043100431\\",\\"43.969\\",\\"43.969\\",2,2,order,abigail +JQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Kim\\",\\"Clarice Kim\\",FEMALE,18,Kim,Kim,\\"(empty)\\",Monday,0,\\"clarice@kim-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566538,\\"sold_product_566538_9847, sold_product_566538_16537\\",\\"sold_product_566538_9847, sold_product_566538_16537\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"13.492, 25.984\\",\\"24.984, 50\\",\\"9,847, 16,537\\",\\"Tights - black, Cocktail dress / Party dress - rose cloud\\",\\"Tights - black, Cocktail dress / Party dress - rose cloud\\",\\"1, 1\\",\\"ZO0224402244, ZO0342403424\\",\\"0, 0\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"0, 0\\",\\"ZO0224402244, ZO0342403424\\",75,75,2,2,order,clarice +JgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Allison\\",\\"Clarice Allison\\",FEMALE,18,Allison,Allison,\\"(empty)\\",Monday,0,\\"clarice@allison-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565918,\\"sold_product_565918_14195, sold_product_565918_7629\\",\\"sold_product_565918_14195, sold_product_565918_7629\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"7.648, 14.492\\",\\"16.984, 28.984\\",\\"14,195, 7,629\\",\\"Jersey dress - black, Jumper - peacoat/winter white\\",\\"Jersey dress - black, Jumper - peacoat/winter white\\",\\"1, 1\\",\\"ZO0155001550, ZO0072100721\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0155001550, ZO0072100721\\",\\"45.969\\",\\"45.969\\",2,2,order,clarice +UAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Morrison\\",\\"Gwen Morrison\\",FEMALE,26,Morrison,Morrison,\\"(empty)\\",Monday,0,\\"gwen@morrison-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises, Crystal Lighting\\",\\"Tigress Enterprises, Crystal Lighting\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565678,\\"sold_product_565678_13792, sold_product_565678_22639\\",\\"sold_product_565678_13792, sold_product_565678_22639\\",\\"12.992, 24.984\\",\\"12.992, 24.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Crystal Lighting\\",\\"Tigress Enterprises, Crystal Lighting\\",\\"6.109, 11.25\\",\\"12.992, 24.984\\",\\"13,792, 22,639\\",\\"Scarf - white/grey, Wool jumper - white\\",\\"Scarf - white/grey, Wool jumper - white\\",\\"1, 1\\",\\"ZO0081800818, ZO0485604856\\",\\"0, 0\\",\\"12.992, 24.984\\",\\"12.992, 24.984\\",\\"0, 0\\",\\"ZO0081800818, ZO0485604856\\",\\"37.969\\",\\"37.969\\",2,2,order,gwen +UQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jason,Jason,\\"Jason Graves\\",\\"Jason Graves\\",MALE,16,Graves,Graves,\\"(empty)\\",Monday,0,\\"jason@graves-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566564,\\"sold_product_566564_11560, sold_product_566564_17533\\",\\"sold_product_566564_11560, sold_product_566564_17533\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"29.406, 5.641\\",\\"60, 11.992\\",\\"11,560, 17,533\\",\\"Trainers - white, Print T-shirt - dark grey\\",\\"Trainers - white, Print T-shirt - dark grey\\",\\"1, 1\\",\\"ZO0107301073, ZO0293002930\\",\\"0, 0\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"0, 0\\",\\"ZO0107301073, ZO0293002930\\",72,72,2,2,order,jason +ZgMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Dixon\\",\\"rania Dixon\\",FEMALE,24,Dixon,Dixon,\\"(empty)\\",Monday,0,\\"rania@dixon-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565498,\\"sold_product_565498_15436, sold_product_565498_16548\\",\\"sold_product_565498_15436, sold_product_565498_16548\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"14.781, 9\\",\\"28.984, 16.984\\",\\"15,436, 16,548\\",\\"Jersey dress - anthra/black, Sweatshirt - black\\",\\"Jersey dress - anthra/black, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0046600466, ZO0503305033\\",\\"0, 0\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"0, 0\\",\\"ZO0046600466, ZO0503305033\\",\\"45.969\\",\\"45.969\\",2,2,order,rani +gAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Sutton\\",\\"Yasmine Sutton\\",FEMALE,43,Sutton,Sutton,\\"(empty)\\",Monday,0,\\"yasmine@sutton-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565793,\\"sold_product_565793_14151, sold_product_565793_22488\\",\\"sold_product_565793_14151, sold_product_565793_22488\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"11.75, 15.07\\",\\"24.984, 28.984\\",\\"14,151, 22,488\\",\\"Slim fit jeans - mid blue denim, Lace-ups - black glitter\\",\\"Slim fit jeans - mid blue denim, Lace-ups - black glitter\\",\\"1, 1\\",\\"ZO0712807128, ZO0007500075\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0712807128, ZO0007500075\\",\\"53.969\\",\\"53.969\\",2,2,order,yasmine +gQMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Fletcher\\",\\"Jason Fletcher\\",MALE,16,Fletcher,Fletcher,\\"(empty)\\",Monday,0,\\"jason@fletcher-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566232,\\"sold_product_566232_21255, sold_product_566232_12532\\",\\"sold_product_566232_21255, sold_product_566232_12532\\",\\"7.988, 11.992\\",\\"7.988, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.76, 6.352\\",\\"7.988, 11.992\\",\\"21,255, 12,532\\",\\"Basic T-shirt - black, Print T-shirt - navy ecru\\",\\"Basic T-shirt - black, Print T-shirt - navy ecru\\",\\"1, 1\\",\\"ZO0545205452, ZO0437304373\\",\\"0, 0\\",\\"7.988, 11.992\\",\\"7.988, 11.992\\",\\"0, 0\\",\\"ZO0545205452, ZO0437304373\\",\\"19.984\\",\\"19.984\\",2,2,order,jason +ggMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Larson\\",\\"Tariq Larson\\",MALE,25,Larson,Larson,\\"(empty)\\",Monday,0,\\"tariq@larson-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566259,\\"sold_product_566259_22713, sold_product_566259_21314\\",\\"sold_product_566259_22713, sold_product_566259_21314\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"32.375, 6.039\\",\\"60, 10.992\\",\\"22,713, 21,314\\",\\"Boots - black, Print T-shirt - white\\",\\"Boots - black, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0694206942, ZO0553805538\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0694206942, ZO0553805538\\",71,71,2,2,order,tariq +pwMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Walters\\",\\"Gwen Walters\\",FEMALE,26,Walters,Walters,\\"(empty)\\",Monday,0,\\"gwen@walters-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Champion Arts, Low Tide Media\\",\\"Champion Arts, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566591,\\"sold_product_566591_19909, sold_product_566591_12575\\",\\"sold_product_566591_19909, sold_product_566591_12575\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Low Tide Media\\",\\"Champion Arts, Low Tide Media\\",\\"13.047, 19.313\\",\\"28.984, 42\\",\\"19,909, 12,575\\",\\"Hoodie - black/white, Classic heels - nude\\",\\"Hoodie - black/white, Classic heels - nude\\",\\"1, 1\\",\\"ZO0502405024, ZO0366003660\\",\\"0, 0\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"0, 0\\",\\"ZO0502405024, ZO0366003660\\",71,71,2,2,order,gwen +WQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Yahya,Yahya,\\"Yahya Foster\\",\\"Yahya Foster\\",MALE,23,Foster,Foster,\\"(empty)\\",Sunday,6,\\"yahya@foster-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564670,\\"sold_product_564670_11411, sold_product_564670_23904\\",\\"sold_product_564670_11411, sold_product_564670_23904\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"8.094, 38.25\\",\\"14.992, 85\\",\\"11,411, 23,904\\",\\"Shorts - bordeaux mel, High-top trainers - black\\",\\"Shorts - bordeaux mel, High-top trainers - black\\",\\"1, 1\\",\\"ZO0531205312, ZO0684706847\\",\\"0, 0\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"0, 0\\",\\"ZO0531205312, ZO0684706847\\",100,100,2,2,order,yahya +WgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Jimenez\\",\\"Betty Jimenez\\",FEMALE,44,Jimenez,Jimenez,\\"(empty)\\",Sunday,6,\\"betty@jimenez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564710,\\"sold_product_564710_21089, sold_product_564710_10916\\",\\"sold_product_564710_21089, sold_product_564710_10916\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"17.156, 10.906\\",\\"33, 20.984\\",\\"21,089, 10,916\\",\\"Jersey dress - black, Sweatshirt - black\\",\\"Jersey dress - black, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0263402634, ZO0499404994\\",\\"0, 0\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"0, 0\\",\\"ZO0263402634, ZO0499404994\\",\\"53.969\\",\\"53.969\\",2,2,order,betty +YAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Daniels\\",\\"Clarice Daniels\\",FEMALE,18,Daniels,Daniels,\\"(empty)\\",Sunday,6,\\"clarice@daniels-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564429,\\"sold_product_564429_19198, sold_product_564429_20939\\",\\"sold_product_564429_19198, sold_product_564429_20939\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"24, 11.75\\",\\"50, 24.984\\",\\"19,198, 20,939\\",\\"Summer dress - grey, Shirt - black/white\\",\\"Summer dress - grey, Shirt - black/white\\",\\"1, 1\\",\\"ZO0260702607, ZO0495804958\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0260702607, ZO0495804958\\",75,75,2,2,order,clarice +YQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Clayton\\",\\"Jackson Clayton\\",MALE,13,Clayton,Clayton,\\"(empty)\\",Sunday,6,\\"jackson@clayton-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564479,\\"sold_product_564479_6603, sold_product_564479_21164\\",\\"sold_product_564479_6603, sold_product_564479_21164\\",\\"75, 10.992\\",\\"75, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"39, 5.93\\",\\"75, 10.992\\",\\"6,603, 21,164\\",\\"Suit jacket - navy, Long sleeved top - dark blue\\",\\"Suit jacket - navy, Long sleeved top - dark blue\\",\\"1, 1\\",\\"ZO0409304093, ZO0436904369\\",\\"0, 0\\",\\"75, 10.992\\",\\"75, 10.992\\",\\"0, 0\\",\\"ZO0409304093, ZO0436904369\\",86,86,2,2,order,jackson +YgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Davidson\\",\\"Abd Davidson\\",MALE,52,Davidson,Davidson,\\"(empty)\\",Sunday,6,\\"abd@davidson-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564513,\\"sold_product_564513_1824, sold_product_564513_19618\\",\\"sold_product_564513_1824, sold_product_564513_19618\\",\\"42, 42\\",\\"42, 42\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"20.156, 21\\",\\"42, 42\\",\\"1,824, 19,618\\",\\"Casual lace-ups - Violet, Waistcoat - petrol\\",\\"Casual lace-ups - Violet, Waistcoat - petrol\\",\\"1, 1\\",\\"ZO0390003900, ZO0287902879\\",\\"0, 0\\",\\"42, 42\\",\\"42, 42\\",\\"0, 0\\",\\"ZO0390003900, ZO0287902879\\",84,84,2,2,order,abd +xAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Stephanie,Stephanie,\\"Stephanie Rowe\\",\\"Stephanie Rowe\\",FEMALE,6,Rowe,Rowe,\\"(empty)\\",Sunday,6,\\"stephanie@rowe-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564885,\\"sold_product_564885_16366, sold_product_564885_11518\\",\\"sold_product_564885_16366, sold_product_564885_11518\\",\\"21.984, 10.992\\",\\"21.984, 10.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"10.344, 5.281\\",\\"21.984, 10.992\\",\\"16,366, 11,518\\",\\"Wallet - red, Scarf - white/navy/red\\",\\"Wallet - red, Scarf - white/navy/red\\",\\"1, 1\\",\\"ZO0303803038, ZO0192501925\\",\\"0, 0\\",\\"21.984, 10.992\\",\\"21.984, 10.992\\",\\"0, 0\\",\\"ZO0303803038, ZO0192501925\\",\\"32.969\\",\\"32.969\\",2,2,order,stephanie +UwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Bryant\\",\\"Mostafa Bryant\\",MALE,9,Bryant,Bryant,\\"(empty)\\",Sunday,6,\\"mostafa@bryant-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565150,\\"sold_product_565150_14275, sold_product_565150_22504\\",\\"sold_product_565150_14275, sold_product_565150_22504\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"25, 13.492\\",\\"50, 24.984\\",\\"14,275, 22,504\\",\\"Winter jacket - black, Shirt - red-blue\\",\\"Winter jacket - black, Shirt - red-blue\\",\\"1, 1\\",\\"ZO0624906249, ZO0411604116\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0624906249, ZO0411604116\\",75,75,2,2,order,mostafa +VAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Wood\\",\\"Jackson Wood\\",MALE,13,Wood,Wood,\\"(empty)\\",Sunday,6,\\"jackson@wood-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565206,\\"sold_product_565206_18416, sold_product_565206_16131\\",\\"sold_product_565206_18416, sold_product_565206_16131\\",\\"85, 60\\",\\"85, 60\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"45.031, 27\\",\\"85, 60\\",\\"18,416, 16,131\\",\\"Briefcase - dark brown, Lace-up boots - black\\",\\"Briefcase - dark brown, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0316303163, ZO0401004010\\",\\"0, 0\\",\\"85, 60\\",\\"85, 60\\",\\"0, 0\\",\\"ZO0316303163, ZO0401004010\\",145,145,2,2,order,jackson +9QMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Baker\\",\\"rania Baker\\",FEMALE,24,Baker,Baker,\\"(empty)\\",Sunday,6,\\"rania@baker-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Pyramidustries active, Champion Arts\\",\\"Pyramidustries active, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564759,\\"sold_product_564759_10104, sold_product_564759_20756\\",\\"sold_product_564759_10104, sold_product_564759_20756\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Champion Arts\\",\\"Pyramidustries active, Champion Arts\\",\\"8.828, 5.059\\",\\"16.984, 10.992\\",\\"10,104, 20,756\\",\\"Print T-shirt - black, Print T-shirt - red\\",\\"Print T-shirt - black, Print T-shirt - red\\",\\"1, 1\\",\\"ZO0218802188, ZO0492604926\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0218802188, ZO0492604926\\",\\"27.984\\",\\"27.984\\",2,2,order,rani +BAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Massey\\",\\"Wilhemina St. Massey\\",FEMALE,17,Massey,Massey,\\"(empty)\\",Sunday,6,\\"wilhemina st.@massey-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries active, Champion Arts\\",\\"Pyramidustries active, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564144,\\"sold_product_564144_20744, sold_product_564144_13946\\",\\"sold_product_564144_20744, sold_product_564144_13946\\",\\"16.984, 20.984\\",\\"16.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Champion Arts\\",\\"Pyramidustries active, Champion Arts\\",\\"8.328, 9.656\\",\\"16.984, 20.984\\",\\"20,744, 13,946\\",\\"Long sleeved top - black, Hoodie - dark grey multicolor\\",\\"Long sleeved top - black, Hoodie - dark grey multicolor\\",\\"1, 1\\",\\"ZO0218602186, ZO0501005010\\",\\"0, 0\\",\\"16.984, 20.984\\",\\"16.984, 20.984\\",\\"0, 0\\",\\"ZO0218602186, ZO0501005010\\",\\"37.969\\",\\"37.969\\",2,2,order,wilhemina +BgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Smith\\",\\"Abd Smith\\",MALE,52,Smith,Smith,\\"(empty)\\",Sunday,6,\\"abd@smith-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563909,\\"sold_product_563909_15619, sold_product_563909_17976\\",\\"sold_product_563909_15619, sold_product_563909_17976\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"13.633, 12.25\\",\\"28.984, 24.984\\",\\"15,619, 17,976\\",\\"Jumper - dark blue, Jumper - blue\\",\\"Jumper - dark blue, Jumper - blue\\",\\"1, 1\\",\\"ZO0452804528, ZO0453604536\\",\\"0, 0\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"0, 0\\",\\"ZO0452804528, ZO0453604536\\",\\"53.969\\",\\"53.969\\",2,2,order,abd +QgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Thompson\\",\\"Sonya Thompson\\",FEMALE,28,Thompson,Thompson,\\"(empty)\\",Sunday,6,\\"sonya@thompson-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564869,\\"sold_product_564869_19715, sold_product_564869_7445\\",\\"sold_product_564869_19715, sold_product_564869_7445\\",\\"10.992, 42\\",\\"10.992, 42\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"5.93, 20.578\\",\\"10.992, 42\\",\\"19,715, 7,445\\",\\"Snood - nude/turquoise/pink, High heels - black\\",\\"Snood - nude/turquoise/pink, High heels - black\\",\\"1, 1\\",\\"ZO0192401924, ZO0366703667\\",\\"0, 0\\",\\"10.992, 42\\",\\"10.992, 42\\",\\"0, 0\\",\\"ZO0192401924, ZO0366703667\\",\\"52.969\\",\\"52.969\\",2,2,order,sonya +jQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Recip,Recip,\\"Recip Tran\\",\\"Recip Tran\\",MALE,10,Tran,Tran,\\"(empty)\\",Sunday,6,\\"recip@tran-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564619,\\"sold_product_564619_19268, sold_product_564619_20016\\",\\"sold_product_564619_19268, sold_product_564619_20016\\",\\"85, 60\\",\\"85, 60\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"42.5, 28.203\\",\\"85, 60\\",\\"19,268, 20,016\\",\\"Briefcase - antique cognac, Lace-up boots - khaki\\",\\"Briefcase - antique cognac, Lace-up boots - khaki\\",\\"1, 1\\",\\"ZO0470304703, ZO0406204062\\",\\"0, 0\\",\\"85, 60\\",\\"85, 60\\",\\"0, 0\\",\\"ZO0470304703, ZO0406204062\\",145,145,2,2,order,recip +mwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Samir,Samir,\\"Samir Moss\\",\\"Samir Moss\\",MALE,34,Moss,Moss,\\"(empty)\\",Sunday,6,\\"samir@moss-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564237,\\"sold_product_564237_19840, sold_product_564237_13857\\",\\"sold_product_564237_19840, sold_product_564237_13857\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"10.289, 17.156\\",\\"20.984, 33\\",\\"19,840, 13,857\\",\\"Watch - black, Trainers - beige\\",\\"Watch - black, Trainers - beige\\",\\"1, 1\\",\\"ZO0311203112, ZO0395703957\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0311203112, ZO0395703957\\",\\"53.969\\",\\"53.969\\",2,2,order,samir +\\"-QMtOW0BH63Xcmy44WNv\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Moss\\",\\"Fitzgerald Moss\\",MALE,11,Moss,Moss,\\"(empty)\\",Sunday,6,\\"fitzgerald@moss-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564269,\\"sold_product_564269_18446, sold_product_564269_19731\\",\\"sold_product_564269_18446, sold_product_564269_19731\\",\\"37, 10.992\\",\\"37, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"17.016, 5.059\\",\\"37, 10.992\\",\\"18,446, 19,731\\",\\"Shirt - dark grey multicolor, Print T-shirt - white/dark blue\\",\\"Shirt - dark grey multicolor, Print T-shirt - white/dark blue\\",\\"1, 1\\",\\"ZO0281102811, ZO0555705557\\",\\"0, 0\\",\\"37, 10.992\\",\\"37, 10.992\\",\\"0, 0\\",\\"ZO0281102811, ZO0555705557\\",\\"47.969\\",\\"47.969\\",2,2,order,fuzzy +NAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Schultz\\",\\"Kamal Schultz\\",MALE,39,Schultz,Schultz,\\"(empty)\\",Sunday,6,\\"kamal@schultz-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564842,\\"sold_product_564842_13508, sold_product_564842_24934\\",\\"sold_product_564842_13508, sold_product_564842_24934\\",\\"85, 50\\",\\"85, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"43.344, 22.5\\",\\"85, 50\\",\\"13,508, 24,934\\",\\"Light jacket - tan, Lace-up boots - resin coffee\\",\\"Light jacket - tan, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0432004320, ZO0403504035\\",\\"0, 0\\",\\"85, 50\\",\\"85, 50\\",\\"0, 0\\",\\"ZO0432004320, ZO0403504035\\",135,135,2,2,order,kamal +NQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Roberson\\",\\"Yasmine Roberson\\",FEMALE,43,Roberson,Roberson,\\"(empty)\\",Sunday,6,\\"yasmine@roberson-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse, Tigress Enterprises MAMA\\",\\"Gnomehouse, Tigress Enterprises MAMA\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564893,\\"sold_product_564893_24371, sold_product_564893_20755\\",\\"sold_product_564893_24371, sold_product_564893_20755\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises MAMA\\",\\"Gnomehouse, Tigress Enterprises MAMA\\",\\"25.984, 14.781\\",\\"50, 28.984\\",\\"24,371, 20,755\\",\\"Lace-ups - rose, Trousers - black denim\\",\\"Lace-ups - rose, Trousers - black denim\\",\\"1, 1\\",\\"ZO0322403224, ZO0227802278\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0322403224, ZO0227802278\\",79,79,2,2,order,yasmine +SQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Fletcher\\",\\"Betty Fletcher\\",FEMALE,44,Fletcher,Fletcher,\\"(empty)\\",Sunday,6,\\"betty@fletcher-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",564215,\\"sold_product_564215_17589, sold_product_564215_17920\\",\\"sold_product_564215_17589, sold_product_564215_17920\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"17.484, 12.492\\",\\"33, 24.984\\",\\"17,589, 17,920\\",\\"Jumpsuit - black, Maxi dress - black\\",\\"Jumpsuit - black, Maxi dress - black\\",\\"1, 1\\",\\"ZO0147201472, ZO0152201522\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0147201472, ZO0152201522\\",\\"57.969\\",\\"57.969\\",2,2,order,betty +TAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Marshall\\",\\"Yasmine Marshall\\",FEMALE,43,Marshall,Marshall,\\"(empty)\\",Sunday,6,\\"yasmine@marshall-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564725,\\"sold_product_564725_21497, sold_product_564725_14166\\",\\"sold_product_564725_21497, sold_product_564725_14166\\",\\"24.984, 125\\",\\"24.984, 125\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"13.492, 61.25\\",\\"24.984, 125\\",\\"21,497, 14,166\\",\\"Jumper - sand, Platform boots - golden\\",\\"Jumper - sand, Platform boots - golden\\",\\"1, 1\\",\\"ZO0071700717, ZO0364303643\\",\\"0, 0\\",\\"24.984, 125\\",\\"24.984, 125\\",\\"0, 0\\",\\"ZO0071700717, ZO0364303643\\",150,150,2,2,order,yasmine +TQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Allison\\",\\"Muniz Allison\\",MALE,37,Allison,Allison,\\"(empty)\\",Sunday,6,\\"muniz@allison-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564733,\\"sold_product_564733_1550, sold_product_564733_13038\\",\\"sold_product_564733_1550, sold_product_564733_13038\\",\\"33, 65\\",\\"33, 65\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"14.852, 31.203\\",\\"33, 65\\",\\"1,550, 13,038\\",\\"Casual lace-ups - dark brown, Suit jacket - grey\\",\\"Casual lace-ups - dark brown, Suit jacket - grey\\",\\"1, 1\\",\\"ZO0384303843, ZO0273702737\\",\\"0, 0\\",\\"33, 65\\",\\"33, 65\\",\\"0, 0\\",\\"ZO0384303843, ZO0273702737\\",98,98,2,2,order,muniz +mAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Mccarthy\\",\\"Rabbia Al Mccarthy\\",FEMALE,5,Mccarthy,Mccarthy,\\"(empty)\\",Sunday,6,\\"rabbia al@mccarthy-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises MAMA, Oceanavigations\\",\\"Tigress Enterprises MAMA, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564331,\\"sold_product_564331_24927, sold_product_564331_11378\\",\\"sold_product_564331_24927, sold_product_564331_11378\\",\\"37, 11.992\\",\\"37, 11.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Oceanavigations\\",\\"Tigress Enterprises MAMA, Oceanavigations\\",\\"18.859, 5.762\\",\\"37, 11.992\\",\\"24,927, 11,378\\",\\"Summer dress - black, Wallet - black\\",\\"Summer dress - black, Wallet - black\\",\\"1, 1\\",\\"ZO0229402294, ZO0303303033\\",\\"0, 0\\",\\"37, 11.992\\",\\"37, 11.992\\",\\"0, 0\\",\\"ZO0229402294, ZO0303303033\\",\\"48.969\\",\\"48.969\\",2,2,order,rabbia +mQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Gregory\\",\\"Jason Gregory\\",MALE,16,Gregory,Gregory,\\"(empty)\\",Sunday,6,\\"jason@gregory-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564350,\\"sold_product_564350_15296, sold_product_564350_19902\\",\\"sold_product_564350_15296, sold_product_564350_19902\\",\\"18.984, 13.992\\",\\"18.984, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"9.117, 7.41\\",\\"18.984, 13.992\\",\\"15,296, 19,902\\",\\"Polo shirt - red, TARTAN 3 PACK - Shorts - tartan/Blue Violety/dark grey\\",\\"Polo shirt - red, TARTAN 3 PACK - Shorts - tartan/Blue Violety/dark grey\\",\\"1, 1\\",\\"ZO0444104441, ZO0476804768\\",\\"0, 0\\",\\"18.984, 13.992\\",\\"18.984, 13.992\\",\\"0, 0\\",\\"ZO0444104441, ZO0476804768\\",\\"32.969\\",\\"32.969\\",2,2,order,jason +mgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Mccarthy\\",\\"Betty Mccarthy\\",FEMALE,44,Mccarthy,Mccarthy,\\"(empty)\\",Sunday,6,\\"betty@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Gnomehouse,Gnomehouse,\\"Jun 22, 2019 @ 00:00:00.000\\",564398,\\"sold_product_564398_15957, sold_product_564398_18712\\",\\"sold_product_564398_15957, sold_product_564398_18712\\",\\"37, 75\\",\\"37, 75\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"19.234, 39.75\\",\\"37, 75\\",\\"15,957, 18,712\\",\\"A-line skirt - Pale Violet Red, Classic coat - navy blazer\\",\\"A-line skirt - Pale Violet Red, Classic coat - navy blazer\\",\\"1, 1\\",\\"ZO0328703287, ZO0351003510\\",\\"0, 0\\",\\"37, 75\\",\\"37, 75\\",\\"0, 0\\",\\"ZO0328703287, ZO0351003510\\",112,112,2,2,order,betty +mwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Gibbs\\",\\"Diane Gibbs\\",FEMALE,22,Gibbs,Gibbs,\\"(empty)\\",Sunday,6,\\"diane@gibbs-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Champion Arts\\",\\"Pyramidustries, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564409,\\"sold_product_564409_23179, sold_product_564409_22261\\",\\"sold_product_564409_23179, sold_product_564409_22261\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Champion Arts\\",\\"Pyramidustries, Champion Arts\\",\\"9.656, 22.5\\",\\"20.984, 50\\",\\"23,179, 22,261\\",\\"Sweatshirt - berry, Winter jacket - bordeaux\\",\\"Sweatshirt - berry, Winter jacket - bordeaux\\",\\"1, 1\\",\\"ZO0178501785, ZO0503805038\\",\\"0, 0\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"0, 0\\",\\"ZO0178501785, ZO0503805038\\",71,71,2,2,order,diane +nAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Baker\\",\\"Hicham Baker\\",MALE,8,Baker,Baker,\\"(empty)\\",Sunday,6,\\"hicham@baker-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564024,\\"sold_product_564024_24786, sold_product_564024_19600\\",\\"sold_product_564024_24786, sold_product_564024_19600\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"11.25, 7.648\\",\\"24.984, 16.984\\",\\"24,786, 19,600\\",\\"Slim fit jeans - black, Sports shorts - mottled grey\\",\\"Slim fit jeans - black, Sports shorts - mottled grey\\",\\"1, 1\\",\\"ZO0534405344, ZO0619006190\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0534405344, ZO0619006190\\",\\"41.969\\",\\"41.969\\",2,2,order,hicham +sgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Perkins\\",\\"Robbie Perkins\\",MALE,48,Perkins,Perkins,\\"(empty)\\",Sunday,6,\\"robbie@perkins-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564271,\\"sold_product_564271_12818, sold_product_564271_18444\\",\\"sold_product_564271_12818, sold_product_564271_18444\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"8.328, 26.984\\",\\"16.984, 50\\",\\"12,818, 18,444\\",\\"Trainers - black, Summer jacket - dark blue\\",\\"Trainers - black, Summer jacket - dark blue\\",\\"1, 1\\",\\"ZO0507905079, ZO0430804308\\",\\"0, 0\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"0, 0\\",\\"ZO0507905079, ZO0430804308\\",67,67,2,2,order,robbie +DgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Rodriguez\\",\\"Sonya Rodriguez\\",FEMALE,28,Rodriguez,Rodriguez,\\"(empty)\\",Sunday,6,\\"sonya@rodriguez-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Microlutions, Pyramidustries\\",\\"Microlutions, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564676,\\"sold_product_564676_22697, sold_product_564676_12704\\",\\"sold_product_564676_22697, sold_product_564676_12704\\",\\"33, 33\\",\\"33, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Pyramidustries\\",\\"Microlutions, Pyramidustries\\",\\"14.852, 16.172\\",\\"33, 33\\",\\"22,697, 12,704\\",\\"Dress - red/black, Ankle boots - cognac\\",\\"Dress - red/black, Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0108401084, ZO0139301393\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0108401084, ZO0139301393\\",66,66,2,2,order,sonya +FAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Bryan\\",\\"Sultan Al Bryan\\",MALE,19,Bryan,Bryan,\\"(empty)\\",Sunday,6,\\"sultan al@bryan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564445,\\"sold_product_564445_14799, sold_product_564445_15411\\",\\"sold_product_564445_14799, sold_product_564445_15411\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"11.953, 7.82\\",\\"22.984, 16.984\\",\\"14,799, 15,411\\",\\"Sweatshirt - mottled grey, Belt - black\\",\\"Sweatshirt - mottled grey, Belt - black\\",\\"1, 1\\",\\"ZO0593805938, ZO0701407014\\",\\"0, 0\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"0, 0\\",\\"ZO0593805938, ZO0701407014\\",\\"39.969\\",\\"39.969\\",2,2,order,sultan +fgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Hodges\\",\\"Phil Hodges\\",MALE,50,Hodges,Hodges,\\"(empty)\\",Sunday,6,\\"phil@hodges-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564241,\\"sold_product_564241_11300, sold_product_564241_16698\\",\\"sold_product_564241_11300, sold_product_564241_16698\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9.867, 4.309\\",\\"20.984, 7.988\\",\\"11,300, 16,698\\",\\"Rucksack - black/grey multicolor , Basic T-shirt - light red\\",\\"Rucksack - black/grey multicolor , Basic T-shirt - light red\\",\\"1, 1\\",\\"ZO0605506055, ZO0547505475\\",\\"0, 0\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"0, 0\\",\\"ZO0605506055, ZO0547505475\\",\\"28.984\\",\\"28.984\\",2,2,order,phil +fwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Phil,Phil,\\"Phil Hernandez\\",\\"Phil Hernandez\\",MALE,50,Hernandez,Hernandez,\\"(empty)\\",Sunday,6,\\"phil@hernandez-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564272,\\"sold_product_564272_24786, sold_product_564272_19965\\",\\"sold_product_564272_24786, sold_product_564272_19965\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.25, 14.211\\",\\"24.984, 28.984\\",\\"24,786, 19,965\\",\\"Slim fit jeans - black, Casual lace-ups - dark grey\\",\\"Slim fit jeans - black, Casual lace-ups - dark grey\\",\\"1, 1\\",\\"ZO0534405344, ZO0512105121\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0534405344, ZO0512105121\\",\\"53.969\\",\\"53.969\\",2,2,order,phil +0AMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Jacobs\\",\\"Mostafa Jacobs\\",MALE,9,Jacobs,Jacobs,\\"(empty)\\",Sunday,6,\\"mostafa@jacobs-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564844,\\"sold_product_564844_24343, sold_product_564844_13084\\",\\"sold_product_564844_24343, sold_product_564844_13084\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.391, 12.742\\",\\"10.992, 24.984\\",\\"24,343, 13,084\\",\\"Print T-shirt - white, Chinos - Forest Green\\",\\"Print T-shirt - white, Chinos - Forest Green\\",\\"1, 1\\",\\"ZO0553205532, ZO0526205262\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0553205532, ZO0526205262\\",\\"35.969\\",\\"35.969\\",2,2,order,mostafa +0QMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Hansen\\",\\"Sonya Hansen\\",FEMALE,28,Hansen,Hansen,\\"(empty)\\",Sunday,6,\\"sonya@hansen-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Spherecords Maternity, Gnomehouse\\",\\"Spherecords Maternity, Gnomehouse\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564883,\\"sold_product_564883_16522, sold_product_564883_25026\\",\\"sold_product_564883_16522, sold_product_564883_25026\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Maternity, Gnomehouse\\",\\"Spherecords Maternity, Gnomehouse\\",\\"7.988, 22.5\\",\\"16.984, 50\\",\\"16,522, 25,026\\",\\"Jersey dress - black/white , Summer dress - multicolour\\",\\"Jersey dress - black/white , Summer dress - multicolour\\",\\"1, 1\\",\\"ZO0705607056, ZO0334703347\\",\\"0, 0\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"0, 0\\",\\"ZO0705607056, ZO0334703347\\",67,67,2,2,order,sonya +7wMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Ryan\\",\\"Rabbia Al Ryan\\",FEMALE,5,Ryan,Ryan,\\"(empty)\\",Sunday,6,\\"rabbia al@ryan-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564307,\\"sold_product_564307_18709, sold_product_564307_19883\\",\\"sold_product_564307_18709, sold_product_564307_19883\\",\\"75, 11.992\\",\\"75, 11.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"39.75, 5.52\\",\\"75, 11.992\\",\\"18,709, 19,883\\",\\"Boots - nude, Scarf - bordeaux/blue/rose\\",\\"Boots - nude, Scarf - bordeaux/blue/rose\\",\\"1, 1\\",\\"ZO0246602466, ZO0195201952\\",\\"0, 0\\",\\"75, 11.992\\",\\"75, 11.992\\",\\"0, 0\\",\\"ZO0246602466, ZO0195201952\\",87,87,2,2,order,rabbia +8AMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Ball\\",\\"Rabbia Al Ball\\",FEMALE,5,Ball,Ball,\\"(empty)\\",Sunday,6,\\"rabbia al@ball-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564148,\\"sold_product_564148_24106, sold_product_564148_16891\\",\\"sold_product_564148_24106, sold_product_564148_16891\\",\\"20.984, 21.984\\",\\"20.984, 21.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"9.867, 11.867\\",\\"20.984, 21.984\\",\\"24,106, 16,891\\",\\"Basic T-shirt - scarab, Rucksack - black \\",\\"Basic T-shirt - scarab, Rucksack - black \\",\\"1, 1\\",\\"ZO0057900579, ZO0211602116\\",\\"0, 0\\",\\"20.984, 21.984\\",\\"20.984, 21.984\\",\\"0, 0\\",\\"ZO0057900579, ZO0211602116\\",\\"42.969\\",\\"42.969\\",2,2,order,rabbia +\\"_wMtOW0BH63Xcmy44mWR\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Bryant\\",\\"Betty Bryant\\",FEMALE,44,Bryant,Bryant,\\"(empty)\\",Sunday,6,\\"betty@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564009,\\"sold_product_564009_13956, sold_product_564009_21367\\",\\"sold_product_564009_13956, sold_product_564009_21367\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"11.328, 14.781\\",\\"20.984, 28.984\\",\\"13,956, 21,367\\",\\"Tracksuit bottoms - black, Trainers - black/silver\\",\\"Tracksuit bottoms - black, Trainers - black/silver\\",\\"1, 1\\",\\"ZO0487904879, ZO0027100271\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0487904879, ZO0027100271\\",\\"49.969\\",\\"49.969\\",2,2,order,betty +AAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Harvey\\",\\"Abd Harvey\\",MALE,52,Harvey,Harvey,\\"(empty)\\",Sunday,6,\\"abd@harvey-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564532,\\"sold_product_564532_21335, sold_product_564532_20709\\",\\"sold_product_564532_21335, sold_product_564532_20709\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"6.352, 12\\",\\"11.992, 24.984\\",\\"21,335, 20,709\\",\\"2 PACK - Basic T-shirt - red multicolor, Tracksuit bottoms - black\\",\\"2 PACK - Basic T-shirt - red multicolor, Tracksuit bottoms - black\\",\\"1, 1\\",\\"ZO0474704747, ZO0622006220\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0474704747, ZO0622006220\\",\\"36.969\\",\\"36.969\\",2,2,order,abd +cwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Cummings\\",\\"Abigail Cummings\\",FEMALE,46,Cummings,Cummings,\\"(empty)\\",Sunday,6,\\"abigail@cummings-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",565308,\\"sold_product_565308_16405, sold_product_565308_8985\\",\\"sold_product_565308_16405, sold_product_565308_8985\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"11.5, 27.594\\",\\"24.984, 60\\",\\"16,405, 8,985\\",\\"Vest - black, Light jacket - cognac\\",\\"Vest - black, Light jacket - cognac\\",\\"1, 1\\",\\"ZO0172401724, ZO0184901849\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0172401724, ZO0184901849\\",85,85,2,2,order,abigail +lQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Moss\\",\\"Elyssa Moss\\",FEMALE,27,Moss,Moss,\\"(empty)\\",Sunday,6,\\"elyssa@moss-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564339,\\"sold_product_564339_24835, sold_product_564339_7932\\",\\"sold_product_564339_24835, sold_product_564339_7932\\",\\"13.992, 37\\",\\"13.992, 37\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"7.129, 19.594\\",\\"13.992, 37\\",\\"24,835, 7,932\\",\\"Scarf - red, Shirt - navy blazer\\",\\"Scarf - red, Shirt - navy blazer\\",\\"1, 1\\",\\"ZO0082900829, ZO0347903479\\",\\"0, 0\\",\\"13.992, 37\\",\\"13.992, 37\\",\\"0, 0\\",\\"ZO0082900829, ZO0347903479\\",\\"50.969\\",\\"50.969\\",2,2,order,elyssa +lgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Muniz,Muniz,\\"Muniz Parker\\",\\"Muniz Parker\\",MALE,37,Parker,Parker,\\"(empty)\\",Sunday,6,\\"muniz@parker-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564361,\\"sold_product_564361_12864, sold_product_564361_14121\\",\\"sold_product_564361_12864, sold_product_564361_14121\\",\\"22.984, 17.984\\",\\"22.984, 17.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"11.719, 9.172\\",\\"22.984, 17.984\\",\\"12,864, 14,121\\",\\"SLIM FIT - Formal shirt - black, Watch - grey\\",\\"SLIM FIT - Formal shirt - black, Watch - grey\\",\\"1, 1\\",\\"ZO0422304223, ZO0600506005\\",\\"0, 0\\",\\"22.984, 17.984\\",\\"22.984, 17.984\\",\\"0, 0\\",\\"ZO0422304223, ZO0600506005\\",\\"40.969\\",\\"40.969\\",2,2,order,muniz +lwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Boone\\",\\"Sonya Boone\\",FEMALE,28,Boone,Boone,\\"(empty)\\",Sunday,6,\\"sonya@boone-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564394,\\"sold_product_564394_18592, sold_product_564394_11914\\",\\"sold_product_564394_18592, sold_product_564394_11914\\",\\"25.984, 75\\",\\"25.984, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"14.031, 39\\",\\"25.984, 75\\",\\"18,592, 11,914\\",\\"Long sleeved top - grey, Wedge boots - white\\",\\"Long sleeved top - grey, Wedge boots - white\\",\\"1, 1\\",\\"ZO0269902699, ZO0667906679\\",\\"0, 0\\",\\"25.984, 75\\",\\"25.984, 75\\",\\"0, 0\\",\\"ZO0269902699, ZO0667906679\\",101,101,2,2,order,sonya +mAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Hopkins\\",\\"rania Hopkins\\",FEMALE,24,Hopkins,Hopkins,\\"(empty)\\",Sunday,6,\\"rania@hopkins-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564030,\\"sold_product_564030_24668, sold_product_564030_20234\\",\\"sold_product_564030_24668, sold_product_564030_20234\\",\\"16.984, 6.988\\",\\"16.984, 6.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"8.828, 3.221\\",\\"16.984, 6.988\\",\\"24,668, 20,234\\",\\"Sweatshirt - black, Vest - bordeaux\\",\\"Sweatshirt - black, Vest - bordeaux\\",\\"1, 1\\",\\"ZO0179901799, ZO0637606376\\",\\"0, 0\\",\\"16.984, 6.988\\",\\"16.984, 6.988\\",\\"0, 0\\",\\"ZO0179901799, ZO0637606376\\",\\"23.984\\",\\"23.984\\",2,2,order,rani +qwMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Salazar\\",\\"Mostafa Salazar\\",MALE,9,Salazar,Salazar,\\"(empty)\\",Sunday,6,\\"mostafa@salazar-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564661,\\"sold_product_564661_20323, sold_product_564661_20690\\",\\"sold_product_564661_20323, sold_product_564661_20690\\",\\"22.984, 33\\",\\"22.984, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"12.18, 18.141\\",\\"22.984, 33\\",\\"20,323, 20,690\\",\\"Formal shirt - light blue, Sweatshirt - black\\",\\"Formal shirt - light blue, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0415004150, ZO0125501255\\",\\"0, 0\\",\\"22.984, 33\\",\\"22.984, 33\\",\\"0, 0\\",\\"ZO0415004150, ZO0125501255\\",\\"55.969\\",\\"55.969\\",2,2,order,mostafa +rAMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Estrada\\",\\"Yasmine Estrada\\",FEMALE,43,Estrada,Estrada,\\"(empty)\\",Sunday,6,\\"yasmine@estrada-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords Curvy, Primemaster\\",\\"Spherecords Curvy, Primemaster\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564706,\\"sold_product_564706_13450, sold_product_564706_11576\\",\\"sold_product_564706_13450, sold_product_564706_11576\\",\\"11.992, 115\\",\\"11.992, 115\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Primemaster\\",\\"Spherecords Curvy, Primemaster\\",\\"5.879, 60.938\\",\\"11.992, 115\\",\\"13,450, 11,576\\",\\"Pencil skirt - black, High heeled boots - Midnight Blue\\",\\"Pencil skirt - black, High heeled boots - Midnight Blue\\",\\"1, 1\\",\\"ZO0709007090, ZO0362103621\\",\\"0, 0\\",\\"11.992, 115\\",\\"11.992, 115\\",\\"0, 0\\",\\"ZO0709007090, ZO0362103621\\",127,127,2,2,order,yasmine +sgMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Tran\\",\\"rania Tran\\",FEMALE,24,Tran,Tran,\\"(empty)\\",Sunday,6,\\"rania@tran-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564460,\\"sold_product_564460_24985, sold_product_564460_16158\\",\\"sold_product_564460_24985, sold_product_564460_16158\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"12, 15.508\\",\\"24.984, 33\\",\\"24,985, 16,158\\",\\"Cardigan - peacoat, Blouse - Dark Turquoise\\",\\"Cardigan - peacoat, Blouse - Dark Turquoise\\",\\"1, 1\\",\\"ZO0655106551, ZO0349403494\\",\\"0, 0\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"0, 0\\",\\"ZO0655106551, ZO0349403494\\",\\"57.969\\",\\"57.969\\",2,2,order,rani +FwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Palmer\\",\\"Diane Palmer\\",FEMALE,22,Palmer,Palmer,\\"(empty)\\",Sunday,6,\\"diane@palmer-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564536,\\"sold_product_564536_17282, sold_product_564536_12577\\",\\"sold_product_564536_17282, sold_product_564536_12577\\",\\"13.992, 50\\",\\"13.992, 50\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"6.719, 24.5\\",\\"13.992, 50\\",\\"17,282, 12,577\\",\\"Scarf - black, Sandals - beige\\",\\"Scarf - black, Sandals - beige\\",\\"1, 1\\",\\"ZO0304603046, ZO0370603706\\",\\"0, 0\\",\\"13.992, 50\\",\\"13.992, 50\\",\\"0, 0\\",\\"ZO0304603046, ZO0370603706\\",\\"63.969\\",\\"63.969\\",2,2,order,diane +GAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Bowers\\",\\"Abigail Bowers\\",FEMALE,46,Bowers,Bowers,\\"(empty)\\",Sunday,6,\\"abigail@bowers-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564559,\\"sold_product_564559_4882, sold_product_564559_16317\\",\\"sold_product_564559_4882, sold_product_564559_16317\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"26.484, 12.094\\",\\"50, 21.984\\",\\"4,882, 16,317\\",\\"Boots - brown, Shirt - light blue\\",\\"Boots - brown, Shirt - light blue\\",\\"1, 1\\",\\"ZO0015500155, ZO0650806508\\",\\"0, 0\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"0, 0\\",\\"ZO0015500155, ZO0650806508\\",72,72,2,2,order,abigail +GQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Wood\\",\\"Clarice Wood\\",FEMALE,18,Wood,Wood,\\"(empty)\\",Sunday,6,\\"clarice@wood-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",564609,\\"sold_product_564609_23139, sold_product_564609_23243\\",\\"sold_product_564609_23139, sold_product_564609_23243\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"6.23, 12.492\\",\\"11.992, 24.984\\",\\"23,139, 23,243\\",\\"Print T-shirt - black/berry, Summer dress - dark purple\\",\\"Print T-shirt - black/berry, Summer dress - dark purple\\",\\"1, 1\\",\\"ZO0162401624, ZO0156001560\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0162401624, ZO0156001560\\",\\"36.969\\",\\"36.969\\",2,2,order,clarice +awMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Caldwell\\",\\"Tariq Caldwell\\",MALE,25,Caldwell,Caldwell,\\"(empty)\\",Sunday,6,\\"tariq@caldwell-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565138,\\"sold_product_565138_18229, sold_product_565138_19505\\",\\"sold_product_565138_18229, sold_product_565138_19505\\",\\"8.992, 16.984\\",\\"8.992, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"4.578, 8.656\\",\\"8.992, 16.984\\",\\"18,229, 19,505\\",\\"Sports shirt - black, Polo shirt - dark blue\\",\\"Sports shirt - black, Polo shirt - dark blue\\",\\"1, 1\\",\\"ZO0615506155, ZO0445304453\\",\\"0, 0\\",\\"8.992, 16.984\\",\\"8.992, 16.984\\",\\"0, 0\\",\\"ZO0615506155, ZO0445304453\\",\\"25.984\\",\\"25.984\\",2,2,order,tariq +bAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Taylor\\",\\"Marwan Taylor\\",MALE,51,Taylor,Taylor,\\"(empty)\\",Sunday,6,\\"marwan@taylor-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565025,\\"sold_product_565025_10984, sold_product_565025_12566\\",\\"sold_product_565025_10984, sold_product_565025_12566\\",\\"24.984, 7.988\\",\\"24.984, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"11.5, 3.92\\",\\"24.984, 7.988\\",\\"10,984, 12,566\\",\\"Shirt - navy, Vest - dark blue\\",\\"Shirt - navy, Vest - dark blue\\",\\"1, 1\\",\\"ZO0280802808, ZO0549005490\\",\\"0, 0\\",\\"24.984, 7.988\\",\\"24.984, 7.988\\",\\"0, 0\\",\\"ZO0280802808, ZO0549005490\\",\\"32.969\\",\\"32.969\\",2,2,order,marwan +hgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Bowers\\",\\"Elyssa Bowers\\",FEMALE,27,Bowers,Bowers,\\"(empty)\\",Sunday,6,\\"elyssa@bowers-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564000,\\"sold_product_564000_21941, sold_product_564000_12880\\",\\"sold_product_564000_21941, sold_product_564000_12880\\",\\"110, 24.984\\",\\"110, 24.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"55, 13.492\\",\\"110, 24.984\\",\\"21,941, 12,880\\",\\"Boots - grey/silver, Ankle boots - blue\\",\\"Boots - grey/silver, Ankle boots - blue\\",\\"1, 1\\",\\"ZO0364603646, ZO0018200182\\",\\"0, 0\\",\\"110, 24.984\\",\\"110, 24.984\\",\\"0, 0\\",\\"ZO0364603646, ZO0018200182\\",135,135,2,2,order,elyssa +hwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Samir,Samir,\\"Samir Meyer\\",\\"Samir Meyer\\",MALE,34,Meyer,Meyer,\\"(empty)\\",Sunday,6,\\"samir@meyer-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564557,\\"sold_product_564557_24657, sold_product_564557_24558\\",\\"sold_product_564557_24657, sold_product_564557_24558\\",\\"10.992, 10.992\\",\\"10.992, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"5.93, 5.5\\",\\"10.992, 10.992\\",\\"24,657, 24,558\\",\\"7 PACK - Socks - black/grey/white/navy, Hat - dark grey multicolor\\",\\"7 PACK - Socks - black/grey/white/navy, Hat - dark grey multicolor\\",\\"1, 1\\",\\"ZO0664606646, ZO0460404604\\",\\"0, 0\\",\\"10.992, 10.992\\",\\"10.992, 10.992\\",\\"0, 0\\",\\"ZO0664606646, ZO0460404604\\",\\"21.984\\",\\"21.984\\",2,2,order,samir +iAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Cortez\\",\\"Elyssa Cortez\\",FEMALE,27,Cortez,Cortez,\\"(empty)\\",Sunday,6,\\"elyssa@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Oceanavigations,Oceanavigations,\\"Jun 22, 2019 @ 00:00:00.000\\",564604,\\"sold_product_564604_20084, sold_product_564604_22900\\",\\"sold_product_564604_20084, sold_product_564604_22900\\",\\"60, 13.992\\",\\"60, 13.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"28.797, 6.578\\",\\"60, 13.992\\",\\"20,084, 22,900\\",\\"High heels - black, Scarf - black/taupe\\",\\"High heels - black, Scarf - black/taupe\\",\\"1, 1\\",\\"ZO0237702377, ZO0304303043\\",\\"0, 0\\",\\"60, 13.992\\",\\"60, 13.992\\",\\"0, 0\\",\\"ZO0237702377, ZO0304303043\\",74,74,2,2,order,elyssa +mAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Graham\\",\\"Yahya Graham\\",MALE,23,Graham,Graham,\\"(empty)\\",Sunday,6,\\"yahya@graham-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564777,\\"sold_product_564777_15017, sold_product_564777_22683\\",\\"sold_product_564777_15017, sold_product_564777_22683\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"13.633, 15.18\\",\\"28.984, 33\\",\\"15,017, 22,683\\",\\"Jumper - off-white, Jumper - black\\",\\"Jumper - off-white, Jumper - black\\",\\"1, 1\\",\\"ZO0452704527, ZO0122201222\\",\\"0, 0\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"0, 0\\",\\"ZO0452704527, ZO0122201222\\",\\"61.969\\",\\"61.969\\",2,2,order,yahya +mQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Rodriguez\\",\\"Gwen Rodriguez\\",FEMALE,26,Rodriguez,Rodriguez,\\"(empty)\\",Sunday,6,\\"gwen@rodriguez-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564812,\\"sold_product_564812_24272, sold_product_564812_12257\\",\\"sold_product_564812_24272, sold_product_564812_12257\\",\\"37, 20.984\\",\\"37, 20.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"18.125, 10.703\\",\\"37, 20.984\\",\\"24,272, 12,257\\",\\"Shirt - white, T-bar sandals - black\\",\\"Shirt - white, T-bar sandals - black\\",\\"1, 1\\",\\"ZO0266002660, ZO0031900319\\",\\"0, 0\\",\\"37, 20.984\\",\\"37, 20.984\\",\\"0, 0\\",\\"ZO0266002660, ZO0031900319\\",\\"57.969\\",\\"57.969\\",2,2,order,gwen +owMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Mcdonald\\",\\"Jackson Mcdonald\\",MALE,13,Mcdonald,Mcdonald,\\"(empty)\\",Sunday,6,\\"jackson@mcdonald-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Microlutions, Low Tide Media, Spritechnologies, Oceanavigations\\",\\"Microlutions, Low Tide Media, Spritechnologies, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",715752,\\"sold_product_715752_18080, sold_product_715752_18512, sold_product_715752_3636, sold_product_715752_6169\\",\\"sold_product_715752_18080, sold_product_715752_18512, sold_product_715752_3636, sold_product_715752_6169\\",\\"6.988, 65, 14.992, 20.984\\",\\"6.988, 65, 14.992, 20.984\\",\\"Men's Clothing, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Microlutions, Low Tide Media, Spritechnologies, Oceanavigations\\",\\"Microlutions, Low Tide Media, Spritechnologies, Oceanavigations\\",\\"3.699, 34.438, 7.941, 11.539\\",\\"6.988, 65, 14.992, 20.984\\",\\"18,080, 18,512, 3,636, 6,169\\",\\"3 PACK - Socks - khaki/black, Lace-up boots - black/grey, Undershirt - black, Jumper - grey\\",\\"3 PACK - Socks - khaki/black, Lace-up boots - black/grey, Undershirt - black, Jumper - grey\\",\\"1, 1, 1, 1\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\",\\"0, 0, 0, 0\\",\\"6.988, 65, 14.992, 20.984\\",\\"6.988, 65, 14.992, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\",\\"107.938\\",\\"107.938\\",4,4,order,jackson +sQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Diane,Diane,\\"Diane Watkins\\",\\"Diane Watkins\\",FEMALE,22,Watkins,Watkins,\\"(empty)\\",Sunday,6,\\"diane@watkins-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563964,\\"sold_product_563964_12582, sold_product_563964_18661\\",\\"sold_product_563964_12582, sold_product_563964_18661\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"6.898, 38.25\\",\\"14.992, 85\\",\\"12,582, 18,661\\",\\"Ballet pumps - nude, Winter boots - black\\",\\"Ballet pumps - nude, Winter boots - black\\",\\"1, 1\\",\\"ZO0001200012, ZO0251902519\\",\\"0, 0\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"0, 0\\",\\"ZO0001200012, ZO0251902519\\",100,100,2,2,order,diane +2wMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Maldonado\\",\\"Betty Maldonado\\",FEMALE,44,Maldonado,Maldonado,\\"(empty)\\",Sunday,6,\\"betty@maldonado-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries active, Oceanavigations\\",\\"Pyramidustries active, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564315,\\"sold_product_564315_14794, sold_product_564315_25010\\",\\"sold_product_564315_14794, sold_product_564315_25010\\",\\"11.992, 17.984\\",\\"11.992, 17.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Oceanavigations\\",\\"Pyramidustries active, Oceanavigations\\",\\"5.762, 9.891\\",\\"11.992, 17.984\\",\\"14,794, 25,010\\",\\"Vest - sheer pink, Print T-shirt - white\\",\\"Vest - sheer pink, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0221002210, ZO0263702637\\",\\"0, 0\\",\\"11.992, 17.984\\",\\"11.992, 17.984\\",\\"0, 0\\",\\"ZO0221002210, ZO0263702637\\",\\"29.984\\",\\"29.984\\",2,2,order,betty +CwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Barber\\",\\"Elyssa Barber\\",FEMALE,27,Barber,Barber,\\"(empty)\\",Sunday,6,\\"elyssa@barber-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565237,\\"sold_product_565237_15847, sold_product_565237_9482\\",\\"sold_product_565237_15847, sold_product_565237_9482\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"23.5, 12.992\\",\\"50, 24.984\\",\\"15,847, 9,482\\",\\"Lace-ups - platino, Blouse - off white\\",\\"Lace-ups - platino, Blouse - off white\\",\\"1, 1\\",\\"ZO0323303233, ZO0172101721\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0323303233, ZO0172101721\\",75,75,2,2,order,elyssa +DgMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Samir,Samir,\\"Samir Tyler\\",\\"Samir Tyler\\",MALE,34,Tyler,Tyler,\\"(empty)\\",Sunday,6,\\"samir@tyler-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565090,\\"sold_product_565090_21928, sold_product_565090_1424\\",\\"sold_product_565090_21928, sold_product_565090_1424\\",\\"85, 42\\",\\"85, 42\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"46.75, 20.156\\",\\"85, 42\\",\\"21,928, 1,424\\",\\"Lace-up boots - black, Lace-up boots - black\\",\\"Lace-up boots - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0690306903, ZO0521005210\\",\\"0, 0\\",\\"85, 42\\",\\"85, 42\\",\\"0, 0\\",\\"ZO0690306903, ZO0521005210\\",127,127,2,2,order,samir +JAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Porter\\",\\"Yuri Porter\\",MALE,21,Porter,Porter,\\"(empty)\\",Sunday,6,\\"yuri@porter-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564649,\\"sold_product_564649_1961, sold_product_564649_6945\\",\\"sold_product_564649_1961, sold_product_564649_6945\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"30.547, 11.273\\",\\"65, 22.984\\",\\"1,961, 6,945\\",\\"Lace-up boots - dark blue, Shirt - navy\\",\\"Lace-up boots - dark blue, Shirt - navy\\",\\"1, 1\\",\\"ZO0405704057, ZO0411704117\\",\\"0, 0\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"0, 0\\",\\"ZO0405704057, ZO0411704117\\",88,88,2,2,order,yuri +KAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Cummings\\",\\"Gwen Cummings\\",FEMALE,26,Cummings,Cummings,\\"(empty)\\",Sunday,6,\\"gwen@cummings-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564510,\\"sold_product_564510_15201, sold_product_564510_10898\\",\\"sold_product_564510_15201, sold_product_564510_10898\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"11.75, 14.781\\",\\"24.984, 28.984\\",\\"15,201, 10,898\\",\\"Handbag - black, Jumpsuit - black\\",\\"Handbag - black, Jumpsuit - black\\",\\"1, 1\\",\\"ZO0093600936, ZO0145301453\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0093600936, ZO0145301453\\",\\"53.969\\",\\"53.969\\",2,2,order,gwen +YwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Cortez\\",\\"Brigitte Cortez\\",FEMALE,12,Cortez,Cortez,\\"(empty)\\",Sunday,6,\\"brigitte@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises Curvy, Oceanavigations\\",\\"Tigress Enterprises Curvy, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565222,\\"sold_product_565222_20561, sold_product_565222_22115\\",\\"sold_product_565222_20561, sold_product_565222_22115\\",\\"24.984, 75\\",\\"24.984, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Oceanavigations\\",\\"Tigress Enterprises Curvy, Oceanavigations\\",\\"12.992, 34.5\\",\\"24.984, 75\\",\\"20,561, 22,115\\",\\"Tracksuit bottoms - black, Winter boots - taupe\\",\\"Tracksuit bottoms - black, Winter boots - taupe\\",\\"1, 1\\",\\"ZO0102001020, ZO0252402524\\",\\"0, 0\\",\\"24.984, 75\\",\\"24.984, 75\\",\\"0, 0\\",\\"ZO0102001020, ZO0252402524\\",100,100,2,2,order,brigitte +kQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Lawrence\\",\\"Robert Lawrence\\",MALE,29,Lawrence,Lawrence,\\"(empty)\\",Sunday,6,\\"robert@lawrence-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565233,\\"sold_product_565233_24859, sold_product_565233_12805\\",\\"sold_product_565233_24859, sold_product_565233_12805\\",\\"11.992, 55\\",\\"11.992, 55\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"5.879, 29.141\\",\\"11.992, 55\\",\\"24,859, 12,805\\",\\"Sports shirt - black, Down jacket - dark beige\\",\\"Sports shirt - black, Down jacket - dark beige\\",\\"1, 1\\",\\"ZO0614906149, ZO0430404304\\",\\"0, 0\\",\\"11.992, 55\\",\\"11.992, 55\\",\\"0, 0\\",\\"ZO0614906149, ZO0430404304\\",67,67,2,2,order,robert +mgMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Brock\\",\\"Youssef Brock\\",MALE,31,Brock,Brock,\\"(empty)\\",Sunday,6,\\"youssef@brock-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",565084,\\"sold_product_565084_11612, sold_product_565084_6793\\",\\"sold_product_565084_11612, sold_product_565084_6793\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.82, 7.82\\",\\"10.992, 16.984\\",\\"11,612, 6,793\\",\\"Print T-shirt - grey, Jumper - grey multicolor\\",\\"Print T-shirt - grey, Jumper - grey multicolor\\",\\"1, 1\\",\\"ZO0549805498, ZO0541205412\\",\\"0, 0\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"0, 0\\",\\"ZO0549805498, ZO0541205412\\",\\"27.984\\",\\"27.984\\",2,2,order,youssef +sQMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Mckenzie\\",\\"Elyssa Mckenzie\\",FEMALE,27,Mckenzie,Mckenzie,\\"(empty)\\",Sunday,6,\\"elyssa@mckenzie-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564796,\\"sold_product_564796_13332, sold_product_564796_23987\\",\\"sold_product_564796_13332, sold_product_564796_23987\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"15.18, 13.492\\",\\"33, 24.984\\",\\"13,332, 23,987\\",\\"Cowboy/Biker boots - cognac, Shirt - red/black\\",\\"Cowboy/Biker boots - cognac, Shirt - red/black\\",\\"1, 1\\",\\"ZO0022100221, ZO0172301723\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0022100221, ZO0172301723\\",\\"57.969\\",\\"57.969\\",2,2,order,elyssa +sgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Burton\\",\\"Gwen Burton\\",FEMALE,26,Burton,Burton,\\"(empty)\\",Sunday,6,\\"gwen@burton-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Pyramidustries, Champion Arts\\",\\"Pyramidustries, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564627,\\"sold_product_564627_16073, sold_product_564627_15494\\",\\"sold_product_564627_16073, sold_product_564627_15494\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Champion Arts\\",\\"Pyramidustries, Champion Arts\\",\\"11.75, 8.328\\",\\"24.984, 16.984\\",\\"16,073, 15,494\\",\\"Rucksack - black , Sweatshirt - black\\",\\"Rucksack - black , Sweatshirt - black\\",\\"1, 1\\",\\"ZO0211702117, ZO0499004990\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0211702117, ZO0499004990\\",\\"41.969\\",\\"41.969\\",2,2,order,gwen +twMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert James\\",\\"Robert James\\",MALE,29,James,James,\\"(empty)\\",Sunday,6,\\"robert@james-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564257,\\"sold_product_564257_23012, sold_product_564257_14015\\",\\"sold_product_564257_23012, sold_product_564257_14015\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"17.813, 15.648\\",\\"33, 28.984\\",\\"23,012, 14,015\\",\\"Denim jacket - grey denim, Jumper - blue\\",\\"Denim jacket - grey denim, Jumper - blue\\",\\"1, 1\\",\\"ZO0539205392, ZO0577705777\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0539205392, ZO0577705777\\",\\"61.969\\",\\"61.969\\",2,2,order,robert +uwMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Boone\\",\\"Yuri Boone\\",MALE,21,Boone,Boone,\\"(empty)\\",Sunday,6,\\"yuri@boone-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564701,\\"sold_product_564701_18884, sold_product_564701_20066\\",\\"sold_product_564701_18884, sold_product_564701_20066\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"9.656, 13.242\\",\\"20.984, 24.984\\",\\"18,884, 20,066\\",\\"Sweatshirt - black /white, Shirt - oliv\\",\\"Sweatshirt - black /white, Shirt - oliv\\",\\"1, 1\\",\\"ZO0585205852, ZO0418104181\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0585205852, ZO0418104181\\",\\"45.969\\",\\"45.969\\",2,2,order,yuri +DwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Hicham,Hicham,\\"Hicham Bryant\\",\\"Hicham Bryant\\",MALE,8,Bryant,Bryant,\\"(empty)\\",Sunday,6,\\"hicham@bryant-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564915,\\"sold_product_564915_13194, sold_product_564915_13091\\",\\"sold_product_564915_13194, sold_product_564915_13091\\",\\"50, 29.984\\",\\"50, 29.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"24, 15.289\\",\\"50, 29.984\\",\\"13,194, 13,091\\",\\"Summer jacket - petrol, Trainers - navy\\",\\"Summer jacket - petrol, Trainers - navy\\",\\"1, 1\\",\\"ZO0286502865, ZO0394703947\\",\\"0, 0\\",\\"50, 29.984\\",\\"50, 29.984\\",\\"0, 0\\",\\"ZO0286502865, ZO0394703947\\",80,80,2,2,order,hicham +EAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Ball\\",\\"Diane Ball\\",FEMALE,22,Ball,Ball,\\"(empty)\\",Sunday,6,\\"diane@ball-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564954,\\"sold_product_564954_20928, sold_product_564954_13902\\",\\"sold_product_564954_20928, sold_product_564954_13902\\",\\"150, 42\\",\\"150, 42\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"70.5, 22.672\\",\\"150, 42\\",\\"20,928, 13,902\\",\\"Over-the-knee boots - passion, Lohan - Summer dress - black/black\\",\\"Over-the-knee boots - passion, Lohan - Summer dress - black/black\\",\\"1, 1\\",\\"ZO0362903629, ZO0048100481\\",\\"0, 0\\",\\"150, 42\\",\\"150, 42\\",\\"0, 0\\",\\"ZO0362903629, ZO0048100481\\",192,192,2,2,order,diane +EQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Gregory\\",\\"Gwen Gregory\\",FEMALE,26,Gregory,Gregory,\\"(empty)\\",Sunday,6,\\"gwen@gregory-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Pyramidustries active, Pyramidustries\\",\\"Pyramidustries active, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565009,\\"sold_product_565009_17113, sold_product_565009_24241\\",\\"sold_product_565009_17113, sold_product_565009_24241\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Pyramidustries\\",\\"Pyramidustries active, Pyramidustries\\",\\"8.328, 11.25\\",\\"16.984, 24.984\\",\\"17,113, 24,241\\",\\"Tights - duffle bag, Jeans Skinny Fit - black denim\\",\\"Tights - duffle bag, Jeans Skinny Fit - black denim\\",\\"1, 1\\",\\"ZO0225302253, ZO0183101831\\",\\"0, 0\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"0, 0\\",\\"ZO0225302253, ZO0183101831\\",\\"41.969\\",\\"41.969\\",2,2,order,gwen +EgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Sherman\\",\\"Mary Sherman\\",FEMALE,20,Sherman,Sherman,\\"(empty)\\",Sunday,6,\\"mary@sherman-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spherecords Curvy, Spherecords\\",\\"Spherecords Curvy, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564065,\\"sold_product_564065_16220, sold_product_564065_13835\\",\\"sold_product_564065_16220, sold_product_564065_13835\\",\\"14.992, 10.992\\",\\"14.992, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Spherecords\\",\\"Spherecords Curvy, Spherecords\\",\\"7.789, 5.82\\",\\"14.992, 10.992\\",\\"16,220, 13,835\\",\\"Vest - white, Print T-shirt - light grey multicolor/white\\",\\"Vest - white, Print T-shirt - light grey multicolor/white\\",\\"1, 1\\",\\"ZO0711207112, ZO0646106461\\",\\"0, 0\\",\\"14.992, 10.992\\",\\"14.992, 10.992\\",\\"0, 0\\",\\"ZO0711207112, ZO0646106461\\",\\"25.984\\",\\"25.984\\",2,2,order,mary +EwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Stewart\\",\\"Abigail Stewart\\",FEMALE,46,Stewart,Stewart,\\"(empty)\\",Sunday,6,\\"abigail@stewart-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563927,\\"sold_product_563927_11755, sold_product_563927_17765\\",\\"sold_product_563927_11755, sold_product_563927_17765\\",\\"24.984, 125\\",\\"24.984, 125\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"12.25, 57.5\\",\\"24.984, 125\\",\\"11,755, 17,765\\",\\"Sandals - cognac, High heeled boots - Midnight Blue\\",\\"Sandals - cognac, High heeled boots - Midnight Blue\\",\\"1, 1\\",\\"ZO0009800098, ZO0362803628\\",\\"0, 0\\",\\"24.984, 125\\",\\"24.984, 125\\",\\"0, 0\\",\\"ZO0009800098, ZO0362803628\\",150,150,2,2,order,abigail +XQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Mckinney\\",\\"Marwan Mckinney\\",MALE,51,Mckinney,Mckinney,\\"(empty)\\",Sunday,6,\\"marwan@mckinney-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564937,\\"sold_product_564937_1994, sold_product_564937_6646\\",\\"sold_product_564937_1994, sold_product_564937_6646\\",\\"33, 75\\",\\"33, 75\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"17.484, 35.25\\",\\"33, 75\\",\\"1,994, 6,646\\",\\"Lace-up boots - dark grey, Winter jacket - dark camel\\",\\"Lace-up boots - dark grey, Winter jacket - dark camel\\",\\"1, 1\\",\\"ZO0520605206, ZO0432204322\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0520605206, ZO0432204322\\",108,108,2,2,order,marwan +XgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Henderson\\",\\"Yasmine Henderson\\",FEMALE,43,Henderson,Henderson,\\"(empty)\\",Sunday,6,\\"yasmine@henderson-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564994,\\"sold_product_564994_16814, sold_product_564994_17456\\",\\"sold_product_564994_16814, sold_product_564994_17456\\",\\"24.984, 11.992\\",\\"24.984, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Pyramidustries, Spherecords Curvy\\",\\"12.992, 6.109\\",\\"24.984, 11.992\\",\\"16,814, 17,456\\",\\"Sweatshirt - light grey multicolor, Long sleeved top - dark grey multicolor\\",\\"Sweatshirt - light grey multicolor, Long sleeved top - dark grey multicolor\\",\\"1, 1\\",\\"ZO0180601806, ZO0710007100\\",\\"0, 0\\",\\"24.984, 11.992\\",\\"24.984, 11.992\\",\\"0, 0\\",\\"ZO0180601806, ZO0710007100\\",\\"36.969\\",\\"36.969\\",2,2,order,yasmine +XwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,rania,rania,\\"rania Howell\\",\\"rania Howell\\",FEMALE,24,Howell,Howell,\\"(empty)\\",Sunday,6,\\"rania@howell-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Gnomehouse mom, Oceanavigations\\",\\"Gnomehouse mom, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564070,\\"sold_product_564070_23824, sold_product_564070_5275\\",\\"sold_product_564070_23824, sold_product_564070_5275\\",\\"55, 65\\",\\"55, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse mom, Oceanavigations\\",\\"Gnomehouse mom, Oceanavigations\\",\\"29.688, 35.094\\",\\"55, 65\\",\\"23,824, 5,275\\",\\"Summer dress - red ochre, Boots - dark brown\\",\\"Summer dress - red ochre, Boots - dark brown\\",\\"1, 1\\",\\"ZO0234202342, ZO0245102451\\",\\"0, 0\\",\\"55, 65\\",\\"55, 65\\",\\"0, 0\\",\\"ZO0234202342, ZO0245102451\\",120,120,2,2,order,rani +YAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Miller\\",\\"Jackson Miller\\",MALE,13,Miller,Miller,\\"(empty)\\",Sunday,6,\\"jackson@miller-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563928,\\"sold_product_563928_17644, sold_product_563928_11004\\",\\"sold_product_563928_17644, sold_product_563928_11004\\",\\"60, 50\\",\\"60, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"29.406, 26.484\\",\\"60, 50\\",\\"17,644, 11,004\\",\\"Suit jacket - dark blue, Casual lace-ups - Gold/cognac/lion\\",\\"Suit jacket - dark blue, Casual lace-ups - Gold/cognac/lion\\",\\"1, 1\\",\\"ZO0424104241, ZO0394103941\\",\\"0, 0\\",\\"60, 50\\",\\"60, 50\\",\\"0, 0\\",\\"ZO0424104241, ZO0394103941\\",110,110,2,2,order,jackson +xQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Morrison\\",\\"Rabbia Al Morrison\\",FEMALE,5,Morrison,Morrison,\\"(empty)\\",Sunday,6,\\"rabbia al@morrison-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Spherecords, Pyramidustries\\",\\"Tigress Enterprises, Spherecords, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",727071,\\"sold_product_727071_20781, sold_product_727071_23338, sold_product_727071_15267, sold_product_727071_12138\\",\\"sold_product_727071_20781, sold_product_727071_23338, sold_product_727071_15267, sold_product_727071_12138\\",\\"17.984, 16.984, 16.984, 32\\",\\"17.984, 16.984, 16.984, 32\\",\\"Women's Accessories, Women's Clothing, Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Clothing, Women's Accessories, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Spherecords, Pyramidustries, Tigress Enterprises\\",\\"Tigress Enterprises, Spherecords, Pyramidustries, Tigress Enterprises\\",\\"8.102, 9.172, 7.988, 16.953\\",\\"17.984, 16.984, 16.984, 32\\",\\"20,781, 23,338, 15,267, 12,138\\",\\"Across body bag - old rose , Pyjama set - grey/pink, Handbag - grey, Handbag - black\\",\\"Across body bag - old rose , Pyjama set - grey/pink, Handbag - grey, Handbag - black\\",\\"1, 1, 1, 1\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\",\\"0, 0, 0, 0\\",\\"17.984, 16.984, 16.984, 32\\",\\"17.984, 16.984, 16.984, 32\\",\\"0, 0, 0, 0\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\",84,84,4,4,order,rabbia +zAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Benson\\",\\"Phil Benson\\",MALE,50,Benson,Benson,\\"(empty)\\",Sunday,6,\\"phil@benson-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565284,\\"sold_product_565284_587, sold_product_565284_12864\\",\\"sold_product_565284_587, sold_product_565284_12864\\",\\"60, 22.984\\",\\"60, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"27.594, 11.719\\",\\"60, 22.984\\",\\"587, 12,864\\",\\"Boots - cognac, SLIM FIT - Formal shirt - black\\",\\"Boots - cognac, SLIM FIT - Formal shirt - black\\",\\"1, 1\\",\\"ZO0687206872, ZO0422304223\\",\\"0, 0\\",\\"60, 22.984\\",\\"60, 22.984\\",\\"0, 0\\",\\"ZO0687206872, ZO0422304223\\",83,83,2,2,order,phil +0AMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Cook\\",\\"Stephanie Cook\\",FEMALE,6,Cook,Cook,\\"(empty)\\",Sunday,6,\\"stephanie@cook-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564380,\\"sold_product_564380_13907, sold_product_564380_23338\\",\\"sold_product_564380_13907, sold_product_564380_23338\\",\\"37, 16.984\\",\\"37, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"16.656, 9.172\\",\\"37, 16.984\\",\\"13,907, 23,338\\",\\"Summer dress - black/Blue Violety, Pyjama set - grey/pink\\",\\"Summer dress - black/Blue Violety, Pyjama set - grey/pink\\",\\"1, 1\\",\\"ZO0050400504, ZO0660006600\\",\\"0, 0\\",\\"37, 16.984\\",\\"37, 16.984\\",\\"0, 0\\",\\"ZO0050400504, ZO0660006600\\",\\"53.969\\",\\"53.969\\",2,2,order,stephanie +JQMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Howell\\",\\"Clarice Howell\\",FEMALE,18,Howell,Howell,\\"(empty)\\",Sunday,6,\\"clarice@howell-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565276,\\"sold_product_565276_19432, sold_product_565276_23037\\",\\"sold_product_565276_19432, sold_product_565276_23037\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"10.906, 34.5\\",\\"20.984, 75\\",\\"19,432, 23,037\\",\\"Slip-ons - black, Lace-ups - black\\",\\"Slip-ons - black, Lace-ups - black\\",\\"1, 1\\",\\"ZO0131501315, ZO0668806688\\",\\"0, 0\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"0, 0\\",\\"ZO0131501315, ZO0668806688\\",96,96,2,2,order,clarice +JgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Stephanie,Stephanie,\\"Stephanie Marshall\\",\\"Stephanie Marshall\\",FEMALE,6,Marshall,Marshall,\\"(empty)\\",Sunday,6,\\"stephanie@marshall-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564819,\\"sold_product_564819_22794, sold_product_564819_20865\\",\\"sold_product_564819_22794, sold_product_564819_20865\\",\\"100, 65\\",\\"100, 65\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"46, 34.438\\",\\"100, 65\\",\\"22,794, 20,865\\",\\"Boots - Midnight Blue, Handbag - black\\",\\"Boots - Midnight Blue, Handbag - black\\",\\"1, 1\\",\\"ZO0374603746, ZO0697106971\\",\\"0, 0\\",\\"100, 65\\",\\"100, 65\\",\\"0, 0\\",\\"ZO0374603746, ZO0697106971\\",165,165,2,2,order,stephanie +yQMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Foster\\",\\"Eddie Foster\\",MALE,38,Foster,Foster,\\"(empty)\\",Sunday,6,\\"eddie@foster-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions, Elitelligence\\",\\"Low Tide Media, Microlutions, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",717243,\\"sold_product_717243_19724, sold_product_717243_20018, sold_product_717243_21122, sold_product_717243_13406\\",\\"sold_product_717243_19724, sold_product_717243_20018, sold_product_717243_21122, sold_product_717243_13406\\",\\"18.984, 33, 20.984, 11.992\\",\\"18.984, 33, 20.984, 11.992\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Microlutions, Low Tide Media, Elitelligence\\",\\"Low Tide Media, Microlutions, Low Tide Media, Elitelligence\\",\\"9.117, 16.172, 10.289, 6.59\\",\\"18.984, 33, 20.984, 11.992\\",\\"19,724, 20,018, 21,122, 13,406\\",\\"Swimming shorts - dark blue, Sweatshirt - Medium Spring Green, Sweatshirt - green , Basic T-shirt - blue\\",\\"Swimming shorts - dark blue, Sweatshirt - Medium Spring Green, Sweatshirt - green , Basic T-shirt - blue\\",\\"1, 1, 1, 1\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\",\\"0, 0, 0, 0\\",\\"18.984, 33, 20.984, 11.992\\",\\"18.984, 33, 20.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\",\\"84.938\\",\\"84.938\\",4,4,order,eddie +6QMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Phelps\\",\\"Pia Phelps\\",FEMALE,45,Phelps,Phelps,\\"(empty)\\",Sunday,6,\\"pia@phelps-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries active, Oceanavigations\\",\\"Pyramidustries active, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564140,\\"sold_product_564140_14794, sold_product_564140_18586\\",\\"sold_product_564140_14794, sold_product_564140_18586\\",\\"11.992, 42\\",\\"11.992, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Oceanavigations\\",\\"Pyramidustries active, Oceanavigations\\",\\"5.762, 21.828\\",\\"11.992, 42\\",\\"14,794, 18,586\\",\\"Vest - sheer pink, Cardigan - dark green\\",\\"Vest - sheer pink, Cardigan - dark green\\",\\"1, 1\\",\\"ZO0221002210, ZO0268502685\\",\\"0, 0\\",\\"11.992, 42\\",\\"11.992, 42\\",\\"0, 0\\",\\"ZO0221002210, ZO0268502685\\",\\"53.969\\",\\"53.969\\",2,2,order,pia +6gMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Jenkins\\",\\"Rabbia Al Jenkins\\",FEMALE,5,Jenkins,Jenkins,\\"(empty)\\",Sunday,6,\\"rabbia al@jenkins-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564164,\\"sold_product_564164_17391, sold_product_564164_11357\\",\\"sold_product_564164_17391, sold_product_564164_11357\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"46.75, 6.469\\",\\"85, 11.992\\",\\"17,391, 11,357\\",\\"Ankle boots - black, Pyjama bottoms - grey\\",\\"Ankle boots - black, Pyjama bottoms - grey\\",\\"1, 1\\",\\"ZO0673506735, ZO0213002130\\",\\"0, 0\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"0, 0\\",\\"ZO0673506735, ZO0213002130\\",97,97,2,2,order,rabbia +6wMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Ruiz\\",\\"Betty Ruiz\\",FEMALE,44,Ruiz,Ruiz,\\"(empty)\\",Sunday,6,\\"betty@ruiz-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564207,\\"sold_product_564207_11825, sold_product_564207_17988\\",\\"sold_product_564207_11825, sold_product_564207_17988\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"11.5, 18.125\\",\\"24.984, 37\\",\\"11,825, 17,988\\",\\"Cardigan - black, Cardigan - sand mel/black\\",\\"Cardigan - black, Cardigan - sand mel/black\\",\\"1, 1\\",\\"ZO0711807118, ZO0073100731\\",\\"0, 0\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"0, 0\\",\\"ZO0711807118, ZO0073100731\\",\\"61.969\\",\\"61.969\\",2,2,order,betty +7QMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Thad,Thad,\\"Thad Kim\\",\\"Thad Kim\\",MALE,30,Kim,Kim,\\"(empty)\\",Sunday,6,\\"thad@kim-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564735,\\"sold_product_564735_13418, sold_product_564735_14150\\",\\"sold_product_564735_13418, sold_product_564735_14150\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"9, 8.492\\",\\"16.984, 16.984\\",\\"13,418, 14,150\\",\\"High-top trainers - navy, Print T-shirt - black\\",\\"High-top trainers - navy, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0509705097, ZO0120501205\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0509705097, ZO0120501205\\",\\"33.969\\",\\"33.969\\",2,2,order,thad +8gMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Hudson\\",\\"Sultan Al Hudson\\",MALE,19,Hudson,Hudson,\\"(empty)\\",Sunday,6,\\"sultan al@hudson-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",Microlutions,Microlutions,\\"Jun 22, 2019 @ 00:00:00.000\\",565077,\\"sold_product_565077_21138, sold_product_565077_20998\\",\\"sold_product_565077_21138, sold_product_565077_20998\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Microlutions\\",\\"Microlutions, Microlutions\\",\\"9.172, 14.781\\",\\"16.984, 28.984\\",\\"21,138, 20,998\\",\\"Basic T-shirt - black, Sweatshirt - black\\",\\"Basic T-shirt - black, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0118701187, ZO0123901239\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0118701187, ZO0123901239\\",\\"45.969\\",\\"45.969\\",2,2,order,sultan +AAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Wood\\",\\"Jackson Wood\\",MALE,13,Wood,Wood,\\"(empty)\\",Sunday,6,\\"jackson@wood-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564274,\\"sold_product_564274_23599, sold_product_564274_23910\\",\\"sold_product_564274_23599, sold_product_564274_23910\\",\\"75, 26.984\\",\\"75, 26.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"34.5, 13.758\\",\\"75, 26.984\\",\\"23,599, 23,910\\",\\"Winter jacket - oliv, Shorts - dark blue\\",\\"Winter jacket - oliv, Shorts - dark blue\\",\\"1, 1\\",\\"ZO0542905429, ZO0423604236\\",\\"0, 0\\",\\"75, 26.984\\",\\"75, 26.984\\",\\"0, 0\\",\\"ZO0542905429, ZO0423604236\\",102,102,2,2,order,jackson +HgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Walters\\",\\"Thad Walters\\",MALE,30,Walters,Walters,\\"(empty)\\",Sunday,6,\\"thad@walters-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565161,\\"sold_product_565161_23831, sold_product_565161_13178\\",\\"sold_product_565161_23831, sold_product_565161_13178\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"5.5, 32.375\\",\\"10.992, 60\\",\\"23,831, 13,178\\",\\"Basic T-shirt - oliv , Light jacket - navy\\",\\"Basic T-shirt - oliv , Light jacket - navy\\",\\"1, 1\\",\\"ZO0441404414, ZO0430504305\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0441404414, ZO0430504305\\",71,71,2,2,order,thad +HwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Taylor\\",\\"Selena Taylor\\",FEMALE,42,Taylor,Taylor,\\"(empty)\\",Sunday,6,\\"selena@taylor-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Champion Arts, Angeldale\\",\\"Champion Arts, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565039,\\"sold_product_565039_17587, sold_product_565039_19471\\",\\"sold_product_565039_17587, sold_product_565039_19471\\",\\"16.984, 13.992\\",\\"16.984, 13.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Angeldale\\",\\"Champion Arts, Angeldale\\",\\"8.328, 6.859\\",\\"16.984, 13.992\\",\\"17,587, 19,471\\",\\"Jersey dress - khaki, Belt - dark brown\\",\\"Jersey dress - khaki, Belt - dark brown\\",\\"1, 1\\",\\"ZO0489804898, ZO0695006950\\",\\"0, 0\\",\\"16.984, 13.992\\",\\"16.984, 13.992\\",\\"0, 0\\",\\"ZO0489804898, ZO0695006950\\",\\"30.984\\",\\"30.984\\",2,2,order,selena +PwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Stokes\\",\\"Elyssa Stokes\\",FEMALE,27,Stokes,Stokes,\\"(empty)\\",Sunday,6,\\"elyssa@stokes-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Champion Arts, Pyramidustries\\",\\"Spherecords, Champion Arts, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",723683,\\"sold_product_723683_19440, sold_product_723683_17349, sold_product_723683_14873, sold_product_723683_24863\\",\\"sold_product_723683_19440, sold_product_723683_17349, sold_product_723683_14873, sold_product_723683_24863\\",\\"10.992, 33, 42, 11.992\\",\\"10.992, 33, 42, 11.992\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Champion Arts, Pyramidustries, Champion Arts\\",\\"Spherecords, Champion Arts, Pyramidustries, Champion Arts\\",\\"5.93, 18.141, 21, 5.879\\",\\"10.992, 33, 42, 11.992\\",\\"19,440, 17,349, 14,873, 24,863\\",\\"Long sleeved top - dark green, Bomber Jacket - khaki/black, Platform boots - grey, Vest - black/white\\",\\"Long sleeved top - dark green, Bomber Jacket - khaki/black, Platform boots - grey, Vest - black/white\\",\\"1, 1, 1, 1\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\",\\"0, 0, 0, 0\\",\\"10.992, 33, 42, 11.992\\",\\"10.992, 33, 42, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\",\\"97.938\\",\\"97.938\\",4,4,order,elyssa +CAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Lloyd\\",\\"Stephanie Lloyd\\",FEMALE,6,Lloyd,Lloyd,\\"(empty)\\",Sunday,6,\\"stephanie@lloyd-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Champion Arts, Spherecords\\",\\"Champion Arts, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563967,\\"sold_product_563967_21565, sold_product_563967_8534\\",\\"sold_product_563967_21565, sold_product_563967_8534\\",\\"10.992, 10.992\\",\\"10.992, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Spherecords\\",\\"Champion Arts, Spherecords\\",\\"5.281, 5.82\\",\\"10.992, 10.992\\",\\"21,565, 8,534\\",\\"Print T-shirt - dark grey multicolor, Long sleeved top - black\\",\\"Print T-shirt - dark grey multicolor, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0493404934, ZO0640806408\\",\\"0, 0\\",\\"10.992, 10.992\\",\\"10.992, 10.992\\",\\"0, 0\\",\\"ZO0493404934, ZO0640806408\\",\\"21.984\\",\\"21.984\\",2,2,order,stephanie +LwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Rodriguez\\",\\"Abigail Rodriguez\\",FEMALE,46,Rodriguez,Rodriguez,\\"(empty)\\",Sunday,6,\\"abigail@rodriguez-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564533,\\"sold_product_564533_15845, sold_product_564533_17192\\",\\"sold_product_564533_15845, sold_product_564533_17192\\",\\"42, 33\\",\\"42, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"23.094, 16.5\\",\\"42, 33\\",\\"15,845, 17,192\\",\\"Summer jacket - black, Jersey dress - black\\",\\"Summer jacket - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0496704967, ZO0049700497\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0496704967, ZO0049700497\\",75,75,2,2,order,abigail +NwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Frances,Frances,\\"Frances Dennis\\",\\"Frances Dennis\\",FEMALE,49,Dennis,Dennis,\\"(empty)\\",Sunday,6,\\"frances@dennis-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565266,\\"sold_product_565266_18617, sold_product_565266_17793\\",\\"sold_product_565266_18617, sold_product_565266_17793\\",\\"60, 35\\",\\"60, 35\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"31.797, 16.453\\",\\"60, 35\\",\\"18,617, 17,793\\",\\"Slip-ons - black, Briefcase - black\\",\\"Slip-ons - black, Briefcase - black\\",\\"1, 1\\",\\"ZO0255602556, ZO0468304683\\",\\"0, 0\\",\\"60, 35\\",\\"60, 35\\",\\"0, 0\\",\\"ZO0255602556, ZO0468304683\\",95,95,2,2,order,frances +OAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al James\\",\\"Ahmed Al James\\",MALE,4,James,James,\\"(empty)\\",Sunday,6,\\"ahmed al@james-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564818,\\"sold_product_564818_12813, sold_product_564818_24108\\",\\"sold_product_564818_12813, sold_product_564818_24108\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"5.52, 11.25\\",\\"11.992, 24.984\\",\\"12,813, 24,108\\",\\"2 PACK - Basic T-shirt - black, SLIM FIT - Formal shirt - light blue\\",\\"2 PACK - Basic T-shirt - black, SLIM FIT - Formal shirt - light blue\\",\\"1, 1\\",\\"ZO0475004750, ZO0412304123\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0475004750, ZO0412304123\\",\\"36.969\\",\\"36.969\\",2,2,order,ahmed +XQMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Yahya,Yahya,\\"Yahya Turner\\",\\"Yahya Turner\\",MALE,23,Turner,Turner,\\"(empty)\\",Sunday,6,\\"yahya@turner-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564932,\\"sold_product_564932_23918, sold_product_564932_23529\\",\\"sold_product_564932_23918, sold_product_564932_23529\\",\\"7.988, 20.984\\",\\"7.988, 20.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"4.148, 10.906\\",\\"7.988, 20.984\\",\\"23,918, 23,529\\",\\"Print T-shirt - red, Across body bag - blue/cognac\\",\\"Print T-shirt - red, Across body bag - blue/cognac\\",\\"1, 1\\",\\"ZO0557305573, ZO0607806078\\",\\"0, 0\\",\\"7.988, 20.984\\",\\"7.988, 20.984\\",\\"0, 0\\",\\"ZO0557305573, ZO0607806078\\",\\"28.984\\",\\"28.984\\",2,2,order,yahya +XgMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Banks\\",\\"Clarice Banks\\",FEMALE,18,Banks,Banks,\\"(empty)\\",Sunday,6,\\"clarice@banks-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564968,\\"sold_product_564968_14312, sold_product_564968_22436\\",\\"sold_product_564968_14312, sold_product_564968_22436\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"15.844, 9.492\\",\\"33, 18.984\\",\\"14,312, 22,436\\",\\"High heels - yellow, Vest - gold metallic\\",\\"High heels - yellow, Vest - gold metallic\\",\\"1, 1\\",\\"ZO0134101341, ZO0062400624\\",\\"0, 0\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"0, 0\\",\\"ZO0134101341, ZO0062400624\\",\\"51.969\\",\\"51.969\\",2,2,order,clarice +XwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Morrison\\",\\"Betty Morrison\\",FEMALE,44,Morrison,Morrison,\\"(empty)\\",Sunday,6,\\"betty@morrison-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Gnomehouse,Gnomehouse,\\"Jun 22, 2019 @ 00:00:00.000\\",565002,\\"sold_product_565002_22932, sold_product_565002_21168\\",\\"sold_product_565002_22932, sold_product_565002_21168\\",\\"100, 75\\",\\"100, 75\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"54, 33.75\\",\\"100, 75\\",\\"22,932, 21,168\\",\\"Classic coat - grey, Cocktail dress / Party dress - eclipse\\",\\"Classic coat - grey, Cocktail dress / Party dress - eclipse\\",\\"1, 1\\",\\"ZO0354203542, ZO0338503385\\",\\"0, 0\\",\\"100, 75\\",\\"100, 75\\",\\"0, 0\\",\\"ZO0354203542, ZO0338503385\\",175,175,2,2,order,betty +YQMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Conner\\",\\"Robbie Conner\\",MALE,48,Conner,Conner,\\"(empty)\\",Sunday,6,\\"robbie@conner-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564095,\\"sold_product_564095_23104, sold_product_564095_24934\\",\\"sold_product_564095_23104, sold_product_564095_24934\\",\\"10.992, 50\\",\\"10.992, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.281, 22.5\\",\\"10.992, 50\\",\\"23,104, 24,934\\",\\"5 PACK - Socks - multicoloured, Lace-up boots - resin coffee\\",\\"5 PACK - Socks - multicoloured, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0613806138, ZO0403504035\\",\\"0, 0\\",\\"10.992, 50\\",\\"10.992, 50\\",\\"0, 0\\",\\"ZO0613806138, ZO0403504035\\",\\"60.969\\",\\"60.969\\",2,2,order,robbie +YgMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Clayton\\",\\"Yuri Clayton\\",MALE,21,Clayton,Clayton,\\"(empty)\\",Sunday,6,\\"yuri@clayton-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",563924,\\"sold_product_563924_14271, sold_product_563924_15400\\",\\"sold_product_563924_14271, sold_product_563924_15400\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"23, 7.051\\",\\"50, 14.992\\",\\"14,271, 15,400\\",\\"Bomber Jacket - blue mix, Long sleeved top - khaki\\",\\"Bomber Jacket - blue mix, Long sleeved top - khaki\\",\\"1, 1\\",\\"ZO0539805398, ZO0554205542\\",\\"0, 0\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"0, 0\\",\\"ZO0539805398, ZO0554205542\\",65,65,2,2,order,yuri +7AMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Mccarthy\\",\\"Elyssa Mccarthy\\",FEMALE,27,Mccarthy,Mccarthy,\\"(empty)\\",Sunday,6,\\"elyssa@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564770,\\"sold_product_564770_15776, sold_product_564770_17904\\",\\"sold_product_564770_15776, sold_product_564770_17904\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"10.078, 17.156\\",\\"20.984, 33\\",\\"15,776, 17,904\\",\\"2 PACK - Leggings - black, Ankle boots - black\\",\\"2 PACK - Leggings - black, Ankle boots - black\\",\\"1, 1\\",\\"ZO0704907049, ZO0024700247\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0704907049, ZO0024700247\\",\\"53.969\\",\\"53.969\\",2,2,order,elyssa +SQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Adams\\",\\"Elyssa Adams\\",FEMALE,27,Adams,Adams,\\"(empty)\\",Sunday,6,\\"elyssa@adams-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563965,\\"sold_product_563965_18560, sold_product_563965_14856\\",\\"sold_product_563965_18560, sold_product_563965_14856\\",\\"34, 18.984\\",\\"34, 18.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"18.016, 9.313\\",\\"34, 18.984\\",\\"18,560, 14,856\\",\\"Summer dress - peacoat/pomegranade, Sweatshirt - grey\\",\\"Summer dress - peacoat/pomegranade, Sweatshirt - grey\\",\\"1, 1\\",\\"ZO0045800458, ZO0503405034\\",\\"0, 0\\",\\"34, 18.984\\",\\"34, 18.984\\",\\"0, 0\\",\\"ZO0045800458, ZO0503405034\\",\\"52.969\\",\\"52.969\\",2,2,order,elyssa +ZAMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Powell\\",\\"rania Powell\\",FEMALE,24,Powell,Powell,\\"(empty)\\",Sunday,6,\\"rania@powell-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",564957,\\"sold_product_564957_22053, sold_product_564957_17382\\",\\"sold_product_564957_22053, sold_product_564957_17382\\",\\"28.984, 6.988\\",\\"28.984, 6.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"15.648, 3.359\\",\\"28.984, 6.988\\",\\"22,053, 17,382\\",\\"Shirt - light blue, Tights - black\\",\\"Shirt - light blue, Tights - black\\",\\"1, 1\\",\\"ZO0171601716, ZO0214602146\\",\\"0, 0\\",\\"28.984, 6.988\\",\\"28.984, 6.988\\",\\"0, 0\\",\\"ZO0171601716, ZO0214602146\\",\\"35.969\\",\\"35.969\\",2,2,order,rani +ZQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jim,Jim,\\"Jim Brewer\\",\\"Jim Brewer\\",MALE,41,Brewer,Brewer,\\"(empty)\\",Sunday,6,\\"jim@brewer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564032,\\"sold_product_564032_20226, sold_product_564032_16558\\",\\"sold_product_564032_20226, sold_product_564032_16558\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"15.648, 15.508\\",\\"28.984, 33\\",\\"20,226, 16,558\\",\\"Pyjamas - grey/blue, Boots - dark brown\\",\\"Pyjamas - grey/blue, Boots - dark brown\\",\\"1, 1\\",\\"ZO0478404784, ZO0521905219\\",\\"0, 0\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"0, 0\\",\\"ZO0478404784, ZO0521905219\\",\\"61.969\\",\\"61.969\\",2,2,order,jim +ZgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Estrada\\",\\"Muniz Estrada\\",MALE,37,Estrada,Estrada,\\"(empty)\\",Sunday,6,\\"muniz@estrada-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564075,\\"sold_product_564075_21248, sold_product_564075_12047\\",\\"sold_product_564075_21248, sold_product_564075_12047\\",\\"27.984, 20.984\\",\\"27.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"13.992, 10.289\\",\\"27.984, 20.984\\",\\"21,248, 12,047\\",\\"Windbreaker - navy blazer, Tracksuit bottoms - dark red\\",\\"Windbreaker - navy blazer, Tracksuit bottoms - dark red\\",\\"1, 1\\",\\"ZO0622706227, ZO0525405254\\",\\"0, 0\\",\\"27.984, 20.984\\",\\"27.984, 20.984\\",\\"0, 0\\",\\"ZO0622706227, ZO0525405254\\",\\"48.969\\",\\"48.969\\",2,2,order,muniz +ZwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Samir,Samir,\\"Samir Mckinney\\",\\"Samir Mckinney\\",MALE,34,Mckinney,Mckinney,\\"(empty)\\",Sunday,6,\\"samir@mckinney-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563931,\\"sold_product_563931_3103, sold_product_563931_11153\\",\\"sold_product_563931_3103, sold_product_563931_11153\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"10.703, 5.172\\",\\"20.984, 10.992\\",\\"3,103, 11,153\\",\\"Polo shirt - light grey multicolor, Cap - black/black\\",\\"Polo shirt - light grey multicolor, Cap - black/black\\",\\"1, 1\\",\\"ZO0444304443, ZO0596505965\\",\\"0, 0\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"0, 0\\",\\"ZO0444304443, ZO0596505965\\",\\"31.984\\",\\"31.984\\",2,2,order,samir +lgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Palmer\\",\\"Clarice Palmer\\",FEMALE,18,Palmer,Palmer,\\"(empty)\\",Sunday,6,\\"clarice@palmer-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564940,\\"sold_product_564940_13407, sold_product_564940_15116\\",\\"sold_product_564940_13407, sold_product_564940_15116\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"13.922, 11.328\\",\\"28.984, 20.984\\",\\"13,407, 15,116\\",\\"Trainers - offwhite, Wedges - Blue Violety\\",\\"Trainers - offwhite, Wedges - Blue Violety\\",\\"1, 1\\",\\"ZO0026800268, ZO0003600036\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0026800268, ZO0003600036\\",\\"49.969\\",\\"49.969\\",2,2,order,clarice +lwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Hampton\\",\\"Jason Hampton\\",MALE,16,Hampton,Hampton,\\"(empty)\\",Sunday,6,\\"jason@hampton-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564987,\\"sold_product_564987_24440, sold_product_564987_12655\\",\\"sold_product_564987_24440, sold_product_564987_12655\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.703, 13.242\\",\\"20.984, 24.984\\",\\"24,440, 12,655\\",\\"Chinos - dark blue, SET - Pyjamas - grey/blue\\",\\"Chinos - dark blue, SET - Pyjamas - grey/blue\\",\\"1, 1\\",\\"ZO0526805268, ZO0478104781\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0526805268, ZO0478104781\\",\\"45.969\\",\\"45.969\\",2,2,order,jason +mQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Lewis\\",\\"Tariq Lewis\\",MALE,25,Lewis,Lewis,\\"(empty)\\",Sunday,6,\\"tariq@lewis-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564080,\\"sold_product_564080_13013, sold_product_564080_16957\\",\\"sold_product_564080_13013, sold_product_564080_16957\\",\\"28.984, 10.992\\",\\"28.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"14.211, 5.711\\",\\"28.984, 10.992\\",\\"13,013, 16,957\\",\\"Shirt - light blue, Cap - navy\\",\\"Shirt - light blue, Cap - navy\\",\\"1, 1\\",\\"ZO0415804158, ZO0460804608\\",\\"0, 0\\",\\"28.984, 10.992\\",\\"28.984, 10.992\\",\\"0, 0\\",\\"ZO0415804158, ZO0460804608\\",\\"39.969\\",\\"39.969\\",2,2,order,tariq +mgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Hicham,Hicham,\\"Hicham Love\\",\\"Hicham Love\\",MALE,8,Love,Love,\\"(empty)\\",Sunday,6,\\"hicham@love-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Oceanavigations,Oceanavigations,\\"Jun 22, 2019 @ 00:00:00.000\\",564106,\\"sold_product_564106_14672, sold_product_564106_15019\\",\\"sold_product_564106_14672, sold_product_564106_15019\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"13.922, 8.547\\",\\"28.984, 18.984\\",\\"14,672, 15,019\\",\\"Jumper - dark blue, Wallet - black\\",\\"Jumper - dark blue, Wallet - black\\",\\"1, 1\\",\\"ZO0298002980, ZO0313103131\\",\\"0, 0\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"0, 0\\",\\"ZO0298002980, ZO0313103131\\",\\"47.969\\",\\"47.969\\",2,2,order,hicham +mwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Foster\\",\\"Gwen Foster\\",FEMALE,26,Foster,Foster,\\"(empty)\\",Sunday,6,\\"gwen@foster-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563947,\\"sold_product_563947_8960, sold_product_563947_19261\\",\\"sold_product_563947_8960, sold_product_563947_19261\\",\\"37, 13.992\\",\\"37, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"18.5, 7\\",\\"37, 13.992\\",\\"8,960, 19,261\\",\\"Shirt - soft pink nude, Vest - black\\",\\"Shirt - soft pink nude, Vest - black\\",\\"1, 1\\",\\"ZO0348103481, ZO0164501645\\",\\"0, 0\\",\\"37, 13.992\\",\\"37, 13.992\\",\\"0, 0\\",\\"ZO0348103481, ZO0164501645\\",\\"50.969\\",\\"50.969\\",2,2,order,gwen +FAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Lewis\\",\\"Elyssa Lewis\\",FEMALE,27,Lewis,Lewis,\\"(empty)\\",Sunday,6,\\"elyssa@lewis-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries active, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Pyramidustries active, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Jun 22, 2019 @ 00:00:00.000\\",725995,\\"sold_product_725995_10498, sold_product_725995_15404, sold_product_725995_16378, sold_product_725995_12398\\",\\"sold_product_725995_10498, sold_product_725995_15404, sold_product_725995_16378, sold_product_725995_12398\\",\\"20.984, 42, 34, 18.984\\",\\"20.984, 42, 34, 18.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries active, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Pyramidustries active, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"11.328, 21.406, 15.641, 9.68\\",\\"20.984, 42, 34, 18.984\\",\\"10,498, 15,404, 16,378, 12,398\\",\\"Tracksuit bottoms - grey multicolor, Shift dress - Lemon Chiffon, Blazer - black/grey, Vest - navy\\",\\"Tracksuit bottoms - grey multicolor, Shift dress - Lemon Chiffon, Blazer - black/grey, Vest - navy\\",\\"1, 1, 1, 1\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\",\\"0, 0, 0, 0\\",\\"20.984, 42, 34, 18.984\\",\\"20.984, 42, 34, 18.984\\",\\"0, 0, 0, 0\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\",\\"115.938\\",\\"115.938\\",4,4,order,elyssa +JwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,George,George,\\"George Butler\\",\\"George Butler\\",MALE,32,Butler,Butler,\\"(empty)\\",Sunday,6,\\"george@butler-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564756,\\"sold_product_564756_16646, sold_product_564756_21840\\",\\"sold_product_564756_16646, sold_product_564756_21840\\",\\"9.992, 155\\",\\"9.992, 155\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"5.191, 83.688\\",\\"9.992, 155\\",\\"16,646, 21,840\\",\\"Long sleeved top - Medium Slate Blue, Lace-ups - brown\\",\\"Long sleeved top - Medium Slate Blue, Lace-ups - brown\\",\\"1, 1\\",\\"ZO0556805568, ZO0481504815\\",\\"0, 0\\",\\"9.992, 155\\",\\"9.992, 155\\",\\"0, 0\\",\\"ZO0556805568, ZO0481504815\\",165,165,2,2,order,george +ZwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Austin\\",\\"Yuri Austin\\",MALE,21,Austin,Austin,\\"(empty)\\",Sunday,6,\\"yuri@austin-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565137,\\"sold_product_565137_18257, sold_product_565137_24282\\",\\"sold_product_565137_18257, sold_product_565137_24282\\",\\"14.992, 7.988\\",\\"14.992, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"7.051, 4.148\\",\\"14.992, 7.988\\",\\"18,257, 24,282\\",\\"Print T-shirt - black, Print T-shirt - bordeaux\\",\\"Print T-shirt - black, Print T-shirt - bordeaux\\",\\"1, 1\\",\\"ZO0118501185, ZO0561905619\\",\\"0, 0\\",\\"14.992, 7.988\\",\\"14.992, 7.988\\",\\"0, 0\\",\\"ZO0118501185, ZO0561905619\\",\\"22.984\\",\\"22.984\\",2,2,order,yuri +aAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Evans\\",\\"Elyssa Evans\\",FEMALE,27,Evans,Evans,\\"(empty)\\",Sunday,6,\\"elyssa@evans-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565173,\\"sold_product_565173_20610, sold_product_565173_23026\\",\\"sold_product_565173_20610, sold_product_565173_23026\\",\\"12.992, 42\\",\\"12.992, 42\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"6.879, 20.156\\",\\"12.992, 42\\",\\"20,610, 23,026\\",\\"Clutch - rose, Platform boots - cognac\\",\\"Clutch - rose, Platform boots - cognac\\",\\"1, 1\\",\\"ZO0203802038, ZO0014900149\\",\\"0, 0\\",\\"12.992, 42\\",\\"12.992, 42\\",\\"0, 0\\",\\"ZO0203802038, ZO0014900149\\",\\"54.969\\",\\"54.969\\",2,2,order,elyssa +aQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Valdez\\",\\"Abdulraheem Al Valdez\\",MALE,33,Valdez,Valdez,\\"(empty)\\",Sunday,6,\\"abdulraheem al@valdez-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565214,\\"sold_product_565214_24934, sold_product_565214_11845\\",\\"sold_product_565214_24934, sold_product_565214_11845\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"22.5, 9.492\\",\\"50, 18.984\\",\\"24,934, 11,845\\",\\"Lace-up boots - resin coffee, Hoodie - light red\\",\\"Lace-up boots - resin coffee, Hoodie - light red\\",\\"1, 1\\",\\"ZO0403504035, ZO0588705887\\",\\"0, 0\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"0, 0\\",\\"ZO0403504035, ZO0588705887\\",69,69,2,2,order,abdulraheem +mQMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Frank\\",\\"Mary Frank\\",FEMALE,20,Frank,Frank,\\"(empty)\\",Sunday,6,\\"mary@frank-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564804,\\"sold_product_564804_16840, sold_product_564804_21361\\",\\"sold_product_564804_16840, sold_product_564804_21361\\",\\"37, 10.992\\",\\"37, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"17.766, 5.172\\",\\"37, 10.992\\",\\"16,840, 21,361\\",\\"Pencil skirt - black, Long sleeved top - dark brown\\",\\"Pencil skirt - black, Long sleeved top - dark brown\\",\\"1, 1\\",\\"ZO0259702597, ZO0640606406\\",\\"0, 0\\",\\"37, 10.992\\",\\"37, 10.992\\",\\"0, 0\\",\\"ZO0259702597, ZO0640606406\\",\\"47.969\\",\\"47.969\\",2,2,order,mary +pAMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Hubbard\\",\\"Yasmine Hubbard\\",FEMALE,43,Hubbard,Hubbard,\\"(empty)\\",Sunday,6,\\"yasmine@hubbard-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Angeldale, Spherecords Curvy\\",\\"Angeldale, Spherecords Curvy\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565052,\\"sold_product_565052_20949, sold_product_565052_16543\\",\\"sold_product_565052_20949, sold_product_565052_16543\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spherecords Curvy\\",\\"Angeldale, Spherecords Curvy\\",\\"30.594, 9.453\\",\\"60, 20.984\\",\\"20,949, 16,543\\",\\"Tote bag - cognac, Blouse - black\\",\\"Tote bag - cognac, Blouse - black\\",\\"1, 1\\",\\"ZO0697006970, ZO0711407114\\",\\"0, 0\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"0, 0\\",\\"ZO0697006970, ZO0711407114\\",81,81,2,2,order,yasmine +pQMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Pia,Pia,\\"Pia Reyes\\",\\"Pia Reyes\\",FEMALE,45,Reyes,Reyes,\\"(empty)\\",Sunday,6,\\"pia@reyes-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565091,\\"sold_product_565091_5862, sold_product_565091_12548\\",\\"sold_product_565091_5862, sold_product_565091_12548\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"31.203, 11.5\\",\\"65, 24.984\\",\\"5,862, 12,548\\",\\"Boots - taupe, Handbag - creme/grey\\",\\"Boots - taupe, Handbag - creme/grey\\",\\"1, 1\\",\\"ZO0324703247, ZO0088600886\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0324703247, ZO0088600886\\",90,90,2,2,order,pia +rgMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Stokes\\",\\"Wilhemina St. Stokes\\",FEMALE,17,Stokes,Stokes,\\"(empty)\\",Sunday,6,\\"wilhemina st.@stokes-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565231,\\"sold_product_565231_17601, sold_product_565231_11904\\",\\"sold_product_565231_17601, sold_product_565231_11904\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Gnomehouse mom, Pyramidustries\\",\\"20.156, 15.07\\",\\"42, 28.984\\",\\"17,601, 11,904\\",\\"Cape - Pale Violet Red, Trainers - rose\\",\\"Cape - Pale Violet Red, Trainers - rose\\",\\"1, 1\\",\\"ZO0235202352, ZO0135001350\\",\\"0, 0\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"0, 0\\",\\"ZO0235202352, ZO0135001350\\",71,71,2,2,order,wilhemina +9wMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Stephanie,Stephanie,\\"Stephanie Hodges\\",\\"Stephanie Hodges\\",FEMALE,6,Hodges,Hodges,\\"(empty)\\",Sunday,6,\\"stephanie@hodges-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564190,\\"sold_product_564190_5329, sold_product_564190_16930\\",\\"sold_product_564190_5329, sold_product_564190_16930\\",\\"115, 24.984\\",\\"115, 24.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"62.094, 13.242\\",\\"115, 24.984\\",\\"5,329, 16,930\\",\\"Over-the-knee boots - Midnight Blue, Across body bag - Blue Violety \\",\\"Over-the-knee boots - Midnight Blue, Across body bag - Blue Violety \\",\\"1, 1\\",\\"ZO0243902439, ZO0208702087\\",\\"0, 0\\",\\"115, 24.984\\",\\"115, 24.984\\",\\"0, 0\\",\\"ZO0243902439, ZO0208702087\\",140,140,2,2,order,stephanie +EgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Kim\\",\\"Selena Kim\\",FEMALE,42,Kim,Kim,\\"(empty)\\",Sunday,6,\\"selena@kim-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",564876,\\"sold_product_564876_12273, sold_product_564876_21758\\",\\"sold_product_564876_12273, sold_product_564876_21758\\",\\"12.992, 11.992\\",\\"12.992, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"6.371, 6.23\\",\\"12.992, 11.992\\",\\"12,273, 21,758\\",\\"2 PACK - Over-the-knee socks - black, Print T-shirt - black\\",\\"2 PACK - Over-the-knee socks - black, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0215502155, ZO0168101681\\",\\"0, 0\\",\\"12.992, 11.992\\",\\"12.992, 11.992\\",\\"0, 0\\",\\"ZO0215502155, ZO0168101681\\",\\"24.984\\",\\"24.984\\",2,2,order,selena +EwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Garza\\",\\"Elyssa Garza\\",FEMALE,27,Garza,Garza,\\"(empty)\\",Sunday,6,\\"elyssa@garza-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Angeldale, Karmanite\\",\\"Angeldale, Karmanite\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564902,\\"sold_product_564902_13639, sold_product_564902_22060\\",\\"sold_product_564902_13639, sold_product_564902_22060\\",\\"60, 100\\",\\"60, 100\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Karmanite\\",\\"Angeldale, Karmanite\\",\\"28.203, 51\\",\\"60, 100\\",\\"13,639, 22,060\\",\\"Handbag - taupe, Boots - grey\\",\\"Handbag - taupe, Boots - grey\\",\\"1, 1\\",\\"ZO0698406984, ZO0704207042\\",\\"0, 0\\",\\"60, 100\\",\\"60, 100\\",\\"0, 0\\",\\"ZO0698406984, ZO0704207042\\",160,160,2,2,order,elyssa +JwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Garza\\",\\"Elyssa Garza\\",FEMALE,27,Garza,Garza,\\"(empty)\\",Sunday,6,\\"elyssa@garza-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Angeldale, Spherecords Curvy\\",\\"Angeldale, Spherecords Curvy\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564761,\\"sold_product_564761_12146, sold_product_564761_24585\\",\\"sold_product_564761_12146, sold_product_564761_24585\\",\\"65, 16.984\\",\\"65, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spherecords Curvy\\",\\"Angeldale, Spherecords Curvy\\",\\"29.25, 9\\",\\"65, 16.984\\",\\"12,146, 24,585\\",\\"Slip-ons - red, Jersey dress - black\\",\\"Slip-ons - red, Jersey dress - black\\",\\"1, 1\\",\\"ZO0665006650, ZO0709407094\\",\\"0, 0\\",\\"65, 16.984\\",\\"65, 16.984\\",\\"0, 0\\",\\"ZO0665006650, ZO0709407094\\",82,82,2,2,order,elyssa +MQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Underwood\\",\\"Elyssa Underwood\\",FEMALE,27,Underwood,Underwood,\\"(empty)\\",Sunday,6,\\"elyssa@underwood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Champion Arts, Pyramidustries, Angeldale, Gnomehouse\\",\\"Champion Arts, Pyramidustries, Angeldale, Gnomehouse\\",\\"Jun 22, 2019 @ 00:00:00.000\\",731788,\\"sold_product_731788_22537, sold_product_731788_11189, sold_product_731788_14323, sold_product_731788_15479\\",\\"sold_product_731788_22537, sold_product_731788_11189, sold_product_731788_14323, sold_product_731788_15479\\",\\"20.984, 16.984, 85, 50\\",\\"20.984, 16.984, 85, 50\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Champion Arts, Pyramidustries, Angeldale, Gnomehouse\\",\\"Champion Arts, Pyramidustries, Angeldale, Gnomehouse\\",\\"10.289, 8.656, 39.938, 22.5\\",\\"20.984, 16.984, 85, 50\\",\\"22,537, 11,189, 14,323, 15,479\\",\\"Tracksuit bottoms - dark grey multicolor, Cardigan - black, Ankle boots - black, Summer dress - dusty rose\\",\\"Tracksuit bottoms - dark grey multicolor, Cardigan - black, Ankle boots - black, Summer dress - dusty rose\\",\\"1, 1, 1, 1\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\",\\"0, 0, 0, 0\\",\\"20.984, 16.984, 85, 50\\",\\"20.984, 16.984, 85, 50\\",\\"0, 0, 0, 0\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\",173,173,4,4,order,elyssa +TQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Recip,Recip,\\"Recip Morrison\\",\\"Recip Morrison\\",MALE,10,Morrison,Morrison,\\"(empty)\\",Sunday,6,\\"recip@morrison-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564340,\\"sold_product_564340_12840, sold_product_564340_24691\\",\\"sold_product_564340_12840, sold_product_564340_24691\\",\\"65, 16.984\\",\\"65, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"30.547, 8.156\\",\\"65, 16.984\\",\\"12,840, 24,691\\",\\"Lace-up boots - black, Long sleeved top - olive\\",\\"Lace-up boots - black, Long sleeved top - olive\\",\\"1, 1\\",\\"ZO0399703997, ZO0565805658\\",\\"0, 0\\",\\"65, 16.984\\",\\"65, 16.984\\",\\"0, 0\\",\\"ZO0399703997, ZO0565805658\\",82,82,2,2,order,recip +TgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,rania,rania,\\"rania Wise\\",\\"rania Wise\\",FEMALE,24,Wise,Wise,\\"(empty)\\",Sunday,6,\\"rania@wise-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564395,\\"sold_product_564395_16857, sold_product_564395_21378\\",\\"sold_product_564395_16857, sold_product_564395_21378\\",\\"50, 11.992\\",\\"50, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"24, 6.109\\",\\"50, 11.992\\",\\"16,857, 21,378\\",\\"Ballet pumps - night, Pyjama bottoms - pink\\",\\"Ballet pumps - night, Pyjama bottoms - pink\\",\\"1, 1\\",\\"ZO0236702367, ZO0660706607\\",\\"0, 0\\",\\"50, 11.992\\",\\"50, 11.992\\",\\"0, 0\\",\\"ZO0236702367, ZO0660706607\\",\\"61.969\\",\\"61.969\\",2,2,order,rani +awMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Pia,Pia,\\"Pia Chapman\\",\\"Pia Chapman\\",FEMALE,45,Chapman,Chapman,\\"(empty)\\",Sunday,6,\\"pia@chapman-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564686,\\"sold_product_564686_4640, sold_product_564686_12658\\",\\"sold_product_564686_4640, sold_product_564686_12658\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"36, 8.492\\",\\"75, 16.984\\",\\"4,640, 12,658\\",\\"Winter boots - black, Ballet pumps - nude\\",\\"Winter boots - black, Ballet pumps - nude\\",\\"1, 1\\",\\"ZO0373303733, ZO0131201312\\",\\"0, 0\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"0, 0\\",\\"ZO0373303733, ZO0131201312\\",92,92,2,2,order,pia +dAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Cross\\",\\"Betty Cross\\",FEMALE,44,Cross,Cross,\\"(empty)\\",Sunday,6,\\"betty@cross-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564446,\\"sold_product_564446_12508, sold_product_564446_25164\\",\\"sold_product_564446_12508, sold_product_564446_25164\\",\\"28.984, 65\\",\\"28.984, 65\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"14.492, 30.547\\",\\"28.984, 65\\",\\"12,508, 25,164\\",\\"Tote bag - black, Trainers - grey\\",\\"Tote bag - black, Trainers - grey\\",\\"1, 1\\",\\"ZO0093400934, ZO0679406794\\",\\"0, 0\\",\\"28.984, 65\\",\\"28.984, 65\\",\\"0, 0\\",\\"ZO0093400934, ZO0679406794\\",94,94,2,2,order,betty +dQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Yasmine,Yasmine,\\"Yasmine Mcdonald\\",\\"Yasmine Mcdonald\\",FEMALE,43,Mcdonald,Mcdonald,\\"(empty)\\",Sunday,6,\\"yasmine@mcdonald-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564481,\\"sold_product_564481_17689, sold_product_564481_11690\\",\\"sold_product_564481_17689, sold_product_564481_11690\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"25.984, 5.5\\",\\"50, 10.992\\",\\"17,689, 11,690\\",\\"Classic heels - navy/white, Necklace - imitation rhodium\\",\\"Classic heels - navy/white, Necklace - imitation rhodium\\",\\"1, 1\\",\\"ZO0321603216, ZO0078000780\\",\\"0, 0\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"0, 0\\",\\"ZO0321603216, ZO0078000780\\",\\"60.969\\",\\"60.969\\",2,2,order,yasmine +fAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Mary,Mary,\\"Mary Griffin\\",\\"Mary Griffin\\",FEMALE,20,Griffin,Griffin,\\"(empty)\\",Sunday,6,\\"mary@griffin-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563953,\\"sold_product_563953_22678, sold_product_563953_17921\\",\\"sold_product_563953_22678, sold_product_563953_17921\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"31.188, 9.867\\",\\"60, 20.984\\",\\"22,678, 17,921\\",\\"Ankle boots - Midnight Blue, Amber - Wallet - black\\",\\"Ankle boots - Midnight Blue, Amber - Wallet - black\\",\\"1, 1\\",\\"ZO0376203762, ZO0303603036\\",\\"0, 0\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"0, 0\\",\\"ZO0376203762, ZO0303603036\\",81,81,2,2,order,mary +9gMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Frances,Frances,\\"Frances Gibbs\\",\\"Frances Gibbs\\",FEMALE,49,Gibbs,Gibbs,\\"(empty)\\",Sunday,6,\\"frances@gibbs-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565061,\\"sold_product_565061_1774, sold_product_565061_20952\\",\\"sold_product_565061_1774, sold_product_565061_20952\\",\\"60, 33\\",\\"60, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"27.594, 16.172\\",\\"60, 33\\",\\"1,774, 20,952\\",\\"Lace-ups - cognac, Light jacket - navy\\",\\"Lace-ups - cognac, Light jacket - navy\\",\\"1, 1\\",\\"ZO0681106811, ZO0286402864\\",\\"0, 0\\",\\"60, 33\\",\\"60, 33\\",\\"0, 0\\",\\"ZO0681106811, ZO0286402864\\",93,93,2,2,order,frances +9wMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Jenkins\\",\\"Elyssa Jenkins\\",FEMALE,27,Jenkins,Jenkins,\\"(empty)\\",Sunday,6,\\"elyssa@jenkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565100,\\"sold_product_565100_13722, sold_product_565100_21376\\",\\"sold_product_565100_13722, sold_product_565100_21376\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"15.844, 8.828\\",\\"33, 16.984\\",\\"13,722, 21,376\\",\\"Cardigan - grey multicolor, Jersey dress - mid grey multicolor\\",\\"Cardigan - grey multicolor, Jersey dress - mid grey multicolor\\",\\"1, 1\\",\\"ZO0069000690, ZO0490004900\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0069000690, ZO0490004900\\",\\"49.969\\",\\"49.969\\",2,2,order,elyssa +3AMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Sharp\\",\\"Oliver Sharp\\",MALE,7,Sharp,Sharp,\\"(empty)\\",Sunday,6,\\"oliver@sharp-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565263,\\"sold_product_565263_15239, sold_product_565263_14475\\",\\"sold_product_565263_15239, sold_product_565263_14475\\",\\"22.984, 25.984\\",\\"22.984, 25.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"11.039, 12.219\\",\\"22.984, 25.984\\",\\"15,239, 14,475\\",\\"Hoodie - light grey/navy, Tracksuit bottoms - black\\",\\"Hoodie - light grey/navy, Tracksuit bottoms - black\\",\\"1, 1\\",\\"ZO0582705827, ZO0111801118\\",\\"0, 0\\",\\"22.984, 25.984\\",\\"22.984, 25.984\\",\\"0, 0\\",\\"ZO0582705827, ZO0111801118\\",\\"48.969\\",\\"48.969\\",2,2,order,oliver +dgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Garner\\",\\"Abdulraheem Al Garner\\",MALE,33,Garner,Garner,\\"(empty)\\",Sunday,6,\\"abdulraheem al@garner-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563984,\\"sold_product_563984_22409, sold_product_563984_20424\\",\\"sold_product_563984_22409, sold_product_563984_20424\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"5.762, 7.129\\",\\"11.992, 13.992\\",\\"22,409, 20,424\\",\\"Basic T-shirt - Dark Salmon, Basic T-shirt - navy\\",\\"Basic T-shirt - Dark Salmon, Basic T-shirt - navy\\",\\"1, 1\\",\\"ZO0121301213, ZO0294102941\\",\\"0, 0\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"0, 0\\",\\"ZO0121301213, ZO0294102941\\",\\"25.984\\",\\"25.984\\",2,2,order,abdulraheem +rgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Brigitte,Brigitte,\\"Brigitte Ramsey\\",\\"Brigitte Ramsey\\",FEMALE,12,Ramsey,Ramsey,\\"(empty)\\",Sunday,6,\\"brigitte@ramsey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565262,\\"sold_product_565262_18767, sold_product_565262_11190\\",\\"sold_product_565262_18767, sold_product_565262_11190\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"10.906, 11.5\\",\\"20.984, 24.984\\",\\"18,767, 11,190\\",\\"Amber - Wallet - cognac, Rucksack - black\\",\\"Amber - Wallet - cognac, Rucksack - black\\",\\"1, 1\\",\\"ZO0303503035, ZO0197601976\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0303503035, ZO0197601976\\",\\"45.969\\",\\"45.969\\",2,2,order,brigitte +rwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Smith\\",\\"Sonya Smith\\",FEMALE,28,Smith,Smith,\\"(empty)\\",Sunday,6,\\"sonya@smith-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565304,\\"sold_product_565304_22359, sold_product_565304_19969\\",\\"sold_product_565304_22359, sold_product_565304_19969\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"12.492, 17.391\\",\\"24.984, 37\\",\\"22,359, 19,969\\",\\"Boots - dark grey, Maxi dress - black/rose gold\\",\\"Boots - dark grey, Maxi dress - black/rose gold\\",\\"1, 1\\",\\"ZO0017800178, ZO0229602296\\",\\"0, 0\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"0, 0\\",\\"ZO0017800178, ZO0229602296\\",\\"61.969\\",\\"61.969\\",2,2,order,sonya +vgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Recip,Recip,\\"Recip Ryan\\",\\"Recip Ryan\\",MALE,10,Ryan,Ryan,\\"(empty)\\",Sunday,6,\\"recip@ryan-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565123,\\"sold_product_565123_14743, sold_product_565123_22906\\",\\"sold_product_565123_14743, sold_product_565123_22906\\",\\"33, 75\\",\\"33, 75\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"17.156, 35.25\\",\\"33, 75\\",\\"14,743, 22,906\\",\\"Laptop bag - black, Lace-up boots - black\\",\\"Laptop bag - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0316903169, ZO0400504005\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0316903169, ZO0400504005\\",108,108,2,2,order,recip +vwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Hansen\\",\\"Robbie Hansen\\",MALE,48,Hansen,Hansen,\\"(empty)\\",Sunday,6,\\"robbie@hansen-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565160,\\"sold_product_565160_19961, sold_product_565160_19172\\",\\"sold_product_565160_19961, sold_product_565160_19172\\",\\"75, 20.984\\",\\"75, 20.984\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"36, 10.078\\",\\"75, 20.984\\",\\"19,961, 19,172\\",\\"Lace-up boots - Burly Wood , Trainers - black/white\\",\\"Lace-up boots - Burly Wood , Trainers - black/white\\",\\"1, 1\\",\\"ZO0693306933, ZO0514605146\\",\\"0, 0\\",\\"75, 20.984\\",\\"75, 20.984\\",\\"0, 0\\",\\"ZO0693306933, ZO0514605146\\",96,96,2,2,order,robbie +wgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Bryant\\",\\"Irwin Bryant\\",MALE,14,Bryant,Bryant,\\"(empty)\\",Sunday,6,\\"irwin@bryant-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565224,\\"sold_product_565224_2269, sold_product_565224_23958\\",\\"sold_product_565224_2269, sold_product_565224_23958\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"23, 13.242\\",\\"50, 24.984\\",\\"2,269, 23,958\\",\\"Boots - Slate Gray, Jumper - black\\",\\"Boots - Slate Gray, Jumper - black\\",\\"1, 1\\",\\"ZO0406604066, ZO0576805768\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0406604066, ZO0576805768\\",75,75,2,2,order,irwin +2wMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Rivera\\",\\"Mostafa Rivera\\",MALE,9,Rivera,Rivera,\\"(empty)\\",Sunday,6,\\"mostafa@rivera-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564121,\\"sold_product_564121_24202, sold_product_564121_21006\\",\\"sold_product_564121_24202, sold_product_564121_21006\\",\\"7.988, 10.992\\",\\"7.988, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"3.92, 5.5\\",\\"7.988, 10.992\\",\\"24,202, 21,006\\",\\"Basic T-shirt - white, Sports shirt - bright white\\",\\"Basic T-shirt - white, Sports shirt - bright white\\",\\"1, 1\\",\\"ZO0291902919, ZO0617206172\\",\\"0, 0\\",\\"7.988, 10.992\\",\\"7.988, 10.992\\",\\"0, 0\\",\\"ZO0291902919, ZO0617206172\\",\\"18.984\\",\\"18.984\\",2,2,order,mostafa +3AMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Yahya,Yahya,\\"Yahya Tyler\\",\\"Yahya Tyler\\",MALE,23,Tyler,Tyler,\\"(empty)\\",Sunday,6,\\"yahya@tyler-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564166,\\"sold_product_564166_14500, sold_product_564166_17015\\",\\"sold_product_564166_14500, sold_product_564166_17015\\",\\"28.984, 85\\",\\"28.984, 85\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"15.07, 41.656\\",\\"28.984, 85\\",\\"14,500, 17,015\\",\\"Laptop bag - black, Briefcase - brown\\",\\"Laptop bag - black, Briefcase - brown\\",\\"1, 1\\",\\"ZO0607106071, ZO0470704707\\",\\"0, 0\\",\\"28.984, 85\\",\\"28.984, 85\\",\\"0, 0\\",\\"ZO0607106071, ZO0470704707\\",114,114,2,2,order,yahya +3wMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Rivera\\",\\"Wilhemina St. Rivera\\",FEMALE,17,Rivera,Rivera,\\"(empty)\\",Sunday,6,\\"wilhemina st.@rivera-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse, Oceanavigations\\",\\"Gnomehouse, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564739,\\"sold_product_564739_21607, sold_product_564739_14854\\",\\"sold_product_564739_21607, sold_product_564739_14854\\",\\"55, 50\\",\\"55, 50\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Oceanavigations\\",\\"Gnomehouse, Oceanavigations\\",\\"25.844, 23.5\\",\\"55, 50\\",\\"21,607, 14,854\\",\\"Jersey dress - inca gold, Ballet pumps - argento\\",\\"Jersey dress - inca gold, Ballet pumps - argento\\",\\"1, 1\\",\\"ZO0335603356, ZO0236502365\\",\\"0, 0\\",\\"55, 50\\",\\"55, 50\\",\\"0, 0\\",\\"ZO0335603356, ZO0236502365\\",105,105,2,2,order,wilhemina +OQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Wood\\",\\"Jason Wood\\",MALE,16,Wood,Wood,\\"(empty)\\",Sunday,6,\\"jason@wood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564016,\\"sold_product_564016_21164, sold_product_564016_3074\\",\\"sold_product_564016_21164, sold_product_564016_3074\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"5.93, 27.594\\",\\"10.992, 60\\",\\"21,164, 3,074\\",\\"Long sleeved top - dark blue, Trenchcoat - navy\\",\\"Long sleeved top - dark blue, Trenchcoat - navy\\",\\"1, 1\\",\\"ZO0436904369, ZO0290402904\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0436904369, ZO0290402904\\",71,71,2,2,order,jason +OgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jim,Jim,\\"Jim Duncan\\",\\"Jim Duncan\\",MALE,41,Duncan,Duncan,\\"(empty)\\",Sunday,6,\\"jim@duncan-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564576,\\"sold_product_564576_1384, sold_product_564576_12074\\",\\"sold_product_564576_1384, sold_product_564576_12074\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"31.188, 5.641\\",\\"60, 11.992\\",\\"1,384, 12,074\\",\\"Lace-ups - black , Polo shirt - blue\\",\\"Lace-ups - black , Polo shirt - blue\\",\\"1, 1\\",\\"ZO0681206812, ZO0441904419\\",\\"0, 0\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"0, 0\\",\\"ZO0681206812, ZO0441904419\\",72,72,2,2,order,jim +OwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Yasmine,Yasmine,\\"Yasmine Fletcher\\",\\"Yasmine Fletcher\\",FEMALE,43,Fletcher,Fletcher,\\"(empty)\\",Sunday,6,\\"yasmine@fletcher-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564605,\\"sold_product_564605_17630, sold_product_564605_14381\\",\\"sold_product_564605_17630, sold_product_564605_14381\\",\\"60, 75\\",\\"60, 75\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"31.188, 34.5\\",\\"60, 75\\",\\"17,630, 14,381\\",\\"Summer dress - navy blazer, Tote bag - cognac\\",\\"Summer dress - navy blazer, Tote bag - cognac\\",\\"1, 1\\",\\"ZO0333103331, ZO0694806948\\",\\"0, 0\\",\\"60, 75\\",\\"60, 75\\",\\"0, 0\\",\\"ZO0333103331, ZO0694806948\\",135,135,2,2,order,yasmine +5QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Mullins\\",\\"Wilhemina St. Mullins\\",FEMALE,17,Mullins,Mullins,\\"(empty)\\",Sunday,6,\\"wilhemina st.@mullins-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Angeldale, Low Tide Media, Tigress Enterprises\\",\\"Angeldale, Low Tide Media, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",730663,\\"sold_product_730663_12404, sold_product_730663_15087, sold_product_730663_13055, sold_product_730663_5529\\",\\"sold_product_730663_12404, sold_product_730663_15087, sold_product_730663_13055, sold_product_730663_5529\\",\\"33, 42, 60, 33\\",\\"33, 42, 60, 33\\",\\"Women's Accessories, Women's Shoes, Women's Shoes, Women's Shoes\\",\\"Women's Accessories, Women's Shoes, Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Low Tide Media, Low Tide Media, Tigress Enterprises\\",\\"Angeldale, Low Tide Media, Low Tide Media, Tigress Enterprises\\",\\"17.156, 21.406, 27.594, 17.813\\",\\"33, 42, 60, 33\\",\\"12,404, 15,087, 13,055, 5,529\\",\\"Clutch - black, Sandals - cognac, Lace-ups - perla, Lace-up boots - cognac\\",\\"Clutch - black, Sandals - cognac, Lace-ups - perla, Lace-up boots - cognac\\",\\"1, 1, 1, 1\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\",\\"0, 0, 0, 0\\",\\"33, 42, 60, 33\\",\\"33, 42, 60, 33\\",\\"0, 0, 0, 0\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\",168,168,4,4,order,wilhemina +BAMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Samir,Samir,\\"Samir Chapman\\",\\"Samir Chapman\\",MALE,34,Chapman,Chapman,\\"(empty)\\",Sunday,6,\\"samir@chapman-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564366,\\"sold_product_564366_810, sold_product_564366_11140\\",\\"sold_product_564366_810, sold_product_564366_11140\\",\\"80, 10.992\\",\\"80, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"38.406, 5.5\\",\\"80, 10.992\\",\\"810, 11,140\\",\\"Smart lace-ups - dark brown, Print T-shirt - dark blue\\",\\"Smart lace-ups - dark brown, Print T-shirt - dark blue\\",\\"1, 1\\",\\"ZO0681906819, ZO0549705497\\",\\"0, 0\\",\\"80, 10.992\\",\\"80, 10.992\\",\\"0, 0\\",\\"ZO0681906819, ZO0549705497\\",91,91,2,2,order,samir +BQMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Swanson\\",\\"Betty Swanson\\",FEMALE,44,Swanson,Swanson,\\"(empty)\\",Sunday,6,\\"betty@swanson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564221,\\"sold_product_564221_5979, sold_product_564221_19823\\",\\"sold_product_564221_5979, sold_product_564221_19823\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"33.75, 12.25\\",\\"75, 24.984\\",\\"5,979, 19,823\\",\\"Ankle boots - Antique White, Slim fit jeans - dark grey\\",\\"Ankle boots - Antique White, Slim fit jeans - dark grey\\",\\"1, 1\\",\\"ZO0249702497, ZO0487404874\\",\\"0, 0\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"0, 0\\",\\"ZO0249702497, ZO0487404874\\",100,100,2,2,order,betty +CgMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Selena,Selena,\\"Selena Rose\\",\\"Selena Rose\\",FEMALE,42,Rose,Rose,\\"(empty)\\",Sunday,6,\\"selena@rose-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564174,\\"sold_product_564174_12644, sold_product_564174_20872\\",\\"sold_product_564174_12644, sold_product_564174_20872\\",\\"33, 50\\",\\"33, 50\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"16.172, 25.484\\",\\"33, 50\\",\\"12,644, 20,872\\",\\"Jumpsuit - black, Ballet pumps - grey\\",\\"Jumpsuit - black, Ballet pumps - grey\\",\\"1, 1\\",\\"ZO0032300323, ZO0236302363\\",\\"0, 0\\",\\"33, 50\\",\\"33, 50\\",\\"0, 0\\",\\"ZO0032300323, ZO0236302363\\",83,83,2,2,order,selena +DgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Powell\\",\\"Diane Powell\\",FEMALE,22,Powell,Powell,\\"(empty)\\",Saturday,5,\\"diane@powell-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries active\\",\\"Pyramidustries active\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562835,\\"sold_product_562835_23805, sold_product_562835_22240\\",\\"sold_product_562835_23805, sold_product_562835_22240\\",\\"20.984, 14.992\\",\\"20.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Pyramidustries active\\",\\"Pyramidustries active, Pyramidustries active\\",\\"9.453, 7.051\\",\\"20.984, 14.992\\",\\"23,805, 22,240\\",\\"Tights - black , Tights - mid grey multicolor\\",\\"Tights - black , Tights - mid grey multicolor\\",\\"1, 1\\",\\"ZO0222302223, ZO0223502235\\",\\"0, 0\\",\\"20.984, 14.992\\",\\"20.984, 14.992\\",\\"0, 0\\",\\"ZO0222302223, ZO0223502235\\",\\"35.969\\",\\"35.969\\",2,2,order,diane +DwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Dixon\\",\\"Tariq Dixon\\",MALE,25,Dixon,Dixon,\\"(empty)\\",Saturday,5,\\"tariq@dixon-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562882,\\"sold_product_562882_16957, sold_product_562882_6401\\",\\"sold_product_562882_16957, sold_product_562882_6401\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"5.711, 10.078\\",\\"10.992, 20.984\\",\\"16,957, 6,401\\",\\"Cap - navy, Shirt - Blue Violety\\",\\"Cap - navy, Shirt - Blue Violety\\",\\"1, 1\\",\\"ZO0460804608, ZO0523905239\\",\\"0, 0\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"0, 0\\",\\"ZO0460804608, ZO0523905239\\",\\"31.984\\",\\"31.984\\",2,2,order,tariq +EAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Daniels\\",\\"Sonya Daniels\\",FEMALE,28,Daniels,Daniels,\\"(empty)\\",Saturday,5,\\"sonya@daniels-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562629,\\"sold_product_562629_21956, sold_product_562629_24341\\",\\"sold_product_562629_21956, sold_product_562629_24341\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"5.82, 6.859\\",\\"10.992, 13.992\\",\\"21,956, 24,341\\",\\"Long sleeved top - royal blue, Scarf - rose\\",\\"Long sleeved top - royal blue, Scarf - rose\\",\\"1, 1\\",\\"ZO0639506395, ZO0083000830\\",\\"0, 0\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"0, 0\\",\\"ZO0639506395, ZO0083000830\\",\\"24.984\\",\\"24.984\\",2,2,order,sonya +EQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Maldonado\\",\\"Jim Maldonado\\",MALE,41,Maldonado,Maldonado,\\"(empty)\\",Saturday,5,\\"jim@maldonado-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562672,\\"sold_product_562672_14354, sold_product_562672_18181\\",\\"sold_product_562672_14354, sold_product_562672_18181\\",\\"7.988, 10.992\\",\\"7.988, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.68, 5.711\\",\\"7.988, 10.992\\",\\"14,354, 18,181\\",\\"(3) Pack - Socks - white/black , Long sleeved top - bordeaux\\",\\"(3) Pack - Socks - white/black , Long sleeved top - bordeaux\\",\\"1, 1\\",\\"ZO0613406134, ZO0436304363\\",\\"0, 0\\",\\"7.988, 10.992\\",\\"7.988, 10.992\\",\\"0, 0\\",\\"ZO0613406134, ZO0436304363\\",\\"18.984\\",\\"18.984\\",2,2,order,jim +YwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Munoz\\",\\"rania Munoz\\",FEMALE,24,Munoz,Munoz,\\"(empty)\\",Saturday,5,\\"rania@munoz-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563193,\\"sold_product_563193_13167, sold_product_563193_12035\\",\\"sold_product_563193_13167, sold_product_563193_12035\\",\\"7.988, 14.992\\",\\"7.988, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"3.68, 7.051\\",\\"7.988, 14.992\\",\\"13,167, 12,035\\",\\"Vest - dark grey, Jersey dress - black\\",\\"Vest - dark grey, Jersey dress - black\\",\\"1, 1\\",\\"ZO0636906369, ZO0150301503\\",\\"0, 0\\",\\"7.988, 14.992\\",\\"7.988, 14.992\\",\\"0, 0\\",\\"ZO0636906369, ZO0150301503\\",\\"22.984\\",\\"22.984\\",2,2,order,rani +ZAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Swanson\\",\\"Fitzgerald Swanson\\",MALE,11,Swanson,Swanson,\\"(empty)\\",Saturday,5,\\"fitzgerald@swanson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563440,\\"sold_product_563440_17325, sold_product_563440_1907\\",\\"sold_product_563440_17325, sold_product_563440_1907\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"9.867, 33.75\\",\\"20.984, 75\\",\\"17,325, 1,907\\",\\"Sweatshirt - white, Lace-up boots - black\\",\\"Sweatshirt - white, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0589605896, ZO0257202572\\",\\"0, 0\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"0, 0\\",\\"ZO0589605896, ZO0257202572\\",96,96,2,2,order,fuzzy +ZQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Jim,Jim,\\"Jim Cortez\\",\\"Jim Cortez\\",MALE,41,Cortez,Cortez,\\"(empty)\\",Saturday,5,\\"jim@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",563485,\\"sold_product_563485_23858, sold_product_563485_16559\\",\\"sold_product_563485_23858, sold_product_563485_16559\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"6.23, 18.5\\",\\"11.992, 37\\",\\"23,858, 16,559\\",\\"Wallet - cognac, Boots - black\\",\\"Wallet - cognac, Boots - black\\",\\"1, 1\\",\\"ZO0602606026, ZO0522005220\\",\\"0, 0\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"0, 0\\",\\"ZO0602606026, ZO0522005220\\",\\"48.969\\",\\"48.969\\",2,2,order,jim +1QMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Underwood\\",\\"Diane Underwood\\",FEMALE,22,Underwood,Underwood,\\"(empty)\\",Saturday,5,\\"diane@underwood-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562792,\\"sold_product_562792_14720, sold_product_562792_9051\\",\\"sold_product_562792_14720, sold_product_562792_9051\\",\\"50, 33\\",\\"50, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"26.984, 17.156\\",\\"50, 33\\",\\"14,720, 9,051\\",\\"High heeled sandals - nude, Jersey dress - navy blazer\\",\\"High heeled sandals - nude, Jersey dress - navy blazer\\",\\"1, 1\\",\\"ZO0242602426, ZO0336103361\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0242602426, ZO0336103361\\",83,83,2,2,order,diane +dwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Boone\\",\\"Stephanie Boone\\",FEMALE,6,Boone,Boone,\\"(empty)\\",Saturday,5,\\"stephanie@boone-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563365,\\"sold_product_563365_24862, sold_product_563365_20441\\",\\"sold_product_563365_24862, sold_product_563365_20441\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"5.5, 14.211\\",\\"10.992, 28.984\\",\\"24,862, 20,441\\",\\"Print T-shirt - dark blue/off white, Blouse - black/white\\",\\"Print T-shirt - dark blue/off white, Blouse - black/white\\",\\"1, 1\\",\\"ZO0646206462, ZO0065200652\\",\\"0, 0\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"0, 0\\",\\"ZO0646206462, ZO0065200652\\",\\"39.969\\",\\"39.969\\",2,2,order,stephanie +iwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Marwan,Marwan,\\"Marwan Wood\\",\\"Marwan Wood\\",MALE,51,Wood,Wood,\\"(empty)\\",Saturday,5,\\"marwan@wood-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562688,\\"sold_product_562688_22319, sold_product_562688_11707\\",\\"sold_product_562688_22319, sold_product_562688_11707\\",\\"24.984, 13.992\\",\\"24.984, 13.992\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"13.742, 7.41\\",\\"24.984, 13.992\\",\\"22,319, 11,707\\",\\"Trainers - black, Wash bag - dark grey \\",\\"Trainers - black, Wash bag - dark grey \\",\\"1, 1\\",\\"ZO0394603946, ZO0608406084\\",\\"0, 0\\",\\"24.984, 13.992\\",\\"24.984, 13.992\\",\\"0, 0\\",\\"ZO0394603946, ZO0608406084\\",\\"38.969\\",\\"38.969\\",2,2,order,marwan +jAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",EUR,Marwan,Marwan,\\"Marwan Barnes\\",\\"Marwan Barnes\\",MALE,51,Barnes,Barnes,\\"(empty)\\",Saturday,5,\\"marwan@barnes-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563647,\\"sold_product_563647_20757, sold_product_563647_11341\\",\\"sold_product_563647_20757, sold_product_563647_11341\\",\\"80, 42\\",\\"80, 42\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"40.781, 22.25\\",\\"80, 42\\",\\"20,757, 11,341\\",\\"Lace-up boots - dark brown, Weekend bag - classic navy\\",\\"Lace-up boots - dark brown, Weekend bag - classic navy\\",\\"1, 1\\",\\"ZO0690906909, ZO0319003190\\",\\"0, 0\\",\\"80, 42\\",\\"80, 42\\",\\"0, 0\\",\\"ZO0690906909, ZO0319003190\\",122,122,2,2,order,marwan +jQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Reese\\",\\"Kamal Reese\\",MALE,39,Reese,Reese,\\"(empty)\\",Saturday,5,\\"kamal@reese-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,Oceanavigations,Oceanavigations,\\"Jun 21, 2019 @ 00:00:00.000\\",563711,\\"sold_product_563711_22407, sold_product_563711_11553\\",\\"sold_product_563711_22407, sold_product_563711_11553\\",\\"60, 140\\",\\"60, 140\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"33, 72.813\\",\\"60, 140\\",\\"22,407, 11,553\\",\\"Lace-ups - grey, Leather jacket - camel\\",\\"Lace-ups - grey, Leather jacket - camel\\",\\"1, 1\\",\\"ZO0254202542, ZO0288202882\\",\\"0, 0\\",\\"60, 140\\",\\"60, 140\\",\\"0, 0\\",\\"ZO0254202542, ZO0288202882\\",200,200,2,2,order,kamal +2AMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Phil,Phil,\\"Phil Willis\\",\\"Phil Willis\\",MALE,50,Willis,Willis,\\"(empty)\\",Saturday,5,\\"phil@willis-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563763,\\"sold_product_563763_16794, sold_product_563763_13661\\",\\"sold_product_563763_16794, sold_product_563763_13661\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"10.703, 10.492\\",\\"20.984, 20.984\\",\\"16,794, 13,661\\",\\"Swimming shorts - white, Tracksuit bottoms - light grey\\",\\"Swimming shorts - white, Tracksuit bottoms - light grey\\",\\"1, 1\\",\\"ZO0479404794, ZO0525305253\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0479404794, ZO0525305253\\",\\"41.969\\",\\"41.969\\",2,2,order,phil +BQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Mary,Mary,\\"Mary Brock\\",\\"Mary Brock\\",FEMALE,20,Brock,Brock,\\"(empty)\\",Saturday,5,\\"mary@brock-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,Oceanavigations,Oceanavigations,\\"Jun 21, 2019 @ 00:00:00.000\\",563825,\\"sold_product_563825_25104, sold_product_563825_5962\\",\\"sold_product_563825_25104, sold_product_563825_5962\\",\\"65, 65\\",\\"65, 65\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"35.094, 33.125\\",\\"65, 65\\",\\"25,104, 5,962\\",\\"Classic heels - rose/true nude, High heels - black\\",\\"Classic heels - rose/true nude, High heels - black\\",\\"1, 1\\",\\"ZO0238202382, ZO0237102371\\",\\"0, 0\\",\\"65, 65\\",\\"65, 65\\",\\"0, 0\\",\\"ZO0238202382, ZO0237102371\\",130,130,2,2,order,mary +HAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Cook\\",\\"Irwin Cook\\",MALE,14,Cook,Cook,\\"(empty)\\",Saturday,5,\\"irwin@cook-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562797,\\"sold_product_562797_20442, sold_product_562797_20442\\",\\"sold_product_562797_20442, sold_product_562797_20442\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"5.398, 5.398\\",\\"11.992, 11.992\\",\\"20,442, 20,442\\",\\"Polo shirt - dark grey multicolor, Polo shirt - dark grey multicolor\\",\\"Polo shirt - dark grey multicolor, Polo shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0442504425, ZO0442504425\\",\\"0, 0\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"0, 0\\",ZO0442504425,\\"23.984\\",\\"23.984\\",2,2,order,irwin +SgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Goodwin\\",\\"Abigail Goodwin\\",FEMALE,46,Goodwin,Goodwin,\\"(empty)\\",Saturday,5,\\"abigail@goodwin-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563846,\\"sold_product_563846_23161, sold_product_563846_13874\\",\\"sold_product_563846_23161, sold_product_563846_13874\\",\\"100, 16.984\\",\\"100, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"53, 9\\",\\"100, 16.984\\",\\"23,161, 13,874\\",\\"Boots - brandy, Long sleeved top - khaki\\",\\"Boots - brandy, Long sleeved top - khaki\\",\\"1, 1\\",\\"ZO0244102441, ZO0169301693\\",\\"0, 0\\",\\"100, 16.984\\",\\"100, 16.984\\",\\"0, 0\\",\\"ZO0244102441, ZO0169301693\\",117,117,2,2,order,abigail +SwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Burton\\",\\"Youssef Burton\\",MALE,31,Burton,Burton,\\"(empty)\\",Saturday,5,\\"youssef@burton-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563887,\\"sold_product_563887_11751, sold_product_563887_18663\\",\\"sold_product_563887_11751, sold_product_563887_18663\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"14.781, 8.156\\",\\"28.984, 16.984\\",\\"11,751, 18,663\\",\\"Shorts - beige, Print T-shirt - dark blue multicolor\\",\\"Shorts - beige, Print T-shirt - dark blue multicolor\\",\\"1, 1\\",\\"ZO0423104231, ZO0438204382\\",\\"0, 0\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"0, 0\\",\\"ZO0423104231, ZO0438204382\\",\\"45.969\\",\\"45.969\\",2,2,order,youssef +UgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Willis\\",\\"Rabbia Al Willis\\",FEMALE,5,Willis,Willis,\\"(empty)\\",Saturday,5,\\"rabbia al@willis-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563607,\\"sold_product_563607_23412, sold_product_563607_14303\\",\\"sold_product_563607_23412, sold_product_563607_14303\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"17.813, 36\\",\\"33, 75\\",\\"23,412, 14,303\\",\\"Jeans Skinny Fit - black, Ankle boots - black\\",\\"Jeans Skinny Fit - black, Ankle boots - black\\",\\"1, 1\\",\\"ZO0271002710, ZO0678806788\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0271002710, ZO0678806788\\",108,108,2,2,order,rabbia +jgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Bryan\\",\\"Betty Bryan\\",FEMALE,44,Bryan,Bryan,\\"(empty)\\",Saturday,5,\\"betty@bryan-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562762,\\"sold_product_562762_23139, sold_product_562762_13840\\",\\"sold_product_562762_23139, sold_product_562762_13840\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"6.23, 29.906\\",\\"11.992, 65\\",\\"23,139, 13,840\\",\\"Print T-shirt - black/berry, Boots - Royal Blue\\",\\"Print T-shirt - black/berry, Boots - Royal Blue\\",\\"1, 1\\",\\"ZO0162401624, ZO0375203752\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0162401624, ZO0375203752\\",77,77,2,2,order,betty +9AMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Sutton\\",\\"Elyssa Sutton\\",FEMALE,27,Sutton,Sutton,\\"(empty)\\",Saturday,5,\\"elyssa@sutton-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Primemaster, Spherecords\\",\\"Tigress Enterprises, Primemaster, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",723905,\\"sold_product_723905_24589, sold_product_723905_11977, sold_product_723905_13368, sold_product_723905_14021\\",\\"sold_product_723905_24589, sold_product_723905_11977, sold_product_723905_13368, sold_product_723905_14021\\",\\"24.984, 100, 21.984, 20.984\\",\\"24.984, 100, 21.984, 20.984\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Primemaster, Spherecords, Spherecords\\",\\"Tigress Enterprises, Primemaster, Spherecords, Spherecords\\",\\"13.492, 54, 11.867, 10.906\\",\\"24.984, 100, 21.984, 20.984\\",\\"24,589, 11,977, 13,368, 14,021\\",\\"Boots - black, Ankle boots - Midnight Blue, Chinos - light blue, Shirt - black\\",\\"Boots - black, Ankle boots - Midnight Blue, Chinos - light blue, Shirt - black\\",\\"1, 1, 1, 1\\",\\"ZO0030300303, ZO0360003600, ZO0632906329, ZO0650906509\\",\\"0, 0, 0, 0\\",\\"24.984, 100, 21.984, 20.984\\",\\"24.984, 100, 21.984, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0030300303, ZO0360003600, ZO0632906329, ZO0650906509\\",168,168,4,4,order,elyssa +FQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Boone\\",\\"Elyssa Boone\\",FEMALE,27,Boone,Boone,\\"(empty)\\",Saturday,5,\\"elyssa@boone-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises MAMA, Champion Arts\\",\\"Tigress Enterprises MAMA, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563195,\\"sold_product_563195_14393, sold_product_563195_22789\\",\\"sold_product_563195_14393, sold_product_563195_22789\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Champion Arts\\",\\"Tigress Enterprises MAMA, Champion Arts\\",\\"9.453, 13.633\\",\\"20.984, 28.984\\",\\"14,393, 22,789\\",\\"Print T-shirt - grey metallic, Tracksuit top - blue\\",\\"Print T-shirt - grey metallic, Tracksuit top - blue\\",\\"1, 1\\",\\"ZO0231802318, ZO0501805018\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0231802318, ZO0501805018\\",\\"49.969\\",\\"49.969\\",2,2,order,elyssa +FgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Bowers\\",\\"Selena Bowers\\",FEMALE,42,Bowers,Bowers,\\"(empty)\\",Saturday,5,\\"selena@bowers-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563436,\\"sold_product_563436_24555, sold_product_563436_11768\\",\\"sold_product_563436_24555, sold_product_563436_11768\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"10.492, 4.07\\",\\"20.984, 7.988\\",\\"24,555, 11,768\\",\\"Blouse - dark red, Bracelet - black\\",\\"Blouse - dark red, Bracelet - black\\",\\"1, 1\\",\\"ZO0651606516, ZO0078100781\\",\\"0, 0\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"0, 0\\",\\"ZO0651606516, ZO0078100781\\",\\"28.984\\",\\"28.984\\",2,2,order,selena +FwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Robert,Robert,\\"Robert Phelps\\",\\"Robert Phelps\\",MALE,29,Phelps,Phelps,\\"(empty)\\",Saturday,5,\\"robert@phelps-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Microlutions, (empty)\\",\\"Microlutions, (empty)\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563489,\\"sold_product_563489_21239, sold_product_563489_13428\\",\\"sold_product_563489_21239, sold_product_563489_13428\\",\\"11.992, 165\\",\\"11.992, 165\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, (empty)\\",\\"Microlutions, (empty)\\",\\"6.469, 90.75\\",\\"11.992, 165\\",\\"21,239, 13,428\\",\\"Hat - multicolor/black, Demi-Boots\\",\\"Hat - multicolor/black, Demi-Boots\\",\\"1, 1\\",\\"ZO0126101261, ZO0483704837\\",\\"0, 0\\",\\"11.992, 165\\",\\"11.992, 165\\",\\"0, 0\\",\\"ZO0126101261, ZO0483704837\\",177,177,2,2,order,robert +dgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Graham\\",\\"Elyssa Graham\\",FEMALE,27,Graham,Graham,\\"(empty)\\",Saturday,5,\\"elyssa@graham-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Oceanavigations, Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Pyramidustries, Oceanavigations, Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",727576,\\"sold_product_727576_18143, sold_product_727576_19012, sold_product_727576_16454, sold_product_727576_11955\\",\\"sold_product_727576_18143, sold_product_727576_19012, sold_product_727576_16454, sold_product_727576_11955\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Oceanavigations, Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Pyramidustries, Oceanavigations, Tigress Enterprises MAMA, Tigress Enterprises\\",\\"11.117, 9.453, 10.063, 10.438\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"18,143, 19,012, 16,454, 11,955\\",\\"Jumper - bordeaux, Vest - black/rose, Vest - black, Print T-shirt - red\\",\\"Jumper - bordeaux, Vest - black/rose, Vest - black, Print T-shirt - red\\",\\"1, 1, 1, 1\\",\\"ZO0181201812, ZO0266902669, ZO0231702317, ZO0055800558\\",\\"0, 0, 0, 0\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"0, 0, 0, 0\\",\\"ZO0181201812, ZO0266902669, ZO0231702317, ZO0055800558\\",\\"79.938\\",\\"79.938\\",4,4,order,elyssa +swMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Stewart\\",\\"Marwan Stewart\\",MALE,51,Stewart,Stewart,\\"(empty)\\",Saturday,5,\\"marwan@stewart-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563167,\\"sold_product_563167_24934, sold_product_563167_11541\\",\\"sold_product_563167_24934, sold_product_563167_11541\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"22.5, 8.547\\",\\"50, 18.984\\",\\"24,934, 11,541\\",\\"Lace-up boots - resin coffee, Polo shirt - black\\",\\"Lace-up boots - resin coffee, Polo shirt - black\\",\\"1, 1\\",\\"ZO0403504035, ZO0295602956\\",\\"0, 0\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"0, 0\\",\\"ZO0403504035, ZO0295602956\\",69,69,2,2,order,marwan +tAMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Selena,Selena,\\"Selena Gibbs\\",\\"Selena Gibbs\\",FEMALE,42,Gibbs,Gibbs,\\"(empty)\\",Saturday,5,\\"selena@gibbs-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563212,\\"sold_product_563212_21217, sold_product_563212_22846\\",\\"sold_product_563212_21217, sold_product_563212_22846\\",\\"33, 50\\",\\"33, 50\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"15.844, 25\\",\\"33, 50\\",\\"21,217, 22,846\\",\\"Jumper dress - grey/Medium Slate Blue multicolor, Over-the-knee boots - cognac\\",\\"Jumper dress - grey/Medium Slate Blue multicolor, Over-the-knee boots - cognac\\",\\"1, 1\\",\\"ZO0043700437, ZO0139001390\\",\\"0, 0\\",\\"33, 50\\",\\"33, 50\\",\\"0, 0\\",\\"ZO0043700437, ZO0139001390\\",83,83,2,2,order,selena +tQMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Abbott\\",\\"Muniz Abbott\\",MALE,37,Abbott,Abbott,\\"(empty)\\",Saturday,5,\\"muniz@abbott-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563460,\\"sold_product_563460_2036, sold_product_563460_17157\\",\\"sold_product_563460_2036, sold_product_563460_17157\\",\\"80, 20.984\\",\\"80, 20.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"40, 10.289\\",\\"80, 20.984\\",\\"2,036, 17,157\\",\\"Lace-ups - Midnight Blue, Sweatshirt - off white\\",\\"Lace-ups - Midnight Blue, Sweatshirt - off white\\",\\"1, 1\\",\\"ZO0682506825, ZO0594505945\\",\\"0, 0\\",\\"80, 20.984\\",\\"80, 20.984\\",\\"0, 0\\",\\"ZO0682506825, ZO0594505945\\",101,101,2,2,order,muniz +tgMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Reese\\",\\"Robbie Reese\\",MALE,48,Reese,Reese,\\"(empty)\\",Saturday,5,\\"robbie@reese-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563492,\\"sold_product_563492_13753, sold_product_563492_16739\\",\\"sold_product_563492_13753, sold_product_563492_16739\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"13.742, 29.25\\",\\"24.984, 65\\",\\"13,753, 16,739\\",\\"Formal shirt - white/blue, Suit jacket - dark grey\\",\\"Formal shirt - white/blue, Suit jacket - dark grey\\",\\"1, 1\\",\\"ZO0412004120, ZO0274102741\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0412004120, ZO0274102741\\",90,90,2,2,order,robbie +0wMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Phil,Phil,\\"Phil Graham\\",\\"Phil Graham\\",MALE,50,Graham,Graham,\\"(empty)\\",Saturday,5,\\"phil@graham-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562729,\\"sold_product_562729_12601, sold_product_562729_22654\\",\\"sold_product_562729_12601, sold_product_562729_22654\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"10.906, 12.25\\",\\"20.984, 24.984\\",\\"12,601, 22,654\\",\\"Sweatshirt - bordeaux multicolor, Relaxed fit jeans - vintage blue\\",\\"Sweatshirt - bordeaux multicolor, Relaxed fit jeans - vintage blue\\",\\"1, 1\\",\\"ZO0456404564, ZO0535605356\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0456404564, ZO0535605356\\",\\"45.969\\",\\"45.969\\",2,2,order,phil +4AMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Caldwell\\",\\"Sonya Caldwell\\",FEMALE,28,Caldwell,Caldwell,\\"(empty)\\",Saturday,5,\\"sonya@caldwell-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562978,\\"sold_product_562978_12226, sold_product_562978_11632\\",\\"sold_product_562978_12226, sold_product_562978_11632\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"21.828, 9.867\\",\\"42, 20.984\\",\\"12,226, 11,632\\",\\"Sandals - beige, Summer dress - coral/pink\\",\\"Sandals - beige, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0371003710, ZO0150601506\\",\\"0, 0\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"0, 0\\",\\"ZO0371003710, ZO0150601506\\",\\"62.969\\",\\"62.969\\",2,2,order,sonya +4gMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Mcdonald\\",\\"Wagdi Mcdonald\\",MALE,15,Mcdonald,Mcdonald,\\"(empty)\\",Saturday,5,\\"wagdi@mcdonald-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563324,\\"sold_product_563324_24573, sold_product_563324_20665\\",\\"sold_product_563324_24573, sold_product_563324_20665\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"9.344, 4.949\\",\\"16.984, 10.992\\",\\"24,573, 20,665\\",\\"Basic T-shirt - dark blue multicolor, 3 PACK - Socks - black/white/grey\\",\\"Basic T-shirt - dark blue multicolor, 3 PACK - Socks - black/white/grey\\",\\"1, 1\\",\\"ZO0440004400, ZO0130401304\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0440004400, ZO0130401304\\",\\"27.984\\",\\"27.984\\",2,2,order,wagdi +4wMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Byrd\\",\\"Elyssa Byrd\\",FEMALE,27,Byrd,Byrd,\\"(empty)\\",Saturday,5,\\"elyssa@byrd-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563249,\\"sold_product_563249_14397, sold_product_563249_5141\\",\\"sold_product_563249_14397, sold_product_563249_5141\\",\\"21.984, 60\\",\\"21.984, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"10.344, 33\\",\\"21.984, 60\\",\\"14,397, 5,141\\",\\"Sweatshirt - light grey multicolor, Ankle boots - black\\",\\"Sweatshirt - light grey multicolor, Ankle boots - black\\",\\"1, 1\\",\\"ZO0181001810, ZO0378903789\\",\\"0, 0\\",\\"21.984, 60\\",\\"21.984, 60\\",\\"0, 0\\",\\"ZO0181001810, ZO0378903789\\",82,82,2,2,order,elyssa +5AMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Chandler\\",\\"Brigitte Chandler\\",FEMALE,12,Chandler,Chandler,\\"(empty)\\",Saturday,5,\\"brigitte@chandler-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563286,\\"sold_product_563286_11887, sold_product_563286_22261\\",\\"sold_product_563286_11887, sold_product_563286_22261\\",\\"50, 50\\",\\"50, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"24.5, 22.5\\",\\"50, 50\\",\\"11,887, 22,261\\",\\"Maxi dress - black, Winter jacket - bordeaux\\",\\"Maxi dress - black, Winter jacket - bordeaux\\",\\"1, 1\\",\\"ZO0040000400, ZO0503805038\\",\\"0, 0\\",\\"50, 50\\",\\"50, 50\\",\\"0, 0\\",\\"ZO0040000400, ZO0503805038\\",100,100,2,2,order,brigitte +dgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Shaw\\",\\"Abd Shaw\\",MALE,52,Shaw,Shaw,\\"(empty)\\",Saturday,5,\\"abd@shaw-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563187,\\"sold_product_563187_12040, sold_product_563187_21172\\",\\"sold_product_563187_12040, sold_product_563187_21172\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"12.492, 12.992\\",\\"24.984, 24.984\\",\\"12,040, 21,172\\",\\"Shirt - navy, Jeans Skinny Fit - blue\\",\\"Shirt - navy, Jeans Skinny Fit - blue\\",\\"1, 1\\",\\"ZO0278702787, ZO0425404254\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0278702787, ZO0425404254\\",\\"49.969\\",\\"49.969\\",2,2,order,abd +dwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Gregory\\",\\"Elyssa Gregory\\",FEMALE,27,Gregory,Gregory,\\"(empty)\\",Saturday,5,\\"elyssa@gregory-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563503,\\"sold_product_563503_23310, sold_product_563503_16900\\",\\"sold_product_563503_23310, sold_product_563503_16900\\",\\"19.984, 24.984\\",\\"19.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"9.797, 13.742\\",\\"19.984, 24.984\\",\\"23,310, 16,900\\",\\"Blouse - dark green, Jersey dress - black/white\\",\\"Blouse - dark green, Jersey dress - black/white\\",\\"1, 1\\",\\"ZO0649306493, ZO0490704907\\",\\"0, 0\\",\\"19.984, 24.984\\",\\"19.984, 24.984\\",\\"0, 0\\",\\"ZO0649306493, ZO0490704907\\",\\"44.969\\",\\"44.969\\",2,2,order,elyssa +ewMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Moran\\",\\"Robert Moran\\",MALE,29,Moran,Moran,\\"(empty)\\",Saturday,5,\\"robert@moran-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563275,\\"sold_product_563275_21731, sold_product_563275_19441\\",\\"sold_product_563275_21731, sold_product_563275_19441\\",\\"37, 24.984\\",\\"37, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"17.016, 11.5\\",\\"37, 24.984\\",\\"21,731, 19,441\\",\\"Bomber Jacket - black, Jumper - green multicolor\\",\\"Bomber Jacket - black, Jumper - green multicolor\\",\\"1, 1\\",\\"ZO0287402874, ZO0453404534\\",\\"0, 0\\",\\"37, 24.984\\",\\"37, 24.984\\",\\"0, 0\\",\\"ZO0287402874, ZO0453404534\\",\\"61.969\\",\\"61.969\\",2,2,order,robert +kgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,rania,rania,\\"rania Mccarthy\\",\\"rania Mccarthy\\",FEMALE,24,Mccarthy,Mccarthy,\\"(empty)\\",Saturday,5,\\"rania@mccarthy-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563737,\\"sold_product_563737_12413, sold_product_563737_19717\\",\\"sold_product_563737_12413, sold_product_563737_19717\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"12.25, 22.25\\",\\"24.984, 42\\",\\"12,413, 19,717\\",\\"Clutch - black, Ballet pumps - blue/white\\",\\"Clutch - black, Ballet pumps - blue/white\\",\\"1, 1\\",\\"ZO0306903069, ZO0320703207\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0306903069, ZO0320703207\\",67,67,2,2,order,rani +kwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Foster\\",\\"Boris Foster\\",MALE,36,Foster,Foster,\\"(empty)\\",Saturday,5,\\"boris@foster-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563796,\\"sold_product_563796_15607, sold_product_563796_14438\\",\\"sold_product_563796_15607, sold_product_563796_14438\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"21.406, 13.344\\",\\"42, 28.984\\",\\"15,607, 14,438\\",\\"Soft shell jacket - dark grey, Jumper - dark grey multicolor\\",\\"Soft shell jacket - dark grey, Jumper - dark grey multicolor\\",\\"1, 1\\",\\"ZO0625806258, ZO0297602976\\",\\"0, 0\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"0, 0\\",\\"ZO0625806258, ZO0297602976\\",71,71,2,2,order,boris +vgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Mcdonald\\",\\"Robert Mcdonald\\",MALE,29,Mcdonald,Mcdonald,\\"(empty)\\",Saturday,5,\\"robert@mcdonald-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562853,\\"sold_product_562853_21053, sold_product_562853_23834\\",\\"sold_product_562853_21053, sold_product_562853_23834\\",\\"10.992, 7.988\\",\\"10.992, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.391, 4.07\\",\\"10.992, 7.988\\",\\"21,053, 23,834\\",\\"Print T-shirt - white/blue, 3 PACK - Socks - blue/grey\\",\\"Print T-shirt - white/blue, 3 PACK - Socks - blue/grey\\",\\"1, 1\\",\\"ZO0564705647, ZO0481004810\\",\\"0, 0\\",\\"10.992, 7.988\\",\\"10.992, 7.988\\",\\"0, 0\\",\\"ZO0564705647, ZO0481004810\\",\\"18.984\\",\\"18.984\\",2,2,order,robert +vwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Love\\",\\"Elyssa Love\\",FEMALE,27,Love,Love,\\"(empty)\\",Saturday,5,\\"elyssa@love-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562900,\\"sold_product_562900_15312, sold_product_562900_12544\\",\\"sold_product_562900_15312, sold_product_562900_12544\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"14.211, 12.992\\",\\"28.984, 24.984\\",\\"15,312, 12,544\\",\\"Print T-shirt - coronet blue, Faux leather jacket - black\\",\\"Print T-shirt - coronet blue, Faux leather jacket - black\\",\\"1, 1\\",\\"ZO0349203492, ZO0173801738\\",\\"0, 0\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"0, 0\\",\\"ZO0349203492, ZO0173801738\\",\\"53.969\\",\\"53.969\\",2,2,order,elyssa +wAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Thompson\\",\\"Betty Thompson\\",FEMALE,44,Thompson,Thompson,\\"(empty)\\",Saturday,5,\\"betty@thompson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562668,\\"sold_product_562668_22190, sold_product_562668_24239\\",\\"sold_product_562668_22190, sold_product_562668_24239\\",\\"33, 25.984\\",\\"33, 25.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"15.844, 12.219\\",\\"33, 25.984\\",\\"22,190, 24,239\\",\\"Vest - black, Long sleeved top - winter white/peacoat\\",\\"Vest - black, Long sleeved top - winter white/peacoat\\",\\"1, 1\\",\\"ZO0348503485, ZO0059100591\\",\\"0, 0\\",\\"33, 25.984\\",\\"33, 25.984\\",\\"0, 0\\",\\"ZO0348503485, ZO0059100591\\",\\"58.969\\",\\"58.969\\",2,2,order,betty +zgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Perkins\\",\\"Muniz Perkins\\",MALE,37,Perkins,Perkins,\\"(empty)\\",Saturday,5,\\"muniz@perkins-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562794,\\"sold_product_562794_12403, sold_product_562794_24539\\",\\"sold_product_562794_12403, sold_product_562794_24539\\",\\"75, 15.992\\",\\"75, 15.992\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"35.25, 8.148\\",\\"75, 15.992\\",\\"12,403, 24,539\\",\\"Rucksack - brandy, Long sleeved top - off-white\\",\\"Rucksack - brandy, Long sleeved top - off-white\\",\\"1, 1\\",\\"ZO0701707017, ZO0440404404\\",\\"0, 0\\",\\"75, 15.992\\",\\"75, 15.992\\",\\"0, 0\\",\\"ZO0701707017, ZO0440404404\\",91,91,2,2,order,muniz +\\"-QMtOW0BH63Xcmy442fU\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Caldwell\\",\\"Marwan Caldwell\\",MALE,51,Caldwell,Caldwell,\\"(empty)\\",Saturday,5,\\"marwan@caldwell-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",562720,\\"sold_product_562720_17428, sold_product_562720_13612\\",\\"sold_product_562720_17428, sold_product_562720_13612\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.078, 6.469\\",\\"20.984, 11.992\\",\\"17,428, 13,612\\",\\"Sweatshirt - bordeaux, Basic T-shirt - light red/white\\",\\"Sweatshirt - bordeaux, Basic T-shirt - light red/white\\",\\"1, 1\\",\\"ZO0585605856, ZO0549505495\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0585605856, ZO0549505495\\",\\"32.969\\",\\"32.969\\",2,2,order,marwan +\\"-gMtOW0BH63Xcmy442fU\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Robert,Robert,\\"Robert Reyes\\",\\"Robert Reyes\\",MALE,29,Reyes,Reyes,\\"(empty)\\",Saturday,5,\\"robert@reyes-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562759,\\"sold_product_562759_15827, sold_product_562759_22599\\",\\"sold_product_562759_15827, sold_product_562759_22599\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"9.867, 11.5\\",\\"20.984, 24.984\\",\\"15,827, 22,599\\",\\"Belt - black/brown, Sweatshirt - black\\",\\"Belt - black/brown, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0310403104, ZO0595005950\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0310403104, ZO0595005950\\",\\"45.969\\",\\"45.969\\",2,2,order,robert +KQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Boris,Boris,\\"Boris Little\\",\\"Boris Little\\",MALE,36,Little,Little,\\"(empty)\\",Saturday,5,\\"boris@little-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563442,\\"sold_product_563442_23887, sold_product_563442_17436\\",\\"sold_product_563442_23887, sold_product_563442_17436\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"27, 5.391\\",\\"60, 10.992\\",\\"23,887, 17,436\\",\\"Casual lace-ups - blue, Print T-shirt - white/orange\\",\\"Casual lace-ups - blue, Print T-shirt - white/orange\\",\\"1, 1\\",\\"ZO0394303943, ZO0556305563\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0394303943, ZO0556305563\\",71,71,2,2,order,boris +qwMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Valdez\\",\\"Samir Valdez\\",MALE,34,Valdez,Valdez,\\"(empty)\\",Saturday,5,\\"samir@valdez-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563775,\\"sold_product_563775_16063, sold_product_563775_12691\\",\\"sold_product_563775_16063, sold_product_563775_12691\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"6.469, 11.75\\",\\"11.992, 24.984\\",\\"16,063, 12,691\\",\\"Long sleeved top - tan, Windbreaker - Cornflower Blue\\",\\"Long sleeved top - tan, Windbreaker - Cornflower Blue\\",\\"1, 1\\",\\"ZO0562805628, ZO0622806228\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0562805628, ZO0622806228\\",\\"36.969\\",\\"36.969\\",2,2,order,samir +rAMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Cross\\",\\"Samir Cross\\",MALE,34,Cross,Cross,\\"(empty)\\",Saturday,5,\\"samir@cross-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563813,\\"sold_product_563813_20520, sold_product_563813_19613\\",\\"sold_product_563813_20520, sold_product_563813_19613\\",\\"14.992, 50\\",\\"14.992, 50\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"7.352, 25.484\\",\\"14.992, 50\\",\\"20,520, 19,613\\",\\"Print T-shirt - bright white, Summer jacket - black\\",\\"Print T-shirt - bright white, Summer jacket - black\\",\\"1, 1\\",\\"ZO0120001200, ZO0286602866\\",\\"0, 0\\",\\"14.992, 50\\",\\"14.992, 50\\",\\"0, 0\\",\\"ZO0120001200, ZO0286602866\\",65,65,2,2,order,samir +NgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Marwan,Marwan,\\"Marwan Reyes\\",\\"Marwan Reyes\\",MALE,51,Reyes,Reyes,\\"(empty)\\",Saturday,5,\\"marwan@reyes-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563250,\\"sold_product_563250_18528, sold_product_563250_12730\\",\\"sold_product_563250_18528, sold_product_563250_12730\\",\\"10.992, 75\\",\\"10.992, 75\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.281, 38.25\\",\\"10.992, 75\\",\\"18,528, 12,730\\",\\"Print T-shirt - black, Crossover Strap Bag\\",\\"Print T-shirt - black, Crossover Strap Bag\\",\\"1, 1\\",\\"ZO0557805578, ZO0463904639\\",\\"0, 0\\",\\"10.992, 75\\",\\"10.992, 75\\",\\"0, 0\\",\\"ZO0557805578, ZO0463904639\\",86,86,2,2,order,marwan +NwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Gilbert\\",\\"Pia Gilbert\\",FEMALE,45,Gilbert,Gilbert,\\"(empty)\\",Saturday,5,\\"pia@gilbert-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563282,\\"sold_product_563282_19216, sold_product_563282_16990\\",\\"sold_product_563282_19216, sold_product_563282_16990\\",\\"25.984, 20.984\\",\\"25.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"13.25, 9.656\\",\\"25.984, 20.984\\",\\"19,216, 16,990\\",\\"SET - Pyjamas - black/light pink, Shirt - white/blue\\",\\"SET - Pyjamas - black/light pink, Shirt - white/blue\\",\\"1, 1\\",\\"ZO0100701007, ZO0651106511\\",\\"0, 0\\",\\"25.984, 20.984\\",\\"25.984, 20.984\\",\\"0, 0\\",\\"ZO0100701007, ZO0651106511\\",\\"46.969\\",\\"46.969\\",2,2,order,pia +bQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Washington\\",\\"Tariq Washington\\",MALE,25,Washington,Washington,\\"(empty)\\",Saturday,5,\\"tariq@washington-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563392,\\"sold_product_563392_12047, sold_product_563392_17700\\",\\"sold_product_563392_12047, sold_product_563392_17700\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.289, 9\\",\\"20.984, 16.984\\",\\"12,047, 17,700\\",\\"Tracksuit bottoms - dark red, Belt - black\\",\\"Tracksuit bottoms - dark red, Belt - black\\",\\"1, 1\\",\\"ZO0525405254, ZO0310203102\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0525405254, ZO0310203102\\",\\"37.969\\",\\"37.969\\",2,2,order,tariq +kgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Martin\\",\\"Brigitte Martin\\",FEMALE,12,Martin,Martin,\\"(empty)\\",Saturday,5,\\"brigitte@martin-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563697,\\"sold_product_563697_15646, sold_product_563697_21369\\",\\"sold_product_563697_15646, sold_product_563697_21369\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"9.867, 5.602\\",\\"20.984, 10.992\\",\\"15,646, 21,369\\",\\"Jumper - off-white, Ballet pumps - yellow\\",\\"Jumper - off-white, Ballet pumps - yellow\\",\\"1, 1\\",\\"ZO0264702647, ZO0000700007\\",\\"0, 0\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"0, 0\\",\\"ZO0264702647, ZO0000700007\\",\\"31.984\\",\\"31.984\\",2,2,order,brigitte +lwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Williams\\",\\"Phil Williams\\",MALE,50,Williams,Williams,\\"(empty)\\",Saturday,5,\\"phil@williams-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563246,\\"sold_product_563246_17897, sold_product_563246_20203\\",\\"sold_product_563246_17897, sold_product_563246_20203\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.703, 14.781\\",\\"20.984, 28.984\\",\\"17,897, 20,203\\",\\"Trainers - grey, Sweatshirt - black\\",\\"Trainers - grey, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0515205152, ZO0300803008\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0515205152, ZO0300803008\\",\\"49.969\\",\\"49.969\\",2,2,order,phil +2gMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Garza\\",\\"Wilhemina St. Garza\\",FEMALE,17,Garza,Garza,\\"(empty)\\",Saturday,5,\\"wilhemina st.@garza-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562934,\\"sold_product_562934_5758, sold_product_562934_18453\\",\\"sold_product_562934_5758, sold_product_562934_18453\\",\\"75, 85\\",\\"75, 85\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"33.75, 40.813\\",\\"75, 85\\",\\"5,758, 18,453\\",\\"Ankle boots - cognac, High heeled ankle boots - black\\",\\"Ankle boots - cognac, High heeled ankle boots - black\\",\\"1, 1\\",\\"ZO0674206742, ZO0326303263\\",\\"0, 0\\",\\"75, 85\\",\\"75, 85\\",\\"0, 0\\",\\"ZO0674206742, ZO0326303263\\",160,160,2,2,order,wilhemina +2wMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Yuri,Yuri,\\"Yuri Burton\\",\\"Yuri Burton\\",MALE,21,Burton,Burton,\\"(empty)\\",Saturday,5,\\"yuri@burton-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Microlutions, Angeldale\\",\\"Microlutions, Angeldale\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562994,\\"sold_product_562994_12714, sold_product_562994_21404\\",\\"sold_product_562994_12714, sold_product_562994_21404\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Angeldale\\",\\"Microlutions, Angeldale\\",\\"40.813, 6.352\\",\\"85, 11.992\\",\\"12,714, 21,404\\",\\"Classic coat - black, Wallet - brown\\",\\"Classic coat - black, Wallet - brown\\",\\"1, 1\\",\\"ZO0115801158, ZO0701507015\\",\\"0, 0\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"0, 0\\",\\"ZO0115801158, ZO0701507015\\",97,97,2,2,order,yuri +3gMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,rania,rania,\\"rania James\\",\\"rania James\\",FEMALE,24,James,James,\\"(empty)\\",Saturday,5,\\"rania@james-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563317,\\"sold_product_563317_12022, sold_product_563317_12978\\",\\"sold_product_563317_12022, sold_product_563317_12978\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.762, 5.172\\",\\"11.992, 10.992\\",\\"12,022, 12,978\\",\\"T-Shirt - blue, Scarf - offwhite/black\\",\\"T-Shirt - blue, Scarf - offwhite/black\\",\\"1, 1\\",\\"ZO0631706317, ZO0192701927\\",\\"0, 0\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"0, 0\\",\\"ZO0631706317, ZO0192701927\\",\\"22.984\\",\\"22.984\\",2,2,order,rani +3wMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Webb\\",\\"Eddie Webb\\",MALE,38,Webb,Webb,\\"(empty)\\",Saturday,5,\\"eddie@webb-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563341,\\"sold_product_563341_18784, sold_product_563341_16207\\",\\"sold_product_563341_18784, sold_product_563341_16207\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"29.406, 5.82\\",\\"60, 10.992\\",\\"18,784, 16,207\\",\\"Smart slip-ons - blue, Bow tie - black\\",\\"Smart slip-ons - blue, Bow tie - black\\",\\"1, 1\\",\\"ZO0397303973, ZO0410304103\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0397303973, ZO0410304103\\",71,71,2,2,order,eddie +CgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Turner\\",\\"Gwen Turner\\",FEMALE,26,Turner,Turner,\\"(empty)\\",Saturday,5,\\"gwen@turner-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Gnomehouse, Pyramidustries active\\",\\"Gnomehouse, Pyramidustries active\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563622,\\"sold_product_563622_19912, sold_product_563622_10691\\",\\"sold_product_563622_19912, sold_product_563622_10691\\",\\"37, 13.992\\",\\"37, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries active\\",\\"Gnomehouse, Pyramidustries active\\",\\"17.016, 6.719\\",\\"37, 13.992\\",\\"19,912, 10,691\\",\\"A-line skirt - june bug, 3/4 sports trousers - magnet \\",\\"A-line skirt - june bug, 3/4 sports trousers - magnet \\",\\"1, 1\\",\\"ZO0328103281, ZO0224602246\\",\\"0, 0\\",\\"37, 13.992\\",\\"37, 13.992\\",\\"0, 0\\",\\"ZO0328103281, ZO0224602246\\",\\"50.969\\",\\"50.969\\",2,2,order,gwen +CwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Boone\\",\\"Abdulraheem Al Boone\\",MALE,33,Boone,Boone,\\"(empty)\\",Saturday,5,\\"abdulraheem al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563666,\\"sold_product_563666_1967, sold_product_563666_15695\\",\\"sold_product_563666_1967, sold_product_563666_15695\\",\\"65, 33\\",\\"65, 33\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"34.438, 15.18\\",\\"65, 33\\",\\"1,967, 15,695\\",\\"Lace-ups - cognac, Watch - gunmetal\\",\\"Lace-ups - cognac, Watch - gunmetal\\",\\"1, 1\\",\\"ZO0390903909, ZO0126801268\\",\\"0, 0\\",\\"65, 33\\",\\"65, 33\\",\\"0, 0\\",\\"ZO0390903909, ZO0126801268\\",98,98,2,2,order,abdulraheem +DgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Clayton\\",\\"Mostafa Clayton\\",MALE,9,Clayton,Clayton,\\"(empty)\\",Saturday,5,\\"mostafa@clayton-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563026,\\"sold_product_563026_18853, sold_product_563026_17728\\",\\"sold_product_563026_18853, sold_product_563026_17728\\",\\"85, 60\\",\\"85, 60\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"40.813, 32.375\\",\\"85, 60\\",\\"18,853, 17,728\\",\\"Tote bag - black , Suit jacket - navy\\",\\"Tote bag - black , Suit jacket - navy\\",\\"1, 1\\",\\"ZO0703407034, ZO0275102751\\",\\"0, 0\\",\\"85, 60\\",\\"85, 60\\",\\"0, 0\\",\\"ZO0703407034, ZO0275102751\\",145,145,2,2,order,mostafa +DwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Marshall\\",\\"Brigitte Marshall\\",FEMALE,12,Marshall,Marshall,\\"(empty)\\",Saturday,5,\\"brigitte@marshall-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Gnomehouse,Gnomehouse,\\"Jun 21, 2019 @ 00:00:00.000\\",563084,\\"sold_product_563084_23929, sold_product_563084_13484\\",\\"sold_product_563084_23929, sold_product_563084_13484\\",\\"65, 42\\",\\"65, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"29.906, 19.313\\",\\"65, 42\\",\\"23,929, 13,484\\",\\"Summer dress - black, Summer dress - pastel blue\\",\\"Summer dress - black, Summer dress - pastel blue\\",\\"1, 1\\",\\"ZO0338803388, ZO0334203342\\",\\"0, 0\\",\\"65, 42\\",\\"65, 42\\",\\"0, 0\\",\\"ZO0338803388, ZO0334203342\\",107,107,2,2,order,brigitte +GwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Rivera\\",\\"Sonya Rivera\\",FEMALE,28,Rivera,Rivera,\\"(empty)\\",Saturday,5,\\"sonya@rivera-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562963,\\"sold_product_562963_5747, sold_product_562963_19886\\",\\"sold_product_562963_5747, sold_product_562963_19886\\",\\"28.984, 7.988\\",\\"28.984, 7.988\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"13.633, 4.391\\",\\"28.984, 7.988\\",\\"5,747, 19,886\\",\\"High heels - nude, Mini skirt - dark grey multicolor\\",\\"High heels - nude, Mini skirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0004900049, ZO0633806338\\",\\"0, 0\\",\\"28.984, 7.988\\",\\"28.984, 7.988\\",\\"0, 0\\",\\"ZO0004900049, ZO0633806338\\",\\"36.969\\",\\"36.969\\",2,2,order,sonya +HAMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Jimenez\\",\\"Yahya Jimenez\\",MALE,23,Jimenez,Jimenez,\\"(empty)\\",Saturday,5,\\"yahya@jimenez-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",563016,\\"sold_product_563016_19484, sold_product_563016_11795\\",\\"sold_product_563016_19484, sold_product_563016_11795\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"25.484, 10.289\\",\\"50, 20.984\\",\\"19,484, 11,795\\",\\"Summer jacket - khaki, Tracksuit bottoms - dark blue\\",\\"Summer jacket - khaki, Tracksuit bottoms - dark blue\\",\\"1, 1\\",\\"ZO0539605396, ZO0525505255\\",\\"0, 0\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"0, 0\\",\\"ZO0539605396, ZO0525505255\\",71,71,2,2,order,yahya +HgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Walters\\",\\"Diane Walters\\",FEMALE,22,Walters,Walters,\\"(empty)\\",Saturday,5,\\"diane@walters-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Spherecords\\",\\"Low Tide Media, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562598,\\"sold_product_562598_5045, sold_product_562598_18398\\",\\"sold_product_562598_5045, sold_product_562598_18398\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spherecords\\",\\"Low Tide Media, Spherecords\\",\\"30.594, 5.391\\",\\"60, 10.992\\",\\"5,045, 18,398\\",\\"Boots - black, Vest - black\\",\\"Boots - black, Vest - black\\",\\"1, 1\\",\\"ZO0383203832, ZO0642806428\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0383203832, ZO0642806428\\",71,71,2,2,order,diane +HwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Underwood\\",\\"Brigitte Underwood\\",FEMALE,12,Underwood,Underwood,\\"(empty)\\",Saturday,5,\\"brigitte@underwood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563336,\\"sold_product_563336_19599, sold_product_563336_21032\\",\\"sold_product_563336_19599, sold_product_563336_21032\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"25.484, 15.648\\",\\"50, 28.984\\",\\"19,599, 21,032\\",\\"Maxi dress - Pale Violet Red, Lace-ups - black\\",\\"Maxi dress - Pale Violet Red, Lace-ups - black\\",\\"1, 1\\",\\"ZO0332903329, ZO0008300083\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0332903329, ZO0008300083\\",79,79,2,2,order,brigitte +bAMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Roberson\\",\\"Wagdi Roberson\\",MALE,15,Roberson,Roberson,\\"(empty)\\",Saturday,5,\\"wagdi@roberson-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563558,\\"sold_product_563558_21248, sold_product_563558_15382\\",\\"sold_product_563558_21248, sold_product_563558_15382\\",\\"27.984, 37\\",\\"27.984, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"13.992, 19.594\\",\\"27.984, 37\\",\\"21,248, 15,382\\",\\"Windbreaker - navy blazer, Tracksuit top - mottled grey\\",\\"Windbreaker - navy blazer, Tracksuit top - mottled grey\\",\\"1, 1\\",\\"ZO0622706227, ZO0584505845\\",\\"0, 0\\",\\"27.984, 37\\",\\"27.984, 37\\",\\"0, 0\\",\\"ZO0622706227, ZO0584505845\\",65,65,2,2,order,wagdi +cwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Holland\\",\\"Tariq Holland\\",MALE,25,Holland,Holland,\\"(empty)\\",Saturday,5,\\"tariq@holland-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Oceanavigations, Microlutions\\",\\"Oceanavigations, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563150,\\"sold_product_563150_12819, sold_product_563150_19994\\",\\"sold_product_563150_12819, sold_product_563150_19994\\",\\"24.984, 6.988\\",\\"24.984, 6.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Microlutions\\",\\"Oceanavigations, Microlutions\\",\\"11.25, 3.631\\",\\"24.984, 6.988\\",\\"12,819, 19,994\\",\\"Chinos - dark green, STAY TRUE 2 PACK - Socks - white/grey/black\\",\\"Chinos - dark green, STAY TRUE 2 PACK - Socks - white/grey/black\\",\\"1, 1\\",\\"ZO0281802818, ZO0130201302\\",\\"0, 0\\",\\"24.984, 6.988\\",\\"24.984, 6.988\\",\\"0, 0\\",\\"ZO0281802818, ZO0130201302\\",\\"31.984\\",\\"31.984\\",2,2,order,tariq +eQMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Smith\\",\\"Wilhemina St. Smith\\",FEMALE,17,Smith,Smith,\\"(empty)\\",Saturday,5,\\"wilhemina st.@smith-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Oceanavigations, Pyramidustries\\",\\"Tigress Enterprises, Oceanavigations, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",728845,\\"sold_product_728845_11691, sold_product_728845_23205, sold_product_728845_14170, sold_product_728845_8257\\",\\"sold_product_728845_11691, sold_product_728845_23205, sold_product_728845_14170, sold_product_728845_8257\\",\\"24.984, 65, 28.984, 13.992\\",\\"24.984, 65, 28.984, 13.992\\",\\"Women's Clothing, Women's Accessories, Women's Accessories, Women's Clothing\\",\\"Women's Clothing, Women's Accessories, Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Pyramidustries\\",\\"13.492, 32.5, 13.047, 7.41\\",\\"24.984, 65, 28.984, 13.992\\",\\"11,691, 23,205, 14,170, 8,257\\",\\"Cape - grey multicolor, Handbag - black, Handbag - brown, Print T-shirt - dark grey\\",\\"Cape - grey multicolor, Handbag - black, Handbag - brown, Print T-shirt - dark grey\\",\\"1, 1, 1, 1\\",\\"ZO0082300823, ZO0306203062, ZO0094600946, ZO0158901589\\",\\"0, 0, 0, 0\\",\\"24.984, 65, 28.984, 13.992\\",\\"24.984, 65, 28.984, 13.992\\",\\"0, 0, 0, 0\\",\\"ZO0082300823, ZO0306203062, ZO0094600946, ZO0158901589\\",133,133,4,4,order,wilhemina +lQMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Craig\\",\\"Abd Craig\\",MALE,52,Craig,Craig,\\"(empty)\\",Saturday,5,\\"abd@craig-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562723,\\"sold_product_562723_15183, sold_product_562723_15983\\",\\"sold_product_562723_15183, sold_product_562723_15983\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"16.5, 11.25\\",\\"33, 24.984\\",\\"15,183, 15,983\\",\\"Shirt - blue/off white, Shirt - grey/white\\",\\"Shirt - blue/off white, Shirt - grey/white\\",\\"1, 1\\",\\"ZO0109901099, ZO0277802778\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0109901099, ZO0277802778\\",\\"57.969\\",\\"57.969\\",2,2,order,abd +lgMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Mullins\\",\\"Oliver Mullins\\",MALE,7,Mullins,Mullins,\\"(empty)\\",Saturday,5,\\"oliver@mullins-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562745,\\"sold_product_562745_12209, sold_product_562745_15674\\",\\"sold_product_562745_12209, sold_product_562745_15674\\",\\"22.984, 28.984\\",\\"22.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"11.953, 14.211\\",\\"22.984, 28.984\\",\\"12,209, 15,674\\",\\"Hoodie - black/olive, Sweatshirt - black\\",\\"Hoodie - black/olive, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0541905419, ZO0628306283\\",\\"0, 0\\",\\"22.984, 28.984\\",\\"22.984, 28.984\\",\\"0, 0\\",\\"ZO0541905419, ZO0628306283\\",\\"51.969\\",\\"51.969\\",2,2,order,oliver +lwMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Perry\\",\\"Robbie Perry\\",MALE,48,Perry,Perry,\\"(empty)\\",Saturday,5,\\"robbie@perry-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562763,\\"sold_product_562763_3029, sold_product_562763_23796\\",\\"sold_product_562763_3029, sold_product_562763_23796\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"22.5, 10.063\\",\\"50, 18.984\\",\\"3,029, 23,796\\",\\"Light jacket - dark blue, Long sleeved top - mid grey multicolor\\",\\"Light jacket - dark blue, Long sleeved top - mid grey multicolor\\",\\"1, 1\\",\\"ZO0428604286, ZO0119601196\\",\\"0, 0\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"0, 0\\",\\"ZO0428604286, ZO0119601196\\",69,69,2,2,order,robbie +yAMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Mostafa,Mostafa,\\"Mostafa Graham\\",\\"Mostafa Graham\\",MALE,9,Graham,Graham,\\"(empty)\\",Saturday,5,\\"mostafa@graham-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563604,\\"sold_product_563604_11391, sold_product_563604_13058\\",\\"sold_product_563604_11391, sold_product_563604_13058\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"9, 28.203\\",\\"16.984, 60\\",\\"11,391, 13,058\\",\\"Sweatshirt - mottled grey, Lace-ups - Midnight Blue\\",\\"Sweatshirt - mottled grey, Lace-ups - Midnight Blue\\",\\"1, 1\\",\\"ZO0588005880, ZO0388703887\\",\\"0, 0\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"0, 0\\",\\"ZO0588005880, ZO0388703887\\",77,77,2,2,order,mostafa +7AMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Mckenzie\\",\\"Elyssa Mckenzie\\",FEMALE,27,Mckenzie,Mckenzie,\\"(empty)\\",Saturday,5,\\"elyssa@mckenzie-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563867,\\"sold_product_563867_15363, sold_product_563867_23604\\",\\"sold_product_563867_15363, sold_product_563867_23604\\",\\"20.984, 13.992\\",\\"20.984, 13.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.289, 6.719\\",\\"20.984, 13.992\\",\\"15,363, 23,604\\",\\"Across body bag - red , Across body bag - rose\\",\\"Across body bag - red , Across body bag - rose\\",\\"1, 1\\",\\"ZO0097300973, ZO0196301963\\",\\"0, 0\\",\\"20.984, 13.992\\",\\"20.984, 13.992\\",\\"0, 0\\",\\"ZO0097300973, ZO0196301963\\",\\"34.969\\",\\"34.969\\",2,2,order,elyssa +AQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Valdez\\",\\"Clarice Valdez\\",FEMALE,18,Valdez,Valdez,\\"(empty)\\",Saturday,5,\\"clarice@valdez-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563383,\\"sold_product_563383_21467, sold_product_563383_17467\\",\\"sold_product_563383_21467, sold_product_563383_17467\\",\\"60, 50\\",\\"60, 50\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"32.375, 26.484\\",\\"60, 50\\",\\"21,467, 17,467\\",\\"Lace-ups - black, Ankle boots - cognac\\",\\"Lace-ups - black, Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0369103691, ZO0378603786\\",\\"0, 0\\",\\"60, 50\\",\\"60, 50\\",\\"0, 0\\",\\"ZO0369103691, ZO0378603786\\",110,110,2,2,order,clarice +AgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Wood\\",\\"Abd Wood\\",MALE,52,Wood,Wood,\\"(empty)\\",Saturday,5,\\"abd@wood-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563218,\\"sold_product_563218_16231, sold_product_563218_18727\\",\\"sold_product_563218_16231, sold_product_563218_18727\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"9, 5.391\\",\\"16.984, 10.992\\",\\"16,231, 18,727\\",\\"Print T-shirt - bright white, Belt - cognac \\",\\"Print T-shirt - bright white, Belt - cognac \\",\\"1, 1\\",\\"ZO0120401204, ZO0598605986\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0120401204, ZO0598605986\\",\\"27.984\\",\\"27.984\\",2,2,order,abd +TAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Ramsey\\",\\"Betty Ramsey\\",FEMALE,44,Ramsey,Ramsey,\\"(empty)\\",Saturday,5,\\"betty@ramsey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563554,\\"sold_product_563554_15671, sold_product_563554_13795\\",\\"sold_product_563554_15671, sold_product_563554_13795\\",\\"70, 33\\",\\"70, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"31.5, 16.5\\",\\"70, 33\\",\\"15,671, 13,795\\",\\"Ankle boots - taupe, Trousers - navy\\",\\"Ankle boots - taupe, Trousers - navy\\",\\"1, 1\\",\\"ZO0246502465, ZO0032100321\\",\\"0, 0\\",\\"70, 33\\",\\"70, 33\\",\\"0, 0\\",\\"ZO0246502465, ZO0032100321\\",103,103,2,2,order,betty +wAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Long\\",\\"rania Long\\",FEMALE,24,Long,Long,\\"(empty)\\",Saturday,5,\\"rania@long-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563023,\\"sold_product_563023_24484, sold_product_563023_21752\\",\\"sold_product_563023_24484, sold_product_563023_21752\\",\\"12.992, 13.992\\",\\"12.992, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"6.879, 6.301\\",\\"12.992, 13.992\\",\\"24,484, 21,752\\",\\"Print T-shirt - black, Pencil skirt - dark grey multicolor\\",\\"Print T-shirt - black, Pencil skirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0055100551, ZO0149701497\\",\\"0, 0\\",\\"12.992, 13.992\\",\\"12.992, 13.992\\",\\"0, 0\\",\\"ZO0055100551, ZO0149701497\\",\\"26.984\\",\\"26.984\\",2,2,order,rani +wQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Betty,Betty,\\"Betty Webb\\",\\"Betty Webb\\",FEMALE,44,Webb,Webb,\\"(empty)\\",Saturday,5,\\"betty@webb-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563060,\\"sold_product_563060_22520, sold_product_563060_22874\\",\\"sold_product_563060_22520, sold_product_563060_22874\\",\\"42, 42\\",\\"42, 42\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"22.672, 22.672\\",\\"42, 42\\",\\"22,520, 22,874\\",\\"Summer dress - black, Across body bag - black\\",\\"Summer dress - black, Across body bag - black\\",\\"1, 1\\",\\"ZO0040600406, ZO0356503565\\",\\"0, 0\\",\\"42, 42\\",\\"42, 42\\",\\"0, 0\\",\\"ZO0040600406, ZO0356503565\\",84,84,2,2,order,betty +wgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Phil,Phil,\\"Phil Hudson\\",\\"Phil Hudson\\",MALE,50,Hudson,Hudson,\\"(empty)\\",Saturday,5,\\"phil@hudson-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563108,\\"sold_product_563108_13510, sold_product_563108_11051\\",\\"sold_product_563108_13510, sold_product_563108_11051\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"25.484, 13.344\\",\\"50, 28.984\\",\\"13,510, 11,051\\",\\"Waistcoat - dark blue, Across body bag - brown/brown\\",\\"Waistcoat - dark blue, Across body bag - brown/brown\\",\\"1, 1\\",\\"ZO0429604296, ZO0465204652\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0429604296, ZO0465204652\\",79,79,2,2,order,phil +hAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Richards\\",\\"Selena Richards\\",FEMALE,42,Richards,Richards,\\"(empty)\\",Saturday,5,\\"selena@richards-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563778,\\"sold_product_563778_15546, sold_product_563778_11477\\",\\"sold_product_563778_15546, sold_product_563778_11477\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"8.328, 11.25\\",\\"16.984, 24.984\\",\\"15,546, 11,477\\",\\"Sweatshirt - coral, Across body bag - cognac\\",\\"Sweatshirt - coral, Across body bag - cognac\\",\\"1, 1\\",\\"ZO0656606566, ZO0186001860\\",\\"0, 0\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"0, 0\\",\\"ZO0656606566, ZO0186001860\\",\\"41.969\\",\\"41.969\\",2,2,order,selena +xwMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Cortez\\",\\"Gwen Cortez\\",FEMALE,26,Cortez,Cortez,\\"(empty)\\",Saturday,5,\\"gwen@cortez-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562705,\\"sold_product_562705_12529, sold_product_562705_22843\\",\\"sold_product_562705_12529, sold_product_562705_22843\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"5.398, 12\\",\\"11.992, 24.984\\",\\"12,529, 22,843\\",\\"Jumpsuit - black, Shirt - black denim\\",\\"Jumpsuit - black, Shirt - black denim\\",\\"1, 1\\",\\"ZO0633106331, ZO0495904959\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0633106331, ZO0495904959\\",\\"36.969\\",\\"36.969\\",2,2,order,gwen +yAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Sutton\\",\\"Phil Sutton\\",MALE,50,Sutton,Sutton,\\"(empty)\\",Saturday,5,\\"phil@sutton-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563639,\\"sold_product_563639_24934, sold_product_563639_3499\\",\\"sold_product_563639_24934, sold_product_563639_3499\\",\\"50, 60\\",\\"50, 60\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"22.5, 28.203\\",\\"50, 60\\",\\"24,934, 3,499\\",\\"Lace-up boots - resin coffee, Hardshell jacket - jet black\\",\\"Lace-up boots - resin coffee, Hardshell jacket - jet black\\",\\"1, 1\\",\\"ZO0403504035, ZO0623006230\\",\\"0, 0\\",\\"50, 60\\",\\"50, 60\\",\\"0, 0\\",\\"ZO0403504035, ZO0623006230\\",110,110,2,2,order,phil +yQMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Yasmine,Yasmine,\\"Yasmine Mcdonald\\",\\"Yasmine Mcdonald\\",FEMALE,43,Mcdonald,Mcdonald,\\"(empty)\\",Saturday,5,\\"yasmine@mcdonald-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563698,\\"sold_product_563698_23206, sold_product_563698_15645\\",\\"sold_product_563698_23206, sold_product_563698_15645\\",\\"33, 11.992\\",\\"33, 11.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"15.844, 6.109\\",\\"33, 11.992\\",\\"23,206, 15,645\\",\\"Cardigan - greymulticolor/black, Scarf - green\\",\\"Cardigan - greymulticolor/black, Scarf - green\\",\\"1, 1\\",\\"ZO0070800708, ZO0084100841\\",\\"0, 0\\",\\"33, 11.992\\",\\"33, 11.992\\",\\"0, 0\\",\\"ZO0070800708, ZO0084100841\\",\\"44.969\\",\\"44.969\\",2,2,order,yasmine +MwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Banks\\",\\"Abd Banks\\",MALE,52,Banks,Banks,\\"(empty)\\",Saturday,5,\\"abd@banks-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations, Microlutions\\",\\"Elitelligence, Oceanavigations, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",714638,\\"sold_product_714638_14544, sold_product_714638_19885, sold_product_714638_13083, sold_product_714638_17585\\",\\"sold_product_714638_14544, sold_product_714638_19885, sold_product_714638_13083, sold_product_714638_17585\\",\\"28.984, 10.992, 24.984, 33\\",\\"28.984, 10.992, 24.984, 33\\",\\"Men's Clothing, Men's Accessories, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Oceanavigations, Microlutions\\",\\"Elitelligence, Elitelligence, Oceanavigations, Microlutions\\",\\"13.633, 5.93, 12.25, 17.484\\",\\"28.984, 10.992, 24.984, 33\\",\\"14,544, 19,885, 13,083, 17,585\\",\\"Jumper - black, Wallet - grey/cognac, Chinos - sand, Shirt - black denim\\",\\"Jumper - black, Wallet - grey/cognac, Chinos - sand, Shirt - black denim\\",\\"1, 1, 1, 1\\",\\"ZO0576205762, ZO0602006020, ZO0281502815, ZO0111001110\\",\\"0, 0, 0, 0\\",\\"28.984, 10.992, 24.984, 33\\",\\"28.984, 10.992, 24.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0576205762, ZO0602006020, ZO0281502815, ZO0111001110\\",\\"97.938\\",\\"97.938\\",4,4,order,abd +bAMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Lloyd\\",\\"Mostafa Lloyd\\",MALE,9,Lloyd,Lloyd,\\"(empty)\\",Saturday,5,\\"mostafa@lloyd-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563602,\\"sold_product_563602_11928, sold_product_563602_13191\\",\\"sold_product_563602_11928, sold_product_563602_13191\\",\\"22.984, 50\\",\\"22.984, 50\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"11.039, 25.984\\",\\"22.984, 50\\",\\"11,928, 13,191\\",\\"Casual lace-ups - black, SOLID - Summer jacket - royal blue\\",\\"Casual lace-ups - black, SOLID - Summer jacket - royal blue\\",\\"1, 1\\",\\"ZO0508705087, ZO0427804278\\",\\"0, 0\\",\\"22.984, 50\\",\\"22.984, 50\\",\\"0, 0\\",\\"ZO0508705087, ZO0427804278\\",73,73,2,2,order,mostafa +8gMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Munoz\\",\\"Sultan Al Munoz\\",MALE,19,Munoz,Munoz,\\"(empty)\\",Saturday,5,\\"sultan al@munoz-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563054,\\"sold_product_563054_11706, sold_product_563054_13408\\",\\"sold_product_563054_11706, sold_product_563054_13408\\",\\"100, 50\\",\\"100, 50\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"49, 23\\",\\"100, 50\\",\\"11,706, 13,408\\",\\"Weekend bag - dark brown, Cowboy/Biker boots - dark brown/tan\\",\\"Weekend bag - dark brown, Cowboy/Biker boots - dark brown/tan\\",\\"1, 1\\",\\"ZO0701907019, ZO0519405194\\",\\"0, 0\\",\\"100, 50\\",\\"100, 50\\",\\"0, 0\\",\\"ZO0701907019, ZO0519405194\\",150,150,2,2,order,sultan +8wMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Shaw\\",\\"Abd Shaw\\",MALE,52,Shaw,Shaw,\\"(empty)\\",Saturday,5,\\"abd@shaw-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563093,\\"sold_product_563093_18385, sold_product_563093_16783\\",\\"sold_product_563093_18385, sold_product_563093_16783\\",\\"7.988, 42\\",\\"7.988, 42\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"4.07, 20.156\\",\\"7.988, 42\\",\\"18,385, 16,783\\",\\"Basic T-shirt - dark grey multicolor, Weekend bag - black\\",\\"Basic T-shirt - dark grey multicolor, Weekend bag - black\\",\\"1, 1\\",\\"ZO0435004350, ZO0472104721\\",\\"0, 0\\",\\"7.988, 42\\",\\"7.988, 42\\",\\"0, 0\\",\\"ZO0435004350, ZO0472104721\\",\\"49.969\\",\\"49.969\\",2,2,order,abd +IQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Ryan\\",\\"Pia Ryan\\",FEMALE,45,Ryan,Ryan,\\"(empty)\\",Saturday,5,\\"pia@ryan-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562875,\\"sold_product_562875_19166, sold_product_562875_21969\\",\\"sold_product_562875_19166, sold_product_562875_21969\\",\\"60, 7.988\\",\\"60, 7.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"29.406, 3.68\\",\\"60, 7.988\\",\\"19,166, 21,969\\",\\"Cardigan - camel, Vest - bordeaux\\",\\"Cardigan - camel, Vest - bordeaux\\",\\"1, 1\\",\\"ZO0353003530, ZO0637006370\\",\\"0, 0\\",\\"60, 7.988\\",\\"60, 7.988\\",\\"0, 0\\",\\"ZO0353003530, ZO0637006370\\",68,68,2,2,order,pia +IgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Brigitte,Brigitte,\\"Brigitte Holland\\",\\"Brigitte Holland\\",FEMALE,12,Holland,Holland,\\"(empty)\\",Saturday,5,\\"brigitte@holland-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Primemaster, Pyramidustries\\",\\"Primemaster, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562914,\\"sold_product_562914_16495, sold_product_562914_16949\\",\\"sold_product_562914_16495, sold_product_562914_16949\\",\\"75, 13.992\\",\\"75, 13.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Pyramidustries\\",\\"Primemaster, Pyramidustries\\",\\"39.75, 6.859\\",\\"75, 13.992\\",\\"16,495, 16,949\\",\\"Sandals - nuvola, Scarf - bordeaux/mustard\\",\\"Sandals - nuvola, Scarf - bordeaux/mustard\\",\\"1, 1\\",\\"ZO0360503605, ZO0194501945\\",\\"0, 0\\",\\"75, 13.992\\",\\"75, 13.992\\",\\"0, 0\\",\\"ZO0360503605, ZO0194501945\\",89,89,2,2,order,brigitte +IwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Bailey\\",\\"Brigitte Bailey\\",FEMALE,12,Bailey,Bailey,\\"(empty)\\",Saturday,5,\\"brigitte@bailey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562654,\\"sold_product_562654_13316, sold_product_562654_13303\\",\\"sold_product_562654_13316, sold_product_562654_13303\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"12, 5.602\\",\\"24.984, 10.992\\",\\"13,316, 13,303\\",\\"Blouse - black, Print T-shirt - white\\",\\"Blouse - black, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0065400654, ZO0158701587\\",\\"0, 0\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"0, 0\\",\\"ZO0065400654, ZO0158701587\\",\\"35.969\\",\\"35.969\\",2,2,order,brigitte +JQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Massey\\",\\"Betty Massey\\",FEMALE,44,Massey,Massey,\\"(empty)\\",Saturday,5,\\"betty@massey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563860,\\"sold_product_563860_17204, sold_product_563860_5970\\",\\"sold_product_563860_17204, sold_product_563860_5970\\",\\"33, 33\\",\\"33, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"17.156, 15.844\\",\\"33, 33\\",\\"17,204, 5,970\\",\\"Blouse - potent purple, Wedge boots - toffee\\",\\"Blouse - potent purple, Wedge boots - toffee\\",\\"1, 1\\",\\"ZO0344703447, ZO0031000310\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0344703447, ZO0031000310\\",66,66,2,2,order,betty +JgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Rivera\\",\\"Yasmine Rivera\\",FEMALE,43,Rivera,Rivera,\\"(empty)\\",Saturday,5,\\"yasmine@rivera-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563907,\\"sold_product_563907_11709, sold_product_563907_20859\\",\\"sold_product_563907_11709, sold_product_563907_20859\\",\\"20.984, 18.984\\",\\"20.984, 18.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"11.328, 10.063\\",\\"20.984, 18.984\\",\\"11,709, 20,859\\",\\"Jersey dress - black, Long sleeved top - navy\\",\\"Jersey dress - black, Long sleeved top - navy\\",\\"1, 1\\",\\"ZO0036700367, ZO0054300543\\",\\"0, 0\\",\\"20.984, 18.984\\",\\"20.984, 18.984\\",\\"0, 0\\",\\"ZO0036700367, ZO0054300543\\",\\"39.969\\",\\"39.969\\",2,2,order,yasmine +QQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Youssef,Youssef,\\"Youssef Conner\\",\\"Youssef Conner\\",MALE,31,Conner,Conner,\\"(empty)\\",Saturday,5,\\"youssef@conner-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562833,\\"sold_product_562833_21511, sold_product_562833_14742\\",\\"sold_product_562833_21511, sold_product_562833_14742\\",\\"13.992, 33\\",\\"13.992, 33\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"7.41, 15.18\\",\\"13.992, 33\\",\\"21,511, 14,742\\",\\"3 PACK - Shorts - black, Laptop bag - brown\\",\\"3 PACK - Shorts - black, Laptop bag - brown\\",\\"1, 1\\",\\"ZO0610806108, ZO0316803168\\",\\"0, 0\\",\\"13.992, 33\\",\\"13.992, 33\\",\\"0, 0\\",\\"ZO0610806108, ZO0316803168\\",\\"46.969\\",\\"46.969\\",2,2,order,youssef +QgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Soto\\",\\"Abd Soto\\",MALE,52,Soto,Soto,\\"(empty)\\",Saturday,5,\\"abd@soto-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562899,\\"sold_product_562899_21057, sold_product_562899_13717\\",\\"sold_product_562899_21057, sold_product_562899_13717\\",\\"13.992, 28.984\\",\\"13.992, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"6.859, 15.359\\",\\"13.992, 28.984\\",\\"21,057, 13,717\\",\\"Scarf - navy/grey, Tracksuit top - blue\\",\\"Scarf - navy/grey, Tracksuit top - blue\\",\\"1, 1\\",\\"ZO0313403134, ZO0587105871\\",\\"0, 0\\",\\"13.992, 28.984\\",\\"13.992, 28.984\\",\\"0, 0\\",\\"ZO0313403134, ZO0587105871\\",\\"42.969\\",\\"42.969\\",2,2,order,abd +QwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Soto\\",\\"Ahmed Al Soto\\",MALE,4,Soto,Soto,\\"(empty)\\",Saturday,5,\\"ahmed al@soto-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Elitelligence, Spherecords\\",\\"Elitelligence, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562665,\\"sold_product_562665_15130, sold_product_562665_14446\\",\\"sold_product_562665_15130, sold_product_562665_14446\\",\\"11.992, 8.992\\",\\"11.992, 8.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spherecords\\",\\"Elitelligence, Spherecords\\",\\"6.469, 4.578\\",\\"11.992, 8.992\\",\\"15,130, 14,446\\",\\"Long sleeved top - white, 5 PACK - Socks - dark grey\\",\\"Long sleeved top - white, 5 PACK - Socks - dark grey\\",\\"1, 1\\",\\"ZO0569205692, ZO0664006640\\",\\"0, 0\\",\\"11.992, 8.992\\",\\"11.992, 8.992\\",\\"0, 0\\",\\"ZO0569205692, ZO0664006640\\",\\"20.984\\",\\"20.984\\",2,2,order,ahmed +RwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Mostafa,Mostafa,\\"Mostafa Clayton\\",\\"Mostafa Clayton\\",MALE,9,Clayton,Clayton,\\"(empty)\\",Saturday,5,\\"mostafa@clayton-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563579,\\"sold_product_563579_12028, sold_product_563579_14742\\",\\"sold_product_563579_12028, sold_product_563579_14742\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"3.92, 15.18\\",\\"7.988, 33\\",\\"12,028, 14,742\\",\\"Vest - light blue multicolor, Laptop bag - brown\\",\\"Vest - light blue multicolor, Laptop bag - brown\\",\\"1, 1\\",\\"ZO0548905489, ZO0316803168\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0548905489, ZO0316803168\\",\\"40.969\\",\\"40.969\\",2,2,order,mostafa +SAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Chandler\\",\\"Elyssa Chandler\\",FEMALE,27,Chandler,Chandler,\\"(empty)\\",Saturday,5,\\"elyssa@chandler-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563119,\\"sold_product_563119_22794, sold_product_563119_23300\\",\\"sold_product_563119_22794, sold_product_563119_23300\\",\\"100, 35\\",\\"100, 35\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"46, 16.453\\",\\"100, 35\\",\\"22,794, 23,300\\",\\"Boots - Midnight Blue, Shift dress - black\\",\\"Boots - Midnight Blue, Shift dress - black\\",\\"1, 1\\",\\"ZO0374603746, ZO0041300413\\",\\"0, 0\\",\\"100, 35\\",\\"100, 35\\",\\"0, 0\\",\\"ZO0374603746, ZO0041300413\\",135,135,2,2,order,elyssa +SQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Women's Accessories\\",\\"Men's Accessories, Women's Accessories\\",EUR,Recip,Recip,\\"Recip Gilbert\\",\\"Recip Gilbert\\",MALE,10,Gilbert,Gilbert,\\"(empty)\\",Saturday,5,\\"recip@gilbert-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",563152,\\"sold_product_563152_22166, sold_product_563152_14897\\",\\"sold_product_563152_22166, sold_product_563152_14897\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Accessories, Women's Accessories\\",\\"Men's Accessories, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"6.469, 12.992\\",\\"11.992, 24.984\\",\\"22,166, 14,897\\",\\"Scarf - navy/turqoise, Rucksack - olive \\",\\"Scarf - navy/turqoise, Rucksack - olive \\",\\"1, 1\\",\\"ZO0603606036, ZO0608206082\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0603606036, ZO0608206082\\",\\"36.969\\",\\"36.969\\",2,2,order,recip +dwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Chandler\\",\\"Wilhemina St. Chandler\\",FEMALE,17,Chandler,Chandler,\\"(empty)\\",Saturday,5,\\"wilhemina st.@chandler-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",725079,\\"sold_product_725079_18356, sold_product_725079_16691, sold_product_725079_9233, sold_product_725079_13733\\",\\"sold_product_725079_18356, sold_product_725079_16691, sold_product_725079_9233, sold_product_725079_13733\\",\\"10.992, 20.984, 42, 14.992\\",\\"10.992, 20.984, 42, 14.992\\",\\"Women's Clothing, Women's Accessories, Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories, Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Tigress Enterprises, Tigress Enterprises, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises, Tigress Enterprises, Tigress Enterprises\\",\\"5.391, 10.492, 22.672, 7.641\\",\\"10.992, 20.984, 42, 14.992\\",\\"18,356, 16,691, 9,233, 13,733\\",\\"2 PACK - Vest - white/white, Across body bag - black, Jumper - grey multicolor, Scarf - mint\\",\\"2 PACK - Vest - white/white, Across body bag - black, Jumper - grey multicolor, Scarf - mint\\",\\"1, 1, 1, 1\\",\\"ZO0641506415, ZO0086200862, ZO0071500715, ZO0085700857\\",\\"0, 0, 0, 0\\",\\"10.992, 20.984, 42, 14.992\\",\\"10.992, 20.984, 42, 14.992\\",\\"0, 0, 0, 0\\",\\"ZO0641506415, ZO0086200862, ZO0071500715, ZO0085700857\\",\\"88.938\\",\\"88.938\\",4,4,order,wilhemina +kQMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Robbie,Robbie,\\"Robbie Harvey\\",\\"Robbie Harvey\\",MALE,48,Harvey,Harvey,\\"(empty)\\",Saturday,5,\\"robbie@harvey-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563736,\\"sold_product_563736_22302, sold_product_563736_14502\\",\\"sold_product_563736_22302, sold_product_563736_14502\\",\\"28.984, 15.992\\",\\"28.984, 15.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"13.633, 7.84\\",\\"28.984, 15.992\\",\\"22,302, 14,502\\",\\"Shirt - white, Belt - black\\",\\"Shirt - white, Belt - black\\",\\"1, 1\\",\\"ZO0415604156, ZO0461704617\\",\\"0, 0\\",\\"28.984, 15.992\\",\\"28.984, 15.992\\",\\"0, 0\\",\\"ZO0415604156, ZO0461704617\\",\\"44.969\\",\\"44.969\\",2,2,order,robbie +kgMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Bryant\\",\\"Stephanie Bryant\\",FEMALE,6,Bryant,Bryant,\\"(empty)\\",Saturday,5,\\"stephanie@bryant-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563761,\\"sold_product_563761_13657, sold_product_563761_15397\\",\\"sold_product_563761_13657, sold_product_563761_15397\\",\\"33, 42\\",\\"33, 42\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"15.844, 20.156\\",\\"33, 42\\",\\"13,657, 15,397\\",\\"Tote bag - black, A-line skirt - coronet blue\\",\\"Tote bag - black, A-line skirt - coronet blue\\",\\"1, 1\\",\\"ZO0087700877, ZO0330603306\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0087700877, ZO0330603306\\",75,75,2,2,order,stephanie +kwMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Jackson\\",\\"Gwen Jackson\\",FEMALE,26,Jackson,Jackson,\\"(empty)\\",Saturday,5,\\"gwen@jackson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563800,\\"sold_product_563800_19249, sold_product_563800_20352\\",\\"sold_product_563800_19249, sold_product_563800_20352\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"41.656, 6\\",\\"85, 11.992\\",\\"19,249, 20,352\\",\\"Handbag - black, Vest - red\\",\\"Handbag - black, Vest - red\\",\\"1, 1\\",\\"ZO0307303073, ZO0161601616\\",\\"0, 0\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"0, 0\\",\\"ZO0307303073, ZO0161601616\\",97,97,2,2,order,gwen +\\"-AMtOW0BH63Xcmy4524Z\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Austin\\",\\"Eddie Austin\\",MALE,38,Austin,Austin,\\"(empty)\\",Saturday,5,\\"eddie@austin-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Oceanavigations,Oceanavigations,\\"Jun 21, 2019 @ 00:00:00.000\\",563822,\\"sold_product_563822_13869, sold_product_563822_12632\\",\\"sold_product_563822_13869, sold_product_563822_12632\\",\\"13.992, 50\\",\\"13.992, 50\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"6.859, 26.484\\",\\"13.992, 50\\",\\"13,869, 12,632\\",\\"Tie - black, Down jacket - black\\",\\"Tie - black, Down jacket - black\\",\\"1, 1\\",\\"ZO0277402774, ZO0288502885\\",\\"0, 0\\",\\"13.992, 50\\",\\"13.992, 50\\",\\"0, 0\\",\\"ZO0277402774, ZO0288502885\\",\\"63.969\\",\\"63.969\\",2,2,order,eddie +GQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Hansen\\",\\"Oliver Hansen\\",MALE,7,Hansen,Hansen,\\"(empty)\\",Saturday,5,\\"oliver@hansen-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562948,\\"sold_product_562948_23445, sold_product_562948_17355\\",\\"sold_product_562948_23445, sold_product_562948_17355\\",\\"28.984, 7.988\\",\\"28.984, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.633, 4\\",\\"28.984, 7.988\\",\\"23,445, 17,355\\",\\"Chinos - navy, Print T-shirt - white\\",\\"Chinos - navy, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0282102821, ZO0554405544\\",\\"0, 0\\",\\"28.984, 7.988\\",\\"28.984, 7.988\\",\\"0, 0\\",\\"ZO0282102821, ZO0554405544\\",\\"36.969\\",\\"36.969\\",2,2,order,oliver +GgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Frances,Frances,\\"Frances Moran\\",\\"Frances Moran\\",FEMALE,49,Moran,Moran,\\"(empty)\\",Saturday,5,\\"frances@moran-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562993,\\"sold_product_562993_17227, sold_product_562993_17918\\",\\"sold_product_562993_17227, sold_product_562993_17918\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"27.594, 6.23\\",\\"60, 11.992\\",\\"17,227, 17,918\\",\\"Trainers - bianco, Basic T-shirt - lilac\\",\\"Trainers - bianco, Basic T-shirt - lilac\\",\\"1, 1\\",\\"ZO0255202552, ZO0560005600\\",\\"0, 0\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"0, 0\\",\\"ZO0255202552, ZO0560005600\\",72,72,2,2,order,frances +HAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Morrison\\",\\"Sonya Morrison\\",FEMALE,28,Morrison,Morrison,\\"(empty)\\",Saturday,5,\\"sonya@morrison-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562585,\\"sold_product_562585_16665, sold_product_562585_8623\\",\\"sold_product_562585_16665, sold_product_562585_8623\\",\\"20.984, 17.984\\",\\"20.984, 17.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"11.539, 8.102\\",\\"20.984, 17.984\\",\\"16,665, 8,623\\",\\"Vest - black, Long sleeved top - red ochre\\",\\"Vest - black, Long sleeved top - red ochre\\",\\"1, 1\\",\\"ZO0063800638, ZO0165301653\\",\\"0, 0\\",\\"20.984, 17.984\\",\\"20.984, 17.984\\",\\"0, 0\\",\\"ZO0063800638, ZO0165301653\\",\\"38.969\\",\\"38.969\\",2,2,order,sonya +HQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Ball\\",\\"Diane Ball\\",FEMALE,22,Ball,Ball,\\"(empty)\\",Saturday,5,\\"diane@ball-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563326,\\"sold_product_563326_22030, sold_product_563326_23066\\",\\"sold_product_563326_22030, sold_product_563326_23066\\",\\"42, 85\\",\\"42, 85\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"21.406, 44.188\\",\\"42, 85\\",\\"22,030, 23,066\\",\\"Blouse - black, Lace-up boots - black\\",\\"Blouse - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0266702667, ZO0680306803\\",\\"0, 0\\",\\"42, 85\\",\\"42, 85\\",\\"0, 0\\",\\"ZO0266702667, ZO0680306803\\",127,127,2,2,order,diane +JQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Fletcher\\",\\"Stephanie Fletcher\\",FEMALE,6,Fletcher,Fletcher,\\"(empty)\\",Saturday,5,\\"stephanie@fletcher-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563755,\\"sold_product_563755_13226, sold_product_563755_12114\\",\\"sold_product_563755_13226, sold_product_563755_12114\\",\\"16.984, 29.984\\",\\"16.984, 29.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"8.828, 16.188\\",\\"16.984, 29.984\\",\\"13,226, 12,114\\",\\"Blouse - offwhite, Jersey dress - black/white\\",\\"Blouse - offwhite, Jersey dress - black/white\\",\\"1, 1\\",\\"ZO0710707107, ZO0038300383\\",\\"0, 0\\",\\"16.984, 29.984\\",\\"16.984, 29.984\\",\\"0, 0\\",\\"ZO0710707107, ZO0038300383\\",\\"46.969\\",\\"46.969\\",2,2,order,stephanie +TwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Hopkins\\",\\"Abd Hopkins\\",MALE,52,Hopkins,Hopkins,\\"(empty)\\",Saturday,5,\\"abd@hopkins-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Oceanavigations, Spherecords\\",\\"Low Tide Media, Oceanavigations, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",715450,\\"sold_product_715450_13559, sold_product_715450_21852, sold_product_715450_16570, sold_product_715450_11336\\",\\"sold_product_715450_13559, sold_product_715450_21852, sold_product_715450_16570, sold_product_715450_11336\\",\\"13.992, 20.984, 65, 10.992\\",\\"13.992, 20.984, 65, 10.992\\",\\"Men's Clothing, Men's Accessories, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Spherecords\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Spherecords\\",\\"6.441, 10.078, 31.844, 5.059\\",\\"13.992, 20.984, 65, 10.992\\",\\"13,559, 21,852, 16,570, 11,336\\",\\"3 PACK - Shorts - light blue/dark blue/white, Wallet - brown, Boots - navy, Long sleeved top - white/black\\",\\"3 PACK - Shorts - light blue/dark blue/white, Wallet - brown, Boots - navy, Long sleeved top - white/black\\",\\"1, 1, 1, 1\\",\\"ZO0476604766, ZO0462404624, ZO0258302583, ZO0658206582\\",\\"0, 0, 0, 0\\",\\"13.992, 20.984, 65, 10.992\\",\\"13.992, 20.984, 65, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0476604766, ZO0462404624, ZO0258302583, ZO0658206582\\",\\"110.938\\",\\"110.938\\",4,4,order,abd +dgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Boone\\",\\"Abdulraheem Al Boone\\",MALE,33,Boone,Boone,\\"(empty)\\",Saturday,5,\\"abdulraheem al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",Oceanavigations,Oceanavigations,\\"Jun 21, 2019 @ 00:00:00.000\\",563181,\\"sold_product_563181_15447, sold_product_563181_19692\\",\\"sold_product_563181_15447, sold_product_563181_19692\\",\\"50, 13.992\\",\\"50, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"24.5, 6.859\\",\\"50, 13.992\\",\\"15,447, 19,692\\",\\"Suit jacket - grey, Print T-shirt - black\\",\\"Suit jacket - grey, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0274902749, ZO0293902939\\",\\"0, 0\\",\\"50, 13.992\\",\\"50, 13.992\\",\\"0, 0\\",\\"ZO0274902749, ZO0293902939\\",\\"63.969\\",\\"63.969\\",2,2,order,abdulraheem +jQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Graves\\",\\"Diane Graves\\",FEMALE,22,Graves,Graves,\\"(empty)\\",Saturday,5,\\"diane@graves-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563131,\\"sold_product_563131_15426, sold_product_563131_21432\\",\\"sold_product_563131_15426, sold_product_563131_21432\\",\\"75, 20.984\\",\\"75, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"39, 11.539\\",\\"75, 20.984\\",\\"15,426, 21,432\\",\\"Cowboy/Biker boots - black, Blouse - peacoat\\",\\"Cowboy/Biker boots - black, Blouse - peacoat\\",\\"1, 1\\",\\"ZO0326803268, ZO0059600596\\",\\"0, 0\\",\\"75, 20.984\\",\\"75, 20.984\\",\\"0, 0\\",\\"ZO0326803268, ZO0059600596\\",96,96,2,2,order,diane +0gMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Wood\\",\\"Selena Wood\\",FEMALE,42,Wood,Wood,\\"(empty)\\",Saturday,5,\\"selena@wood-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563254,\\"sold_product_563254_23719, sold_product_563254_11095\\",\\"sold_product_563254_23719, sold_product_563254_11095\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"13.922, 9.867\\",\\"28.984, 20.984\\",\\"23,719, 11,095\\",\\"Jersey dress - peacoat, Tracksuit top - pink multicolor\\",\\"Jersey dress - peacoat, Tracksuit top - pink multicolor\\",\\"1, 1\\",\\"ZO0052100521, ZO0498804988\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0052100521, ZO0498804988\\",\\"49.969\\",\\"49.969\\",2,2,order,selena +OQMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Tran\\",\\"Brigitte Tran\\",FEMALE,12,Tran,Tran,\\"(empty)\\",Saturday,5,\\"brigitte@tran-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563573,\\"sold_product_563573_22735, sold_product_563573_23822\\",\\"sold_product_563573_22735, sold_product_563573_23822\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"13.742, 32.375\\",\\"24.984, 60\\",\\"22,735, 23,822\\",\\"Platform heels - black, Sandals - Midnight Blue\\",\\"Platform heels - black, Sandals - Midnight Blue\\",\\"1, 1\\",\\"ZO0132601326, ZO0243002430\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0132601326, ZO0243002430\\",85,85,2,2,order,brigitte +VwMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Thad,Thad,\\"Thad Chapman\\",\\"Thad Chapman\\",MALE,30,Chapman,Chapman,\\"(empty)\\",Saturday,5,\\"thad@chapman-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562699,\\"sold_product_562699_24934, sold_product_562699_20799\\",\\"sold_product_562699_24934, sold_product_562699_20799\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"22.5, 7.5\\",\\"50, 14.992\\",\\"24,934, 20,799\\",\\"Lace-up boots - resin coffee, Long sleeved top - white/black\\",\\"Lace-up boots - resin coffee, Long sleeved top - white/black\\",\\"1, 1\\",\\"ZO0403504035, ZO0558905589\\",\\"0, 0\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"0, 0\\",\\"ZO0403504035, ZO0558905589\\",65,65,2,2,order,thad +WAMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Rivera\\",\\"Tariq Rivera\\",MALE,25,Rivera,Rivera,\\"(empty)\\",Saturday,5,\\"tariq@rivera-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563644,\\"sold_product_563644_20541, sold_product_563644_14121\\",\\"sold_product_563644_20541, sold_product_563644_14121\\",\\"90, 17.984\\",\\"90, 17.984\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"44.094, 9.172\\",\\"90, 17.984\\",\\"20,541, 14,121\\",\\"Laptop bag - Dark Sea Green, Watch - grey\\",\\"Laptop bag - Dark Sea Green, Watch - grey\\",\\"1, 1\\",\\"ZO0470104701, ZO0600506005\\",\\"0, 0\\",\\"90, 17.984\\",\\"90, 17.984\\",\\"0, 0\\",\\"ZO0470104701, ZO0600506005\\",108,108,2,2,order,tariq +WQMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Davidson\\",\\"Eddie Davidson\\",MALE,38,Davidson,Davidson,\\"(empty)\\",Saturday,5,\\"eddie@davidson-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563701,\\"sold_product_563701_20743, sold_product_563701_23294\\",\\"sold_product_563701_20743, sold_product_563701_23294\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.75, 15.938\\",\\"24.984, 28.984\\",\\"20,743, 23,294\\",\\"Slim fit jeans - grey, Tracksuit bottoms - dark blue\\",\\"Slim fit jeans - grey, Tracksuit bottoms - dark blue\\",\\"1, 1\\",\\"ZO0536305363, ZO0282702827\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0536305363, ZO0282702827\\",\\"53.969\\",\\"53.969\\",2,2,order,eddie +ZQMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Frank\\",\\"Ahmed Al Frank\\",MALE,4,Frank,Frank,\\"(empty)\\",Saturday,5,\\"ahmed al@frank-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562817,\\"sold_product_562817_1438, sold_product_562817_22804\\",\\"sold_product_562817_1438, sold_product_562817_22804\\",\\"60, 29.984\\",\\"60, 29.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"32.375, 15.891\\",\\"60, 29.984\\",\\"1,438, 22,804\\",\\"Trainers - black, Bomber Jacket - navy\\",\\"Trainers - black, Bomber Jacket - navy\\",\\"1, 1\\",\\"ZO0254702547, ZO0457804578\\",\\"0, 0\\",\\"60, 29.984\\",\\"60, 29.984\\",\\"0, 0\\",\\"ZO0254702547, ZO0457804578\\",90,90,2,2,order,ahmed +ZgMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Stokes\\",\\"Stephanie Stokes\\",FEMALE,6,Stokes,Stokes,\\"(empty)\\",Saturday,5,\\"stephanie@stokes-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562881,\\"sold_product_562881_20244, sold_product_562881_21108\\",\\"sold_product_562881_20244, sold_product_562881_21108\\",\\"28.984, 9.992\\",\\"28.984, 9.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"15.359, 5\\",\\"28.984, 9.992\\",\\"20,244, 21,108\\",\\"Handbag - black, Jersey dress - black\\",\\"Handbag - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0091700917, ZO0635406354\\",\\"0, 0\\",\\"28.984, 9.992\\",\\"28.984, 9.992\\",\\"0, 0\\",\\"ZO0091700917, ZO0635406354\\",\\"38.969\\",\\"38.969\\",2,2,order,stephanie +ZwMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Sherman\\",\\"Brigitte Sherman\\",FEMALE,12,Sherman,Sherman,\\"(empty)\\",Saturday,5,\\"brigitte@sherman-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562630,\\"sold_product_562630_18015, sold_product_562630_15858\\",\\"sold_product_562630_18015, sold_product_562630_15858\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"30, 13.492\\",\\"60, 24.984\\",\\"18,015, 15,858\\",\\"Summer dress - blue fog, Slip-ons - gold\\",\\"Summer dress - blue fog, Slip-ons - gold\\",\\"1, 1\\",\\"ZO0339803398, ZO0009700097\\",\\"0, 0\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"0, 0\\",\\"ZO0339803398, ZO0009700097\\",85,85,2,2,order,brigitte +aAMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Hicham,Hicham,\\"Hicham Hudson\\",\\"Hicham Hudson\\",MALE,8,Hudson,Hudson,\\"(empty)\\",Saturday,5,\\"hicham@hudson-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Elitelligence\\",\\"Spherecords, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562667,\\"sold_product_562667_21772, sold_product_562667_1559\\",\\"sold_product_562667_21772, sold_product_562667_1559\\",\\"8.992, 33\\",\\"8.992, 33\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Elitelligence\\",\\"Spherecords, Elitelligence\\",\\"4.672, 17.813\\",\\"8.992, 33\\",\\"21,772, 1,559\\",\\"3 PACK - Socks - white, Lace-ups - light brown\\",\\"3 PACK - Socks - white, Lace-ups - light brown\\",\\"1, 1\\",\\"ZO0664706647, ZO0506005060\\",\\"0, 0\\",\\"8.992, 33\\",\\"8.992, 33\\",\\"0, 0\\",\\"ZO0664706647, ZO0506005060\\",\\"41.969\\",\\"41.969\\",2,2,order,hicham +jQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Palmer\\",\\"Abd Palmer\\",MALE,52,Palmer,Palmer,\\"(empty)\\",Saturday,5,\\"abd@palmer-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563342,\\"sold_product_563342_24934, sold_product_563342_21049\\",\\"sold_product_563342_24934, sold_product_563342_21049\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"22.5, 7.941\\",\\"50, 14.992\\",\\"24,934, 21,049\\",\\"Lace-up boots - resin coffee, Print T-shirt - dark grey\\",\\"Lace-up boots - resin coffee, Print T-shirt - dark grey\\",\\"1, 1\\",\\"ZO0403504035, ZO0121101211\\",\\"0, 0\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"0, 0\\",\\"ZO0403504035, ZO0121101211\\",65,65,2,2,order,abd +mgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Hansen\\",\\"Jackson Hansen\\",MALE,13,Hansen,Hansen,\\"(empty)\\",Saturday,5,\\"jackson@hansen-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563366,\\"sold_product_563366_13189, sold_product_563366_18905\\",\\"sold_product_563366_13189, sold_product_563366_18905\\",\\"33, 42\\",\\"33, 42\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"17.156, 20.156\\",\\"33, 42\\",\\"13,189, 18,905\\",\\"Smart lace-ups - black , Light jacket - khaki\\",\\"Smart lace-ups - black , Light jacket - khaki\\",\\"1, 1\\",\\"ZO0388103881, ZO0540005400\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0388103881, ZO0540005400\\",75,75,2,2,order,jackson +oAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Recip,Recip,\\"Recip Webb\\",\\"Recip Webb\\",MALE,10,Webb,Webb,\\"(empty)\\",Saturday,5,\\"recip@webb-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562919,\\"sold_product_562919_24934, sold_product_562919_22599\\",\\"sold_product_562919_24934, sold_product_562919_22599\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"22.5, 11.5\\",\\"50, 24.984\\",\\"24,934, 22,599\\",\\"Lace-up boots - resin coffee, Sweatshirt - black\\",\\"Lace-up boots - resin coffee, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0403504035, ZO0595005950\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0403504035, ZO0595005950\\",75,75,2,2,order,recip +oQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Hicham,Hicham,\\"Hicham Sutton\\",\\"Hicham Sutton\\",MALE,8,Sutton,Sutton,\\"(empty)\\",Saturday,5,\\"hicham@sutton-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562976,\\"sold_product_562976_23426, sold_product_562976_1978\\",\\"sold_product_562976_23426, sold_product_562976_1978\\",\\"33, 50\\",\\"33, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"16.813, 27.484\\",\\"33, 50\\",\\"23,426, 1,978\\",\\"Slim fit jeans - navy coated , Lace-up boots - black\\",\\"Slim fit jeans - navy coated , Lace-up boots - black\\",\\"1, 1\\",\\"ZO0426904269, ZO0520305203\\",\\"0, 0\\",\\"33, 50\\",\\"33, 50\\",\\"0, 0\\",\\"ZO0426904269, ZO0520305203\\",83,83,2,2,order,hicham +sgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Barber\\",\\"Elyssa Barber\\",FEMALE,27,Barber,Barber,\\"(empty)\\",Saturday,5,\\"elyssa@barber-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563371,\\"sold_product_563371_16009, sold_product_563371_24465\\",\\"sold_product_563371_16009, sold_product_563371_24465\\",\\"30.984, 24.984\\",\\"30.984, 24.984\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"16.734, 11.5\\",\\"30.984, 24.984\\",\\"16,009, 24,465\\",\\"Handbag - black, Cowboy/Biker boots - black\\",\\"Handbag - black, Cowboy/Biker boots - black\\",\\"1, 1\\",\\"ZO0097500975, ZO0017100171\\",\\"0, 0\\",\\"30.984, 24.984\\",\\"30.984, 24.984\\",\\"0, 0\\",\\"ZO0097500975, ZO0017100171\\",\\"55.969\\",\\"55.969\\",2,2,order,elyssa +1wMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Graves\\",\\"Oliver Graves\\",MALE,7,Graves,Graves,\\"(empty)\\",Saturday,5,\\"oliver@graves-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562989,\\"sold_product_562989_22919, sold_product_562989_22668\\",\\"sold_product_562989_22919, sold_product_562989_22668\\",\\"22.984, 22.984\\",\\"22.984, 22.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.813, 11.492\\",\\"22.984, 22.984\\",\\"22,919, 22,668\\",\\"Sweatshirt - white, Shirt - petrol\\",\\"Sweatshirt - white, Shirt - petrol\\",\\"1, 1\\",\\"ZO0590905909, ZO0279902799\\",\\"0, 0\\",\\"22.984, 22.984\\",\\"22.984, 22.984\\",\\"0, 0\\",\\"ZO0590905909, ZO0279902799\\",\\"45.969\\",\\"45.969\\",2,2,order,oliver +2QMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Pia,Pia,\\"Pia Harmon\\",\\"Pia Harmon\\",FEMALE,45,Harmon,Harmon,\\"(empty)\\",Saturday,5,\\"pia@harmon-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562597,\\"sold_product_562597_24187, sold_product_562597_14371\\",\\"sold_product_562597_24187, sold_product_562597_14371\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"25.984, 10.063\\",\\"50, 18.984\\",\\"24,187, 14,371\\",\\"Boots - cognac, Across body bag - black\\",\\"Boots - cognac, Across body bag - black\\",\\"1, 1\\",\\"ZO0013200132, ZO0093800938\\",\\"0, 0\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"0, 0\\",\\"ZO0013200132, ZO0093800938\\",69,69,2,2,order,pia +TwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Goodwin\\",\\"Clarice Goodwin\\",FEMALE,18,Goodwin,Goodwin,\\"(empty)\\",Saturday,5,\\"clarice@goodwin-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563548,\\"sold_product_563548_5972, sold_product_563548_20864\\",\\"sold_product_563548_5972, sold_product_563548_20864\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"12.992, 16.172\\",\\"24.984, 33\\",\\"5,972, 20,864\\",\\"Ankle boots - black, Winter boots - cognac\\",\\"Ankle boots - black, Winter boots - cognac\\",\\"1, 1\\",\\"ZO0021600216, ZO0031600316\\",\\"0, 0\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"0, 0\\",\\"ZO0021600216, ZO0031600316\\",\\"57.969\\",\\"57.969\\",2,2,order,clarice +awMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Shaw\\",\\"Marwan Shaw\\",MALE,51,Shaw,Shaw,\\"(empty)\\",Saturday,5,\\"marwan@shaw-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562715,\\"sold_product_562715_21515, sold_product_562715_13710\\",\\"sold_product_562715_21515, sold_product_562715_13710\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"13.922, 5.52\\",\\"28.984, 11.992\\",\\"21,515, 13,710\\",\\"Shirt - dark blue, Print T-shirt - blue\\",\\"Shirt - dark blue, Print T-shirt - blue\\",\\"1, 1\\",\\"ZO0413404134, ZO0437204372\\",\\"0, 0\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"0, 0\\",\\"ZO0413404134, ZO0437204372\\",\\"40.969\\",\\"40.969\\",2,2,order,marwan +bAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Mary,Mary,\\"Mary Dennis\\",\\"Mary Dennis\\",FEMALE,20,Dennis,Dennis,\\"(empty)\\",Saturday,5,\\"mary@dennis-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563657,\\"sold_product_563657_21922, sold_product_563657_16149\\",\\"sold_product_563657_21922, sold_product_563657_16149\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"10.492, 29.906\\",\\"20.984, 65\\",\\"21,922, 16,149\\",\\"Jumper - dark blue/off white , Lace-up heels - cognac\\",\\"Jumper - dark blue/off white , Lace-up heels - cognac\\",\\"1, 1\\",\\"ZO0653506535, ZO0322303223\\",\\"0, 0\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"0, 0\\",\\"ZO0653506535, ZO0322303223\\",86,86,2,2,order,mary +bQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Chapman\\",\\"Wilhemina St. Chapman\\",FEMALE,17,Chapman,Chapman,\\"(empty)\\",Saturday,5,\\"wilhemina st.@chapman-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563704,\\"sold_product_563704_21823, sold_product_563704_19078\\",\\"sold_product_563704_21823, sold_product_563704_19078\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"9.656, 8.828\\",\\"20.984, 16.984\\",\\"21,823, 19,078\\",\\"Long sleeved top - peacoat, Print T-shirt - black\\",\\"Long sleeved top - peacoat, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0062700627, ZO0054100541\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0062700627, ZO0054100541\\",\\"37.969\\",\\"37.969\\",2,2,order,wilhemina +bgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Underwood\\",\\"Elyssa Underwood\\",FEMALE,27,Underwood,Underwood,\\"(empty)\\",Saturday,5,\\"elyssa@underwood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563534,\\"sold_product_563534_18172, sold_product_563534_19097\\",\\"sold_product_563534_18172, sold_product_563534_19097\\",\\"42, 60\\",\\"42, 60\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"22.25, 29.406\\",\\"42, 60\\",\\"18,172, 19,097\\",\\"Boots - black, Ankle boots - camel\\",\\"Boots - black, Ankle boots - camel\\",\\"1, 1\\",\\"ZO0014300143, ZO0249202492\\",\\"0, 0\\",\\"42, 60\\",\\"42, 60\\",\\"0, 0\\",\\"ZO0014300143, ZO0249202492\\",102,102,2,2,order,elyssa +jgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes, Men's Clothing\\",\\"Men's Accessories, Men's Shoes, Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Rivera\\",\\"Sultan Al Rivera\\",MALE,19,Rivera,Rivera,\\"(empty)\\",Saturday,5,\\"sultan al@rivera-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",716616,\\"sold_product_716616_11922, sold_product_716616_19741, sold_product_716616_6283, sold_product_716616_6868\\",\\"sold_product_716616_11922, sold_product_716616_19741, sold_product_716616_6283, sold_product_716616_6868\\",\\"18.984, 16.984, 11.992, 42\\",\\"18.984, 16.984, 11.992, 42\\",\\"Men's Accessories, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Men's Accessories, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Elitelligence, Microlutions\\",\\"Elitelligence, Elitelligence, Elitelligence, Microlutions\\",\\"9.68, 7.988, 6.352, 20.156\\",\\"18.984, 16.984, 11.992, 42\\",\\"11,922, 19,741, 6,283, 6,868\\",\\"Watch - black, Trainers - black, Basic T-shirt - dark blue/white, Bomber Jacket - bordeaux\\",\\"Watch - black, Trainers - black, Basic T-shirt - dark blue/white, Bomber Jacket - bordeaux\\",\\"1, 1, 1, 1\\",\\"ZO0601506015, ZO0507505075, ZO0549605496, ZO0114701147\\",\\"0, 0, 0, 0\\",\\"18.984, 16.984, 11.992, 42\\",\\"18.984, 16.984, 11.992, 42\\",\\"0, 0, 0, 0\\",\\"ZO0601506015, ZO0507505075, ZO0549605496, ZO0114701147\\",\\"89.938\\",\\"89.938\\",4,4,order,sultan +oQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Rice\\",\\"Jason Rice\\",MALE,16,Rice,Rice,\\"(empty)\\",Saturday,5,\\"jason@rice-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",563419,\\"sold_product_563419_17629, sold_product_563419_21599\\",\\"sold_product_563419_17629, sold_product_563419_21599\\",\\"24.984, 26.984\\",\\"24.984, 26.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"12.992, 13.492\\",\\"24.984, 26.984\\",\\"17,629, 21,599\\",\\"Tracksuit bottoms - mottled grey, Jumper - black\\",\\"Tracksuit bottoms - mottled grey, Jumper - black\\",\\"1, 1\\",\\"ZO0528605286, ZO0578505785\\",\\"0, 0\\",\\"24.984, 26.984\\",\\"24.984, 26.984\\",\\"0, 0\\",\\"ZO0528605286, ZO0578505785\\",\\"51.969\\",\\"51.969\\",2,2,order,jason +ogMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Wise\\",\\"Elyssa Wise\\",FEMALE,27,Wise,Wise,\\"(empty)\\",Saturday,5,\\"elyssa@wise-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Spherecords Curvy\\",\\"Gnomehouse, Spherecords Curvy\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563468,\\"sold_product_563468_18486, sold_product_563468_18903\\",\\"sold_product_563468_18486, sold_product_563468_18903\\",\\"100, 26.984\\",\\"100, 26.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords Curvy\\",\\"Gnomehouse, Spherecords Curvy\\",\\"46, 13.758\\",\\"100, 26.984\\",\\"18,486, 18,903\\",\\"Over-the-knee boots - black, Shirt - white\\",\\"Over-the-knee boots - black, Shirt - white\\",\\"1, 1\\",\\"ZO0324003240, ZO0711107111\\",\\"0, 0\\",\\"100, 26.984\\",\\"100, 26.984\\",\\"0, 0\\",\\"ZO0324003240, ZO0711107111\\",127,127,2,2,order,elyssa +owMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Mcdonald\\",\\"Rabbia Al Mcdonald\\",FEMALE,5,Mcdonald,Mcdonald,\\"(empty)\\",Saturday,5,\\"rabbia al@mcdonald-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563496,\\"sold_product_563496_19888, sold_product_563496_15294\\",\\"sold_product_563496_19888, sold_product_563496_15294\\",\\"100, 18.984\\",\\"100, 18.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"51, 9.68\\",\\"100, 18.984\\",\\"19,888, 15,294\\",\\"Classic coat - camel, Across body bag - cognac\\",\\"Classic coat - camel, Across body bag - cognac\\",\\"1, 1\\",\\"ZO0354103541, ZO0196101961\\",\\"0, 0\\",\\"100, 18.984\\",\\"100, 18.984\\",\\"0, 0\\",\\"ZO0354103541, ZO0196101961\\",119,119,2,2,order,rabbia +3QMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Gilbert\\",\\"Yasmine Gilbert\\",FEMALE,43,Gilbert,Gilbert,\\"(empty)\\",Saturday,5,\\"yasmine@gilbert-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563829,\\"sold_product_563829_18348, sold_product_563829_22842\\",\\"sold_product_563829_18348, sold_product_563829_22842\\",\\"50, 50\\",\\"50, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"26.484, 26.984\\",\\"50, 50\\",\\"18,348, 22,842\\",\\"Summer dress - apple butter, Beaded Occasion Dress\\",\\"Summer dress - apple butter, Beaded Occasion Dress\\",\\"1, 1\\",\\"ZO0335103351, ZO0043000430\\",\\"0, 0\\",\\"50, 50\\",\\"50, 50\\",\\"0, 0\\",\\"ZO0335103351, ZO0043000430\\",100,100,2,2,order,yasmine +3gMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Selena,Selena,\\"Selena Wells\\",\\"Selena Wells\\",FEMALE,42,Wells,Wells,\\"(empty)\\",Saturday,5,\\"selena@wells-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563888,\\"sold_product_563888_24162, sold_product_563888_20172\\",\\"sold_product_563888_24162, sold_product_563888_20172\\",\\"24.984, 21.984\\",\\"24.984, 21.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"13.242, 11.648\\",\\"24.984, 21.984\\",\\"24,162, 20,172\\",\\"Rucksack - cognac, Nightie - dark green\\",\\"Rucksack - cognac, Nightie - dark green\\",\\"1, 1\\",\\"ZO0090400904, ZO0100501005\\",\\"0, 0\\",\\"24.984, 21.984\\",\\"24.984, 21.984\\",\\"0, 0\\",\\"ZO0090400904, ZO0100501005\\",\\"46.969\\",\\"46.969\\",2,2,order,selena +\\"-QMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Hodges\\",\\"Pia Hodges\\",FEMALE,45,Hodges,Hodges,\\"(empty)\\",Saturday,5,\\"pia@hodges-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563037,\\"sold_product_563037_20079, sold_product_563037_11032\\",\\"sold_product_563037_20079, sold_product_563037_11032\\",\\"24.984, 75\\",\\"24.984, 75\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"12, 38.25\\",\\"24.984, 75\\",\\"20,079, 11,032\\",\\"Vest - black, Parka - mottled grey\\",\\"Vest - black, Parka - mottled grey\\",\\"1, 1\\",\\"ZO0172801728, ZO0115701157\\",\\"0, 0\\",\\"24.984, 75\\",\\"24.984, 75\\",\\"0, 0\\",\\"ZO0172801728, ZO0115701157\\",100,100,2,2,order,pia +\\"-gMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Brewer\\",\\"Mostafa Brewer\\",MALE,9,Brewer,Brewer,\\"(empty)\\",Saturday,5,\\"mostafa@brewer-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563105,\\"sold_product_563105_23911, sold_product_563105_15250\\",\\"sold_product_563105_23911, sold_product_563105_15250\\",\\"6.988, 33\\",\\"6.988, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"3.5, 18.141\\",\\"6.988, 33\\",\\"23,911, 15,250\\",\\"Basic T-shirt - black, Shirt - beige\\",\\"Basic T-shirt - black, Shirt - beige\\",\\"1, 1\\",\\"ZO0562205622, ZO0110901109\\",\\"0, 0\\",\\"6.988, 33\\",\\"6.988, 33\\",\\"0, 0\\",\\"ZO0562205622, ZO0110901109\\",\\"39.969\\",\\"39.969\\",2,2,order,mostafa +ZwMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Rose\\",\\"Wilhemina St. Rose\\",FEMALE,17,Rose,Rose,\\"(empty)\\",Saturday,5,\\"wilhemina st.@rose-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563066,\\"sold_product_563066_18616, sold_product_563066_17298\\",\\"sold_product_563066_18616, sold_product_563066_17298\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"36.75, 9.344\\",\\"75, 16.984\\",\\"18,616, 17,298\\",\\"Boots - brown, Across body bag - turquoise\\",\\"Boots - brown, Across body bag - turquoise\\",\\"1, 1\\",\\"ZO0373503735, ZO0206902069\\",\\"0, 0\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"0, 0\\",\\"ZO0373503735, ZO0206902069\\",92,92,2,2,order,wilhemina +aAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine King\\",\\"Yasmine King\\",FEMALE,43,King,King,\\"(empty)\\",Saturday,5,\\"yasmine@king-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563113,\\"sold_product_563113_13234, sold_product_563113_18481\\",\\"sold_product_563113_13234, sold_product_563113_18481\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"17.156, 13.242\\",\\"33, 24.984\\",\\"13,234, 18,481\\",\\"Jersey dress - red ochre, Jersey dress - dark red\\",\\"Jersey dress - red ochre, Jersey dress - dark red\\",\\"1, 1\\",\\"ZO0333903339, ZO0151801518\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0333903339, ZO0151801518\\",\\"57.969\\",\\"57.969\\",2,2,order,yasmine +\\"_QMtOW0BH63Xcmy432DJ\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Parker\\",\\"Wilhemina St. Parker\\",FEMALE,17,Parker,Parker,\\"(empty)\\",Friday,4,\\"wilhemina st.@parker-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562351,\\"sold_product_562351_18495, sold_product_562351_22598\\",\\"sold_product_562351_18495, sold_product_562351_22598\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"25, 14.781\\",\\"50, 28.984\\",\\"18,495, 22,598\\",\\"Ankle boots - cognac, Shift dress - black\\",\\"Ankle boots - cognac, Shift dress - black\\",\\"1, 1\\",\\"ZO0376403764, ZO0050800508\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0376403764, ZO0050800508\\",79,79,2,2,order,wilhemina +WwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Graham\\",\\"Gwen Graham\\",FEMALE,26,Graham,Graham,\\"(empty)\\",Friday,4,\\"gwen@graham-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561666,\\"sold_product_561666_24242, sold_product_561666_16817\\",\\"sold_product_561666_24242, sold_product_561666_16817\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"17.813, 10.25\\",\\"33, 18.984\\",\\"24,242, 16,817\\",\\"Jersey dress - black/white, Long sleeved top - black\\",\\"Jersey dress - black/white, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0042600426, ZO0166401664\\",\\"0, 0\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"0, 0\\",\\"ZO0042600426, ZO0166401664\\",\\"51.969\\",\\"51.969\\",2,2,order,gwen +XAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Porter\\",\\"Rabbia Al Porter\\",FEMALE,5,Porter,Porter,\\"(empty)\\",Friday,4,\\"rabbia al@porter-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561236,\\"sold_product_561236_23790, sold_product_561236_19511\\",\\"sold_product_561236_23790, sold_product_561236_19511\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"14.492, 8.656\\",\\"28.984, 16.984\\",\\"23,790, 19,511\\",\\"Jumper - peacoat, Nightie - black\\",\\"Jumper - peacoat, Nightie - black\\",\\"1, 1\\",\\"ZO0072700727, ZO0101001010\\",\\"0, 0\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"0, 0\\",\\"ZO0072700727, ZO0101001010\\",\\"45.969\\",\\"45.969\\",2,2,order,rabbia +XQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Shaw\\",\\"Hicham Shaw\\",MALE,8,Shaw,Shaw,\\"(empty)\\",Friday,4,\\"hicham@shaw-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561290,\\"sold_product_561290_1694, sold_product_561290_15025\\",\\"sold_product_561290_1694, sold_product_561290_15025\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"38.25, 12.992\\",\\"75, 24.984\\",\\"1,694, 15,025\\",\\"Slip-ons - Midnight Blue, Jumper - black\\",\\"Slip-ons - Midnight Blue, Jumper - black\\",\\"1, 1\\",\\"ZO0255702557, ZO0577605776\\",\\"0, 0\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"0, 0\\",\\"ZO0255702557, ZO0577605776\\",100,100,2,2,order,hicham +XgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Washington\\",\\"Abd Washington\\",MALE,52,Washington,Washington,\\"(empty)\\",Friday,4,\\"abd@washington-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",561739,\\"sold_product_561739_16553, sold_product_561739_14242\\",\\"sold_product_561739_16553, sold_product_561739_14242\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"12, 11.75\\",\\"24.984, 24.984\\",\\"16,553, 14,242\\",\\"Straight leg jeans - blue denim, Jeans Tapered Fit - black denim \\",\\"Straight leg jeans - blue denim, Jeans Tapered Fit - black denim \\",\\"1, 1\\",\\"ZO0537805378, ZO0538005380\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0537805378, ZO0538005380\\",\\"49.969\\",\\"49.969\\",2,2,order,abd +XwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Tran\\",\\"Rabbia Al Tran\\",FEMALE,5,Tran,Tran,\\"(empty)\\",Friday,4,\\"rabbia al@tran-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561786,\\"sold_product_561786_12183, sold_product_561786_15264\\",\\"sold_product_561786_12183, sold_product_561786_15264\\",\\"25.984, 29.984\\",\\"25.984, 29.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"13.508, 14.102\\",\\"25.984, 29.984\\",\\"12,183, 15,264\\",\\"Blouse - navy, Cardigan - black/anthrazit \\",\\"Blouse - navy, Cardigan - black/anthrazit \\",\\"1, 1\\",\\"ZO0064100641, ZO0068600686\\",\\"0, 0\\",\\"25.984, 29.984\\",\\"25.984, 29.984\\",\\"0, 0\\",\\"ZO0064100641, ZO0068600686\\",\\"55.969\\",\\"55.969\\",2,2,order,rabbia +hgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Willis\\",\\"Diane Willis\\",FEMALE,22,Willis,Willis,\\"(empty)\\",Friday,4,\\"diane@willis-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562400,\\"sold_product_562400_16415, sold_product_562400_5857\\",\\"sold_product_562400_16415, sold_product_562400_5857\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"8.156, 23.5\\",\\"16.984, 50\\",\\"16,415, 5,857\\",\\"Across body bag - black, Ankle boots - cognac\\",\\"Across body bag - black, Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0094200942, ZO0376603766\\",\\"0, 0\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"0, 0\\",\\"ZO0094200942, ZO0376603766\\",67,67,2,2,order,diane +1gMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Weber\\",\\"Elyssa Weber\\",FEMALE,27,Weber,Weber,\\"(empty)\\",Friday,4,\\"elyssa@weber-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562352,\\"sold_product_562352_19189, sold_product_562352_8284\\",\\"sold_product_562352_19189, sold_product_562352_8284\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"13.344, 16.813\\",\\"28.984, 33\\",\\"19,189, 8,284\\",\\"Blouse - black, Shirt - soft pink nude\\",\\"Blouse - black, Shirt - soft pink nude\\",\\"1, 1\\",\\"ZO0265302653, ZO0348203482\\",\\"0, 0\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"0, 0\\",\\"ZO0265302653, ZO0348203482\\",\\"61.969\\",\\"61.969\\",2,2,order,elyssa +BwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Garza\\",\\"Jackson Garza\\",MALE,13,Garza,Garza,\\"(empty)\\",Friday,4,\\"jackson@garza-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561343,\\"sold_product_561343_23977, sold_product_561343_19776\\",\\"sold_product_561343_23977, sold_product_561343_19776\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"30.547, 5.5\\",\\"65, 10.992\\",\\"23,977, 19,776\\",\\"Waterproof trousers - pumpkin spice, Print T-shirt - white\\",\\"Waterproof trousers - pumpkin spice, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0620706207, ZO0566705667\\",\\"0, 0\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"0, 0\\",\\"ZO0620706207, ZO0566705667\\",76,76,2,2,order,jackson +VQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Lewis\\",\\"Elyssa Lewis\\",FEMALE,27,Lewis,Lewis,\\"(empty)\\",Friday,4,\\"elyssa@lewis-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises Curvy, Pyramidustries\\",\\"Tigress Enterprises Curvy, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561543,\\"sold_product_561543_13132, sold_product_561543_19621\\",\\"sold_product_561543_13132, sold_product_561543_19621\\",\\"42, 34\\",\\"42, 34\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Pyramidustries\\",\\"Tigress Enterprises Curvy, Pyramidustries\\",\\"22.672, 17.328\\",\\"42, 34\\",\\"13,132, 19,621\\",\\"Blazer - black, Waterproof jacket - black\\",\\"Blazer - black, Waterproof jacket - black\\",\\"1, 1\\",\\"ZO0106701067, ZO0175101751\\",\\"0, 0\\",\\"42, 34\\",\\"42, 34\\",\\"0, 0\\",\\"ZO0106701067, ZO0175101751\\",76,76,2,2,order,elyssa +VgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Davidson\\",\\"Fitzgerald Davidson\\",MALE,11,Davidson,Davidson,\\"(empty)\\",Friday,4,\\"fitzgerald@davidson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561577,\\"sold_product_561577_15263, sold_product_561577_6820\\",\\"sold_product_561577_15263, sold_product_561577_6820\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"15.844, 12.992\\",\\"33, 24.984\\",\\"15,263, 6,820\\",\\"Briefcase - brown, Cardigan - dark blue\\",\\"Briefcase - brown, Cardigan - dark blue\\",\\"1, 1\\",\\"ZO0604406044, ZO0296302963\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0604406044, ZO0296302963\\",\\"57.969\\",\\"57.969\\",2,2,order,fuzzy +WQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Barnes\\",\\"Abd Barnes\\",MALE,52,Barnes,Barnes,\\"(empty)\\",Friday,4,\\"abd@barnes-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561429,\\"sold_product_561429_1791, sold_product_561429_3467\\",\\"sold_product_561429_1791, sold_product_561429_3467\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"14.852, 13.922\\",\\"33, 28.984\\",\\"1,791, 3,467\\",\\"Lace-up boots - green, Tights - black\\",\\"Lace-up boots - green, Tights - black\\",\\"1, 1\\",\\"ZO0511405114, ZO0621506215\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0511405114, ZO0621506215\\",\\"61.969\\",\\"61.969\\",2,2,order,abd +egMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Pia,Pia,\\"Pia Willis\\",\\"Pia Willis\\",FEMALE,45,Willis,Willis,\\"(empty)\\",Friday,4,\\"pia@willis-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Low Tide Media\\",\\"Gnomehouse, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562050,\\"sold_product_562050_14157, sold_product_562050_19227\\",\\"sold_product_562050_14157, sold_product_562050_19227\\",\\"50, 90\\",\\"50, 90\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Low Tide Media\\",\\"Gnomehouse, Low Tide Media\\",\\"24.5, 44.094\\",\\"50, 90\\",\\"14,157, 19,227\\",\\"Classic heels - black, Boots - cognac\\",\\"Classic heels - black, Boots - cognac\\",\\"1, 1\\",\\"ZO0322103221, ZO0373903739\\",\\"0, 0\\",\\"50, 90\\",\\"50, 90\\",\\"0, 0\\",\\"ZO0322103221, ZO0373903739\\",140,140,2,2,order,pia +ewMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Jim,Jim,\\"Jim Chandler\\",\\"Jim Chandler\\",MALE,41,Chandler,Chandler,\\"(empty)\\",Friday,4,\\"jim@chandler-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562101,\\"sold_product_562101_24315, sold_product_562101_11349\\",\\"sold_product_562101_24315, sold_product_562101_11349\\",\\"33, 42\\",\\"33, 42\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"16.813, 21.406\\",\\"33, 42\\",\\"24,315, 11,349\\",\\"Weekend bag - navy/brown, Summer jacket - black\\",\\"Weekend bag - navy/brown, Summer jacket - black\\",\\"1, 1\\",\\"ZO0468804688, ZO0285502855\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0468804688, ZO0285502855\\",75,75,2,2,order,jim +fAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Betty,Betty,\\"Betty Salazar\\",\\"Betty Salazar\\",FEMALE,44,Salazar,Salazar,\\"(empty)\\",Friday,4,\\"betty@salazar-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Angeldale,Angeldale,\\"Jun 20, 2019 @ 00:00:00.000\\",562247,\\"sold_product_562247_14495, sold_product_562247_5292\\",\\"sold_product_562247_14495, sold_product_562247_5292\\",\\"70, 85\\",\\"70, 85\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Angeldale\\",\\"Angeldale, Angeldale\\",\\"34.313, 43.344\\",\\"70, 85\\",\\"14,495, 5,292\\",\\"Classic Heels with Straps, Ankle boots - camel\\",\\"Classic Heels with Straps, Ankle boots - camel\\",\\"1, 1\\",\\"ZO0666206662, ZO0673206732\\",\\"0, 0\\",\\"70, 85\\",\\"70, 85\\",\\"0, 0\\",\\"ZO0666206662, ZO0673206732\\",155,155,2,2,order,betty +fQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Ball\\",\\"Robbie Ball\\",MALE,48,Ball,Ball,\\"(empty)\\",Friday,4,\\"robbie@ball-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562285,\\"sold_product_562285_15123, sold_product_562285_21357\\",\\"sold_product_562285_15123, sold_product_562285_21357\\",\\"10.992, 9.992\\",\\"10.992, 9.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"5.93, 4.699\\",\\"10.992, 9.992\\",\\"15,123, 21,357\\",\\"Print T-shirt - black, Basic T-shirt - white\\",\\"Print T-shirt - black, Basic T-shirt - white\\",\\"1, 1\\",\\"ZO0618306183, ZO0563105631\\",\\"0, 0\\",\\"10.992, 9.992\\",\\"10.992, 9.992\\",\\"0, 0\\",\\"ZO0618306183, ZO0563105631\\",\\"20.984\\",\\"20.984\\",2,2,order,robbie +ugMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Dawson\\",\\"Betty Dawson\\",FEMALE,44,Dawson,Dawson,\\"(empty)\\",Friday,4,\\"betty@dawson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561965,\\"sold_product_561965_8728, sold_product_561965_24101\\",\\"sold_product_561965_8728, sold_product_561965_24101\\",\\"65, 42\\",\\"65, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"35.094, 18.906\\",\\"65, 42\\",\\"8,728, 24,101\\",\\"Jumper - dark red, Jersey dress - jester red\\",\\"Jumper - dark red, Jersey dress - jester red\\",\\"1, 1\\",\\"ZO0655806558, ZO0334503345\\",\\"0, 0\\",\\"65, 42\\",\\"65, 42\\",\\"0, 0\\",\\"ZO0655806558, ZO0334503345\\",107,107,2,2,order,betty +uwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Hart\\",\\"Sonya Hart\\",FEMALE,28,Hart,Hart,\\"(empty)\\",Friday,4,\\"sonya@hart-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Spherecords, Crystal Lighting\\",\\"Spherecords, Crystal Lighting\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562008,\\"sold_product_562008_21990, sold_product_562008_22639\\",\\"sold_product_562008_21990, sold_product_562008_22639\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Crystal Lighting\\",\\"Spherecords, Crystal Lighting\\",\\"15.844, 11.25\\",\\"33, 24.984\\",\\"21,990, 22,639\\",\\"Blazer - black, Wool jumper - white\\",\\"Blazer - black, Wool jumper - white\\",\\"1, 1\\",\\"ZO0657006570, ZO0485604856\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0657006570, ZO0485604856\\",\\"57.969\\",\\"57.969\\",2,2,order,sonya +wAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Simmons\\",\\"Sultan Al Simmons\\",MALE,19,Simmons,Simmons,\\"(empty)\\",Friday,4,\\"sultan al@simmons-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561472,\\"sold_product_561472_12840, sold_product_561472_24625\\",\\"sold_product_561472_12840, sold_product_561472_24625\\",\\"65, 13.992\\",\\"65, 13.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"30.547, 6.301\\",\\"65, 13.992\\",\\"12,840, 24,625\\",\\"Lace-up boots - black, Print T-shirt - dark blue multicolor\\",\\"Lace-up boots - black, Print T-shirt - dark blue multicolor\\",\\"1, 1\\",\\"ZO0399703997, ZO0439904399\\",\\"0, 0\\",\\"65, 13.992\\",\\"65, 13.992\\",\\"0, 0\\",\\"ZO0399703997, ZO0439904399\\",79,79,2,2,order,sultan +wQMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Carr\\",\\"Abdulraheem Al Carr\\",MALE,33,Carr,Carr,\\"(empty)\\",Friday,4,\\"abdulraheem al@carr-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561490,\\"sold_product_561490_12150, sold_product_561490_20378\\",\\"sold_product_561490_12150, sold_product_561490_20378\\",\\"50, 8.992\\",\\"50, 8.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"22.5, 4.23\\",\\"50, 8.992\\",\\"12,150, 20,378\\",\\"Casual lace-ups - dark brown , Basic T-shirt - white\\",\\"Casual lace-ups - dark brown , Basic T-shirt - white\\",\\"1, 1\\",\\"ZO0681306813, ZO0545705457\\",\\"0, 0\\",\\"50, 8.992\\",\\"50, 8.992\\",\\"0, 0\\",\\"ZO0681306813, ZO0545705457\\",\\"58.969\\",\\"58.969\\",2,2,order,abdulraheem +wgMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Allison\\",\\"Selena Allison\\",FEMALE,42,Allison,Allison,\\"(empty)\\",Friday,4,\\"selena@allison-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561317,\\"sold_product_561317_20991, sold_product_561317_22586\\",\\"sold_product_561317_20991, sold_product_561317_22586\\",\\"42, 33\\",\\"42, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"21.828, 16.172\\",\\"42, 33\\",\\"20,991, 22,586\\",\\"Mini skirt - navy blazer, Cardigan - navy/brown\\",\\"Mini skirt - navy blazer, Cardigan - navy/brown\\",\\"1, 1\\",\\"ZO0329303293, ZO0074000740\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0329303293, ZO0074000740\\",75,75,2,2,order,selena +0gMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Walters\\",\\"Thad Walters\\",MALE,30,Walters,Walters,\\"(empty)\\",Friday,4,\\"thad@walters-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562424,\\"sold_product_562424_11737, sold_product_562424_13228\\",\\"sold_product_562424_11737, sold_product_562424_13228\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"9.867, 11.5\\",\\"20.984, 24.984\\",\\"11,737, 13,228\\",\\"Sweatshirt - dark blue, Jumper - dark blue multicolor\\",\\"Sweatshirt - dark blue, Jumper - dark blue multicolor\\",\\"1, 1\\",\\"ZO0581705817, ZO0448804488\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0581705817, ZO0448804488\\",\\"45.969\\",\\"45.969\\",2,2,order,thad +0wMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Potter\\",\\"Sultan Al Potter\\",MALE,19,Potter,Potter,\\"(empty)\\",Friday,4,\\"sultan al@potter-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562473,\\"sold_product_562473_13192, sold_product_562473_21203\\",\\"sold_product_562473_13192, sold_product_562473_21203\\",\\"85, 75\\",\\"85, 75\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"39.094, 36.75\\",\\"85, 75\\",\\"13,192, 21,203\\",\\"Parka - navy, Winter jacket - dark blue\\",\\"Parka - navy, Winter jacket - dark blue\\",\\"1, 1\\",\\"ZO0289202892, ZO0432304323\\",\\"0, 0\\",\\"85, 75\\",\\"85, 75\\",\\"0, 0\\",\\"ZO0289202892, ZO0432304323\\",160,160,2,2,order,sultan +1AMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Jimenez\\",\\"Hicham Jimenez\\",MALE,8,Jimenez,Jimenez,\\"(empty)\\",Friday,4,\\"hicham@jimenez-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562488,\\"sold_product_562488_13297, sold_product_562488_13138\\",\\"sold_product_562488_13297, sold_product_562488_13138\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"32.375, 13.492\\",\\"60, 24.984\\",\\"13,297, 13,138\\",\\"Light jacket - navy, Jumper - black\\",\\"Light jacket - navy, Jumper - black\\",\\"1, 1\\",\\"ZO0275202752, ZO0574405744\\",\\"0, 0\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"0, 0\\",\\"ZO0275202752, ZO0574405744\\",85,85,2,2,order,hicham +1QMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Richards\\",\\"Yuri Richards\\",MALE,21,Richards,Richards,\\"(empty)\\",Friday,4,\\"yuri@richards-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562118,\\"sold_product_562118_18280, sold_product_562118_15033\\",\\"sold_product_562118_18280, sold_product_562118_15033\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"7.82, 13.492\\",\\"16.984, 24.984\\",\\"18,280, 15,033\\",\\"Tights - black, Hoodie - mottled grey\\",\\"Tights - black, Hoodie - mottled grey\\",\\"1, 1\\",\\"ZO0622406224, ZO0591405914\\",\\"0, 0\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"0, 0\\",\\"ZO0622406224, ZO0591405914\\",\\"41.969\\",\\"41.969\\",2,2,order,yuri +1gMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Padilla\\",\\"Yasmine Padilla\\",FEMALE,43,Padilla,Padilla,\\"(empty)\\",Friday,4,\\"yasmine@padilla-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Crystal Lighting, Spherecords\\",\\"Crystal Lighting, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562159,\\"sold_product_562159_8592, sold_product_562159_19303\\",\\"sold_product_562159_8592, sold_product_562159_19303\\",\\"24.984, 9.992\\",\\"24.984, 9.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Crystal Lighting, Spherecords\\",\\"Crystal Lighting, Spherecords\\",\\"11.25, 5.488\\",\\"24.984, 9.992\\",\\"8,592, 19,303\\",\\"Wool jumper - pink, 5 PACK - Trainer socks - black\\",\\"Wool jumper - pink, 5 PACK - Trainer socks - black\\",\\"1, 1\\",\\"ZO0485704857, ZO0662006620\\",\\"0, 0\\",\\"24.984, 9.992\\",\\"24.984, 9.992\\",\\"0, 0\\",\\"ZO0485704857, ZO0662006620\\",\\"34.969\\",\\"34.969\\",2,2,order,yasmine +1wMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Mcdonald\\",\\"Robbie Mcdonald\\",MALE,48,Mcdonald,Mcdonald,\\"(empty)\\",Friday,4,\\"robbie@mcdonald-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"(empty)\\",\\"(empty)\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562198,\\"sold_product_562198_12308, sold_product_562198_12830\\",\\"sold_product_562198_12308, sold_product_562198_12830\\",\\"155, 155\\",\\"155, 155\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"(empty), (empty)\\",\\"(empty), (empty)\\",\\"72.875, 72.875\\",\\"155, 155\\",\\"12,308, 12,830\\",\\"Smart slip-ons - brown, Lace-ups - black\\",\\"Smart slip-ons - brown, Lace-ups - black\\",\\"1, 1\\",\\"ZO0482504825, ZO0481304813\\",\\"0, 0\\",\\"155, 155\\",\\"155, 155\\",\\"0, 0\\",\\"ZO0482504825, ZO0481304813\\",310,310,2,2,order,robbie +2QMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Betty,Betty,\\"Betty Frank\\",\\"Betty Frank\\",FEMALE,44,Frank,Frank,\\"(empty)\\",Friday,4,\\"betty@frank-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562523,\\"sold_product_562523_11110, sold_product_562523_20613\\",\\"sold_product_562523_11110, sold_product_562523_20613\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"15.359, 11.5\\",\\"28.984, 24.984\\",\\"11,110, 20,613\\",\\"Tracksuit top - black, Watch - silver-coloured\\",\\"Tracksuit top - black, Watch - silver-coloured\\",\\"1, 1\\",\\"ZO0178001780, ZO0078400784\\",\\"0, 0\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"0, 0\\",\\"ZO0178001780, ZO0078400784\\",\\"53.969\\",\\"53.969\\",2,2,order,betty +lwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Valdez\\",\\"Youssef Valdez\\",MALE,31,Valdez,Valdez,\\"(empty)\\",Friday,4,\\"youssef@valdez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",561373,\\"sold_product_561373_20306, sold_product_561373_18262\\",\\"sold_product_561373_20306, sold_product_561373_18262\\",\\"11.992, 20.984\\",\\"11.992, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.52, 10.703\\",\\"11.992, 20.984\\",\\"20,306, 18,262\\",\\"Long sleeved top - mottled dark grey, Chinos - khaki\\",\\"Long sleeved top - mottled dark grey, Chinos - khaki\\",\\"1, 1\\",\\"ZO0563905639, ZO0528805288\\",\\"0, 0\\",\\"11.992, 20.984\\",\\"11.992, 20.984\\",\\"0, 0\\",\\"ZO0563905639, ZO0528805288\\",\\"32.969\\",\\"32.969\\",2,2,order,youssef +mAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jason,Jason,\\"Jason Webb\\",\\"Jason Webb\\",MALE,16,Webb,Webb,\\"(empty)\\",Friday,4,\\"jason@webb-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561409,\\"sold_product_561409_1438, sold_product_561409_15672\\",\\"sold_product_561409_1438, sold_product_561409_15672\\",\\"60, 65\\",\\"60, 65\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"32.375, 33.125\\",\\"60, 65\\",\\"1,438, 15,672\\",\\"Trainers - black, Waterproof jacket - black\\",\\"Trainers - black, Waterproof jacket - black\\",\\"1, 1\\",\\"ZO0254702547, ZO0626306263\\",\\"0, 0\\",\\"60, 65\\",\\"60, 65\\",\\"0, 0\\",\\"ZO0254702547, ZO0626306263\\",125,125,2,2,order,jason +mQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Stephanie,Stephanie,\\"Stephanie Munoz\\",\\"Stephanie Munoz\\",FEMALE,6,Munoz,Munoz,\\"(empty)\\",Friday,4,\\"stephanie@munoz-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises Curvy, Low Tide Media\\",\\"Tigress Enterprises Curvy, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561858,\\"sold_product_561858_22426, sold_product_561858_12672\\",\\"sold_product_561858_22426, sold_product_561858_12672\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Low Tide Media\\",\\"Tigress Enterprises Curvy, Low Tide Media\\",\\"13.742, 16.813\\",\\"24.984, 33\\",\\"22,426, 12,672\\",\\"Print T-shirt - Chocolate, Ballet pumps - black\\",\\"Print T-shirt - Chocolate, Ballet pumps - black\\",\\"1, 1\\",\\"ZO0105301053, ZO0364803648\\",\\"0, 0\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"0, 0\\",\\"ZO0105301053, ZO0364803648\\",\\"57.969\\",\\"57.969\\",2,2,order,stephanie +mgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Marshall\\",\\"Fitzgerald Marshall\\",MALE,11,Marshall,Marshall,\\"(empty)\\",Friday,4,\\"fitzgerald@marshall-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561904,\\"sold_product_561904_15204, sold_product_561904_12074\\",\\"sold_product_561904_15204, sold_product_561904_12074\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"21.406, 5.641\\",\\"42, 11.992\\",\\"15,204, 12,074\\",\\"Weekend bag - black, Polo shirt - blue\\",\\"Weekend bag - black, Polo shirt - blue\\",\\"1, 1\\",\\"ZO0315303153, ZO0441904419\\",\\"0, 0\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"0, 0\\",\\"ZO0315303153, ZO0441904419\\",\\"53.969\\",\\"53.969\\",2,2,order,fuzzy +9QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Tran\\",\\"Betty Tran\\",FEMALE,44,Tran,Tran,\\"(empty)\\",Friday,4,\\"betty@tran-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises MAMA, Tigress Enterprises Curvy\\",\\"Tigress Enterprises MAMA, Tigress Enterprises Curvy\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561381,\\"sold_product_561381_16065, sold_product_561381_20409\\",\\"sold_product_561381_16065, sold_product_561381_20409\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Tigress Enterprises Curvy\\",\\"Tigress Enterprises MAMA, Tigress Enterprises Curvy\\",\\"10.289, 15.844\\",\\"20.984, 33\\",\\"16,065, 20,409\\",\\"Vest - rose/black, Cardigan - black/offwhite\\",\\"Vest - rose/black, Cardigan - black/offwhite\\",\\"1, 1\\",\\"ZO0231202312, ZO0106401064\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0231202312, ZO0106401064\\",\\"53.969\\",\\"53.969\\",2,2,order,betty +9gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Nash\\",\\"Abd Nash\\",MALE,52,Nash,Nash,\\"(empty)\\",Friday,4,\\"abd@nash-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",561830,\\"sold_product_561830_15032, sold_product_561830_12189\\",\\"sold_product_561830_15032, sold_product_561830_12189\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"13.922, 7.199\\",\\"28.984, 14.992\\",\\"15,032, 12,189\\",\\"Sweatshirt - mottled grey, Tracksuit bottoms - mottled grey\\",\\"Sweatshirt - mottled grey, Tracksuit bottoms - mottled grey\\",\\"1, 1\\",\\"ZO0591105911, ZO0532805328\\",\\"0, 0\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"0, 0\\",\\"ZO0591105911, ZO0532805328\\",\\"43.969\\",\\"43.969\\",2,2,order,abd +9wMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Wagdi,Wagdi,\\"Wagdi Gomez\\",\\"Wagdi Gomez\\",MALE,15,Gomez,Gomez,\\"(empty)\\",Friday,4,\\"wagdi@gomez-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561878,\\"sold_product_561878_17804, sold_product_561878_17209\\",\\"sold_product_561878_17804, sold_product_561878_17209\\",\\"12.992, 50\\",\\"12.992, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"6.5, 26.484\\",\\"12.992, 50\\",\\"17,804, 17,209\\",\\"Long sleeved top - mottled dark grey, Casual lace-ups - grey\\",\\"Long sleeved top - mottled dark grey, Casual lace-ups - grey\\",\\"1, 1\\",\\"ZO0562905629, ZO0388303883\\",\\"0, 0\\",\\"12.992, 50\\",\\"12.992, 50\\",\\"0, 0\\",\\"ZO0562905629, ZO0388303883\\",\\"62.969\\",\\"62.969\\",2,2,order,wagdi +\\"-AMtOW0BH63Xcmy44WNv\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Baker\\",\\"Stephanie Baker\\",FEMALE,6,Baker,Baker,\\"(empty)\\",Friday,4,\\"stephanie@baker-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561916,\\"sold_product_561916_15403, sold_product_561916_11041\\",\\"sold_product_561916_15403, sold_product_561916_11041\\",\\"20.984, 13.992\\",\\"20.984, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"10.703, 7.27\\",\\"20.984, 13.992\\",\\"15,403, 11,041\\",\\"Sweatshirt - dark grey multicolor, Basic T-shirt - dark grey multicolor\\",\\"Sweatshirt - dark grey multicolor, Basic T-shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0180101801, ZO0157101571\\",\\"0, 0\\",\\"20.984, 13.992\\",\\"20.984, 13.992\\",\\"0, 0\\",\\"ZO0180101801, ZO0157101571\\",\\"34.969\\",\\"34.969\\",2,2,order,stephanie +HQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Recip,Recip,\\"Recip Shaw\\",\\"Recip Shaw\\",MALE,10,Shaw,Shaw,\\"(empty)\\",Friday,4,\\"recip@shaw-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562324,\\"sold_product_562324_20112, sold_product_562324_12375\\",\\"sold_product_562324_20112, sold_product_562324_12375\\",\\"25.984, 20.984\\",\\"25.984, 20.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"12.477, 10.289\\",\\"25.984, 20.984\\",\\"20,112, 12,375\\",\\"Shirt - blue, Trainers - red\\",\\"Shirt - blue, Trainers - red\\",\\"1, 1\\",\\"ZO0413604136, ZO0509005090\\",\\"0, 0\\",\\"25.984, 20.984\\",\\"25.984, 20.984\\",\\"0, 0\\",\\"ZO0413604136, ZO0509005090\\",\\"46.969\\",\\"46.969\\",2,2,order,recip +HgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Ruiz\\",\\"Sonya Ruiz\\",FEMALE,28,Ruiz,Ruiz,\\"(empty)\\",Friday,4,\\"sonya@ruiz-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562367,\\"sold_product_562367_19018, sold_product_562367_15868\\",\\"sold_product_562367_19018, sold_product_562367_15868\\",\\"42, 10.992\\",\\"42, 10.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"19.734, 5.711\\",\\"42, 10.992\\",\\"19,018, 15,868\\",\\"High heeled sandals - red, Scarf - black/white\\",\\"High heeled sandals - red, Scarf - black/white\\",\\"1, 1\\",\\"ZO0371803718, ZO0195401954\\",\\"0, 0\\",\\"42, 10.992\\",\\"42, 10.992\\",\\"0, 0\\",\\"ZO0371803718, ZO0195401954\\",\\"52.969\\",\\"52.969\\",2,2,order,sonya +UwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Ryan\\",\\"Wilhemina St. Ryan\\",FEMALE,17,Ryan,Ryan,\\"(empty)\\",Friday,4,\\"wilhemina st.@ryan-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Tigress Enterprises, Pyramidustries, Angeldale\\",\\"Oceanavigations, Tigress Enterprises, Pyramidustries, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",729673,\\"sold_product_729673_23755, sold_product_729673_23467, sold_product_729673_15159, sold_product_729673_5415\\",\\"sold_product_729673_23755, sold_product_729673_23467, sold_product_729673_15159, sold_product_729673_5415\\",\\"50, 60, 24.984, 65\\",\\"50, 60, 24.984, 65\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Shoes\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Tigress Enterprises, Pyramidustries, Angeldale\\",\\"Oceanavigations, Tigress Enterprises, Pyramidustries, Angeldale\\",\\"23, 31.188, 11.75, 31.844\\",\\"50, 60, 24.984, 65\\",\\"23,755, 23,467, 15,159, 5,415\\",\\"Cardigan - blue & white, Lohan - Maxi dress - silver/black, High heels - blue, Lace-ups - grey\\",\\"Cardigan - blue & white, Lohan - Maxi dress - silver/black, High heels - blue, Lace-ups - grey\\",\\"1, 1, 1, 1\\",\\"ZO0268202682, ZO0048200482, ZO0134801348, ZO0668406684\\",\\"0, 0, 0, 0\\",\\"50, 60, 24.984, 65\\",\\"50, 60, 24.984, 65\\",\\"0, 0, 0, 0\\",\\"ZO0268202682, ZO0048200482, ZO0134801348, ZO0668406684\\",200,200,4,4,order,wilhemina +rQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Ruiz\\",\\"Rabbia Al Ruiz\\",FEMALE,5,Ruiz,Ruiz,\\"(empty)\\",Friday,4,\\"rabbia al@ruiz-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises MAMA\\",\\"Tigress Enterprises MAMA\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561953,\\"sold_product_561953_22114, sold_product_561953_19225\\",\\"sold_product_561953_22114, sold_product_561953_19225\\",\\"29.984, 22.984\\",\\"29.984, 22.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Tigress Enterprises MAMA\\",\\"Tigress Enterprises MAMA, Tigress Enterprises MAMA\\",\\"15.891, 11.273\\",\\"29.984, 22.984\\",\\"22,114, 19,225\\",\\"Blouse - black/white, Blouse - black\\",\\"Blouse - black/white, Blouse - black\\",\\"1, 1\\",\\"ZO0232002320, ZO0231402314\\",\\"0, 0\\",\\"29.984, 22.984\\",\\"29.984, 22.984\\",\\"0, 0\\",\\"ZO0232002320, ZO0231402314\\",\\"52.969\\",\\"52.969\\",2,2,order,rabbia +rgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,rania,rania,\\"rania Brady\\",\\"rania Brady\\",FEMALE,24,Brady,Brady,\\"(empty)\\",Friday,4,\\"rania@brady-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561997,\\"sold_product_561997_16402, sold_product_561997_12822\\",\\"sold_product_561997_16402, sold_product_561997_12822\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"17.484, 7.82\\",\\"33, 16.984\\",\\"16,402, 12,822\\",\\"Shirt - navy blazer, Platform sandals - navy\\",\\"Shirt - navy blazer, Platform sandals - navy\\",\\"1, 1\\",\\"ZO0346203462, ZO0010700107\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0346203462, ZO0010700107\\",\\"49.969\\",\\"49.969\\",2,2,order,rani +rwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Gwen,Gwen,\\"Gwen Butler\\",\\"Gwen Butler\\",FEMALE,26,Butler,Butler,\\"(empty)\\",Friday,4,\\"gwen@butler-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561534,\\"sold_product_561534_25055, sold_product_561534_15461\\",\\"sold_product_561534_25055, sold_product_561534_15461\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"23, 8.492\\",\\"50, 16.984\\",\\"25,055, 15,461\\",\\"Ankle boots - Dodger Blue, Across body bag - black \\",\\"Ankle boots - Dodger Blue, Across body bag - black \\",\\"1, 1\\",\\"ZO0380303803, ZO0211902119\\",\\"0, 0\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"0, 0\\",\\"ZO0380303803, ZO0211902119\\",67,67,2,2,order,gwen +sQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Wagdi,Wagdi,\\"Wagdi Graham\\",\\"Wagdi Graham\\",MALE,15,Graham,Graham,\\"(empty)\\",Friday,4,\\"wagdi@graham-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",561632,\\"sold_product_561632_19048, sold_product_561632_15628\\",\\"sold_product_561632_19048, sold_product_561632_15628\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.93, 10.078\\",\\"10.992, 20.984\\",\\"19,048, 15,628\\",\\"Long sleeved top - lt grey/dk grey , Watch - brown\\",\\"Long sleeved top - lt grey/dk grey , Watch - brown\\",\\"1, 1\\",\\"ZO0546605466, ZO0600906009\\",\\"0, 0\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"0, 0\\",\\"ZO0546605466, ZO0600906009\\",\\"31.984\\",\\"31.984\\",2,2,order,wagdi +DwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Romero\\",\\"Mostafa Romero\\",MALE,9,Romero,Romero,\\"(empty)\\",Friday,4,\\"mostafa@romero-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561676,\\"sold_product_561676_1702, sold_product_561676_11429\\",\\"sold_product_561676_1702, sold_product_561676_11429\\",\\"25.984, 10.992\\",\\"25.984, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"12.219, 5.391\\",\\"25.984, 10.992\\",\\"1,702, 11,429\\",\\"Trainers - black/grey, Swimming shorts - lime punch\\",\\"Trainers - black/grey, Swimming shorts - lime punch\\",\\"1, 1\\",\\"ZO0512705127, ZO0629406294\\",\\"0, 0\\",\\"25.984, 10.992\\",\\"25.984, 10.992\\",\\"0, 0\\",\\"ZO0512705127, ZO0629406294\\",\\"36.969\\",\\"36.969\\",2,2,order,mostafa +EAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Estrada\\",\\"Abdulraheem Al Estrada\\",MALE,33,Estrada,Estrada,\\"(empty)\\",Friday,4,\\"abdulraheem al@estrada-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561218,\\"sold_product_561218_14074, sold_product_561218_12696\\",\\"sold_product_561218_14074, sold_product_561218_12696\\",\\"60, 75\\",\\"60, 75\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"27.594, 36.75\\",\\"60, 75\\",\\"14,074, 12,696\\",\\"Suit jacket - dark blue, Briefcase - brandy\\",\\"Suit jacket - dark blue, Briefcase - brandy\\",\\"1, 1\\",\\"ZO0409604096, ZO0466904669\\",\\"0, 0\\",\\"60, 75\\",\\"60, 75\\",\\"0, 0\\",\\"ZO0409604096, ZO0466904669\\",135,135,2,2,order,abdulraheem +EQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Reese\\",\\"Diane Reese\\",FEMALE,22,Reese,Reese,\\"(empty)\\",Friday,4,\\"diane@reese-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561256,\\"sold_product_561256_23086, sold_product_561256_16589\\",\\"sold_product_561256_23086, sold_product_561256_16589\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"12.742, 8.492\\",\\"24.984, 16.984\\",\\"23,086, 16,589\\",\\"Jersey dress - black, Long sleeved top - black\\",\\"Jersey dress - black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0151601516, ZO0162901629\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0151601516, ZO0162901629\\",\\"41.969\\",\\"41.969\\",2,2,order,diane +EgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Rivera\\",\\"Jackson Rivera\\",MALE,13,Rivera,Rivera,\\"(empty)\\",Friday,4,\\"jackson@rivera-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561311,\\"sold_product_561311_22466, sold_product_561311_13378\\",\\"sold_product_561311_22466, sold_product_561311_13378\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"10.703, 24.5\\",\\"20.984, 50\\",\\"22,466, 13,378\\",\\"Sweatshirt - black , Casual lace-ups - cognac\\",\\"Sweatshirt - black , Casual lace-ups - cognac\\",\\"1, 1\\",\\"ZO0458604586, ZO0391603916\\",\\"0, 0\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"0, 0\\",\\"ZO0458604586, ZO0391603916\\",71,71,2,2,order,jackson +EwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Mccarthy\\",\\"Wilhemina St. Mccarthy\\",FEMALE,17,Mccarthy,Mccarthy,\\"(empty)\\",Friday,4,\\"wilhemina st.@mccarthy-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561781,\\"sold_product_561781_5453, sold_product_561781_15437\\",\\"sold_product_561781_5453, sold_product_561781_15437\\",\\"50, 33\\",\\"50, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"26.984, 18.141\\",\\"50, 33\\",\\"5,453, 15,437\\",\\"Slip-ons - Midnight Blue, Summer dress - black\\",\\"Slip-ons - Midnight Blue, Summer dress - black\\",\\"1, 1\\",\\"ZO0235402354, ZO0048700487\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0235402354, ZO0048700487\\",83,83,2,2,order,wilhemina +ewMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Garza\\",\\"Kamal Garza\\",MALE,39,Garza,Garza,\\"(empty)\\",Friday,4,\\"kamal@garza-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561375,\\"sold_product_561375_2773, sold_product_561375_18549\\",\\"sold_product_561375_2773, sold_product_561375_18549\\",\\"85, 24.984\\",\\"85, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"39.094, 11.5\\",\\"85, 24.984\\",\\"2,773, 18,549\\",\\"Winter jacket - black, Trousers - dark blue\\",\\"Winter jacket - black, Trousers - dark blue\\",\\"1, 1\\",\\"ZO0115201152, ZO0420404204\\",\\"0, 0\\",\\"85, 24.984\\",\\"85, 24.984\\",\\"0, 0\\",\\"ZO0115201152, ZO0420404204\\",110,110,2,2,order,kamal +fAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Simpson\\",\\"Brigitte Simpson\\",FEMALE,12,Simpson,Simpson,\\"(empty)\\",Friday,4,\\"brigitte@simpson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561876,\\"sold_product_561876_11067, sold_product_561876_20664\\",\\"sold_product_561876_11067, sold_product_561876_20664\\",\\"13.992, 28.984\\",\\"13.992, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"7.27, 14.781\\",\\"13.992, 28.984\\",\\"11,067, 20,664\\",\\"Print T-shirt - black/turquoise, Trainers - navy/black\\",\\"Print T-shirt - black/turquoise, Trainers - navy/black\\",\\"1, 1\\",\\"ZO0170301703, ZO0027000270\\",\\"0, 0\\",\\"13.992, 28.984\\",\\"13.992, 28.984\\",\\"0, 0\\",\\"ZO0170301703, ZO0027000270\\",\\"42.969\\",\\"42.969\\",2,2,order,brigitte +fQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Chapman\\",\\"Betty Chapman\\",FEMALE,44,Chapman,Chapman,\\"(empty)\\",Friday,4,\\"betty@chapman-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561633,\\"sold_product_561633_23859, sold_product_561633_7687\\",\\"sold_product_561633_23859, sold_product_561633_7687\\",\\"16.984, 13.992\\",\\"16.984, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"8.328, 6.719\\",\\"16.984, 13.992\\",\\"23,859, 7,687\\",\\"Long sleeved top - berry, Print T-shirt - black\\",\\"Long sleeved top - berry, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0165001650, ZO0159001590\\",\\"0, 0\\",\\"16.984, 13.992\\",\\"16.984, 13.992\\",\\"0, 0\\",\\"ZO0165001650, ZO0159001590\\",\\"30.984\\",\\"30.984\\",2,2,order,betty +4wMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Wood\\",\\"Elyssa Wood\\",FEMALE,27,Wood,Wood,\\"(empty)\\",Friday,4,\\"elyssa@wood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562323,\\"sold_product_562323_17653, sold_product_562323_25172\\",\\"sold_product_562323_17653, sold_product_562323_25172\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"31.844, 11.539\\",\\"65, 20.984\\",\\"17,653, 25,172\\",\\"Classic heels - blush, Blouse - black\\",\\"Classic heels - blush, Blouse - black\\",\\"1, 1\\",\\"ZO0238502385, ZO0650406504\\",\\"0, 0\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"0, 0\\",\\"ZO0238502385, ZO0650406504\\",86,86,2,2,order,elyssa +5AMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Nash\\",\\"Elyssa Nash\\",FEMALE,27,Nash,Nash,\\"(empty)\\",Friday,4,\\"elyssa@nash-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562358,\\"sold_product_562358_15777, sold_product_562358_20699\\",\\"sold_product_562358_15777, sold_product_562358_20699\\",\\"60, 18.984\\",\\"60, 18.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"33, 9.68\\",\\"60, 18.984\\",\\"15,777, 20,699\\",\\"Summer dress - Lemon Chiffon, Watch - black\\",\\"Summer dress - Lemon Chiffon, Watch - black\\",\\"1, 1\\",\\"ZO0337303373, ZO0079600796\\",\\"0, 0\\",\\"60, 18.984\\",\\"60, 18.984\\",\\"0, 0\\",\\"ZO0337303373, ZO0079600796\\",79,79,2,2,order,elyssa +DwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes, Men's Accessories\\",\\"Men's Clothing, Men's Shoes, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Bryan\\",\\"Sultan Al Bryan\\",MALE,19,Bryan,Bryan,\\"(empty)\\",Friday,4,\\"sultan al@bryan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Oceanavigations, (empty), Low Tide Media\\",\\"Oceanavigations, (empty), Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",718360,\\"sold_product_718360_16955, sold_product_718360_20827, sold_product_718360_14564, sold_product_718360_21672\\",\\"sold_product_718360_16955, sold_product_718360_20827, sold_product_718360_14564, sold_product_718360_21672\\",\\"200, 165, 10.992, 16.984\\",\\"200, 165, 10.992, 16.984\\",\\"Men's Clothing, Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, (empty), Low Tide Media, Low Tide Media\\",\\"Oceanavigations, (empty), Low Tide Media, Low Tide Media\\",\\"92, 85.813, 4.949, 9\\",\\"200, 165, 10.992, 16.984\\",\\"16,955, 20,827, 14,564, 21,672\\",\\"Classic coat - navy, Boots - black, Hat - light grey multicolor, Polo shirt - black multicolor\\",\\"Classic coat - navy, Boots - black, Hat - light grey multicolor, Polo shirt - black multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0291402914, ZO0483804838, ZO0460304603, ZO0443904439\\",\\"0, 0, 0, 0\\",\\"200, 165, 10.992, 16.984\\",\\"200, 165, 10.992, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0291402914, ZO0483804838, ZO0460304603, ZO0443904439\\",393,393,4,4,order,sultan +JgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Jim,Jim,\\"Jim Rowe\\",\\"Jim Rowe\\",MALE,41,Rowe,Rowe,\\"(empty)\\",Friday,4,\\"jim@rowe-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561969,\\"sold_product_561969_1737, sold_product_561969_14073\\",\\"sold_product_561969_1737, sold_product_561969_14073\\",\\"42, 33\\",\\"42, 33\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"18.906, 17.156\\",\\"42, 33\\",\\"1,737, 14,073\\",\\"Lace-up boots - brown, Briefcase - brown \\",\\"Lace-up boots - brown, Briefcase - brown \\",\\"1, 1\\",\\"ZO0521205212, ZO0316003160\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0521205212, ZO0316003160\\",75,75,2,2,order,jim +JwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Mary,Mary,\\"Mary Garza\\",\\"Mary Garza\\",FEMALE,20,Garza,Garza,\\"(empty)\\",Friday,4,\\"mary@garza-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562011,\\"sold_product_562011_7816, sold_product_562011_13449\\",\\"sold_product_562011_7816, sold_product_562011_13449\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"16.5, 37.5\\",\\"33, 75\\",\\"7,816, 13,449\\",\\"Cardigan - Sky Blue, Ankle boots - black\\",\\"Cardigan - Sky Blue, Ankle boots - black\\",\\"1, 1\\",\\"ZO0068200682, ZO0245202452\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0068200682, ZO0245202452\\",108,108,2,2,order,mary +oAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",EUR,Eddie,Eddie,\\"Eddie Hodges\\",\\"Eddie Hodges\\",MALE,38,Hodges,Hodges,\\"(empty)\\",Friday,4,\\"eddie@hodges-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Microlutions, Low Tide Media, Angeldale\\",\\"Microlutions, Low Tide Media, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",719185,\\"sold_product_719185_18940, sold_product_719185_24924, sold_product_719185_20248, sold_product_719185_24003\\",\\"sold_product_719185_18940, sold_product_719185_24924, sold_product_719185_20248, sold_product_719185_24003\\",\\"14.992, 10.992, 60, 100\\",\\"14.992, 10.992, 60, 100\\",\\"Men's Clothing, Men's Clothing, Men's Accessories, Men's Shoes\\",\\"Men's Clothing, Men's Clothing, Men's Accessories, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Microlutions, Low Tide Media, Low Tide Media, Angeldale\\",\\"Microlutions, Low Tide Media, Low Tide Media, Angeldale\\",\\"7.352, 5.711, 33, 47\\",\\"14.992, 10.992, 60, 100\\",\\"18,940, 24,924, 20,248, 24,003\\",\\"Basic T-shirt - marshmallow, Print T-shirt - navy, Across body bag - black, Lace-ups - Midnight Blue\\",\\"Basic T-shirt - marshmallow, Print T-shirt - navy, Across body bag - black, Lace-ups - Midnight Blue\\",\\"1, 1, 1, 1\\",\\"ZO0118601186, ZO0438904389, ZO0468004680, ZO0684106841\\",\\"0, 0, 0, 0\\",\\"14.992, 10.992, 60, 100\\",\\"14.992, 10.992, 60, 100\\",\\"0, 0, 0, 0\\",\\"ZO0118601186, ZO0438904389, ZO0468004680, ZO0684106841\\",186,186,4,4,order,eddie +rQMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Evans\\",\\"Selena Evans\\",FEMALE,42,Evans,Evans,\\"(empty)\\",Friday,4,\\"selena@evans-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561669,\\"sold_product_561669_11107, sold_product_561669_19052\\",\\"sold_product_561669_11107, sold_product_561669_19052\\",\\"20.984, 14.992\\",\\"20.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"11.117, 7.051\\",\\"20.984, 14.992\\",\\"11,107, 19,052\\",\\"Pyjamas - grey/pink , 2 PACK - Basic T-shirt - black/white\\",\\"Pyjamas - grey/pink , 2 PACK - Basic T-shirt - black/white\\",\\"1, 1\\",\\"ZO0100001000, ZO0642406424\\",\\"0, 0\\",\\"20.984, 14.992\\",\\"20.984, 14.992\\",\\"0, 0\\",\\"ZO0100001000, ZO0642406424\\",\\"35.969\\",\\"35.969\\",2,2,order,selena +rgMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Wood\\",\\"Wilhemina St. Wood\\",FEMALE,17,Wood,Wood,\\"(empty)\\",Friday,4,\\"wilhemina st.@wood-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords, Tigress Enterprises Curvy\\",\\"Spherecords, Tigress Enterprises Curvy\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561225,\\"sold_product_561225_16493, sold_product_561225_13770\\",\\"sold_product_561225_16493, sold_product_561225_13770\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises Curvy\\",\\"Spherecords, Tigress Enterprises Curvy\\",\\"12.492, 22.672\\",\\"24.984, 42\\",\\"16,493, 13,770\\",\\"Dressing gown - pale pink, Summer dress - peacoat\\",\\"Dressing gown - pale pink, Summer dress - peacoat\\",\\"1, 1\\",\\"ZO0660906609, ZO0102801028\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0660906609, ZO0102801028\\",67,67,2,2,order,wilhemina +rwMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Hampton\\",\\"Abigail Hampton\\",FEMALE,46,Hampton,Hampton,\\"(empty)\\",Friday,4,\\"abigail@hampton-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561284,\\"sold_product_561284_13751, sold_product_561284_24729\\",\\"sold_product_561284_13751, sold_product_561284_24729\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"11.5, 8.156\\",\\"24.984, 16.984\\",\\"13,751, 24,729\\",\\"Rucksack - black, Vest - black\\",\\"Rucksack - black, Vest - black\\",\\"1, 1\\",\\"ZO0086300863, ZO0171901719\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0086300863, ZO0171901719\\",\\"41.969\\",\\"41.969\\",2,2,order,abigail +sAMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Rodriguez\\",\\"Gwen Rodriguez\\",FEMALE,26,Rodriguez,Rodriguez,\\"(empty)\\",Friday,4,\\"gwen@rodriguez-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561735,\\"sold_product_561735_15452, sold_product_561735_17692\\",\\"sold_product_561735_15452, sold_product_561735_17692\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"17.813, 9.656\\",\\"33, 20.984\\",\\"15,452, 17,692\\",\\"High heels - black, Long sleeved top - peacoat\\",\\"High heels - black, Long sleeved top - peacoat\\",\\"1, 1\\",\\"ZO0006300063, ZO0058400584\\",\\"0, 0\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"0, 0\\",\\"ZO0006300063, ZO0058400584\\",\\"53.969\\",\\"53.969\\",2,2,order,gwen +sQMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Fleming\\",\\"Abd Fleming\\",MALE,52,Fleming,Fleming,\\"(empty)\\",Friday,4,\\"abd@fleming-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561798,\\"sold_product_561798_23272, sold_product_561798_19140\\",\\"sold_product_561798_23272, sold_product_561798_19140\\",\\"100, 24.984\\",\\"100, 24.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"54, 13.742\\",\\"100, 24.984\\",\\"23,272, 19,140\\",\\"Lace-ups - bianco, Across body bag - black/dark brown\\",\\"Lace-ups - bianco, Across body bag - black/dark brown\\",\\"1, 1\\",\\"ZO0684006840, ZO0469104691\\",\\"0, 0\\",\\"100, 24.984\\",\\"100, 24.984\\",\\"0, 0\\",\\"ZO0684006840, ZO0469104691\\",125,125,2,2,order,abd +3QMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Morrison\\",\\"Elyssa Morrison\\",FEMALE,27,Morrison,Morrison,\\"(empty)\\",Friday,4,\\"elyssa@morrison-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562047,\\"sold_product_562047_19148, sold_product_562047_11032\\",\\"sold_product_562047_19148, sold_product_562047_11032\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"6.109, 38.25\\",\\"11.992, 75\\",\\"19,148, 11,032\\",\\"Clutch - black, Parka - mottled grey\\",\\"Clutch - black, Parka - mottled grey\\",\\"1, 1\\",\\"ZO0203102031, ZO0115701157\\",\\"0, 0\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"0, 0\\",\\"ZO0203102031, ZO0115701157\\",87,87,2,2,order,elyssa +3gMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Reese\\",\\"Muniz Reese\\",MALE,37,Reese,Reese,\\"(empty)\\",Friday,4,\\"muniz@reese-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562107,\\"sold_product_562107_18292, sold_product_562107_23258\\",\\"sold_product_562107_18292, sold_product_562107_23258\\",\\"100, 20.984\\",\\"100, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"52, 10.289\\",\\"100, 20.984\\",\\"18,292, 23,258\\",\\"Snowboard jacket - mottled grey, Jumper - grey/dark blue\\",\\"Snowboard jacket - mottled grey, Jumper - grey/dark blue\\",\\"1, 1\\",\\"ZO0624806248, ZO0579405794\\",\\"0, 0\\",\\"100, 20.984\\",\\"100, 20.984\\",\\"0, 0\\",\\"ZO0624806248, ZO0579405794\\",121,121,2,2,order,muniz +3wMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Samir,Samir,\\"Samir Foster\\",\\"Samir Foster\\",MALE,34,Foster,Foster,\\"(empty)\\",Friday,4,\\"samir@foster-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562290,\\"sold_product_562290_1665, sold_product_562290_24934\\",\\"sold_product_562290_1665, sold_product_562290_24934\\",\\"65, 50\\",\\"65, 50\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"31.203, 22.5\\",\\"65, 50\\",\\"1,665, 24,934\\",\\"Boots - light brown, Lace-up boots - resin coffee\\",\\"Boots - light brown, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0686106861, ZO0403504035\\",\\"0, 0\\",\\"65, 50\\",\\"65, 50\\",\\"0, 0\\",\\"ZO0686106861, ZO0403504035\\",115,115,2,2,order,samir +PAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Harvey\\",\\"Abd Harvey\\",MALE,52,Harvey,Harvey,\\"(empty)\\",Friday,4,\\"abd@harvey-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",720967,\\"sold_product_720967_24934, sold_product_720967_12278, sold_product_720967_14535, sold_product_720967_17629\\",\\"sold_product_720967_24934, sold_product_720967_12278, sold_product_720967_14535, sold_product_720967_17629\\",\\"50, 11.992, 28.984, 24.984\\",\\"50, 11.992, 28.984, 24.984\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, Elitelligence, Elitelligence\\",\\"Low Tide Media, Elitelligence, Elitelligence, Elitelligence\\",\\"22.5, 6, 13.922, 12.992\\",\\"50, 11.992, 28.984, 24.984\\",\\"24,934, 12,278, 14,535, 17,629\\",\\"Lace-up boots - resin coffee, Print T-shirt - black, Boots - brown, Tracksuit bottoms - mottled grey\\",\\"Lace-up boots - resin coffee, Print T-shirt - black, Boots - brown, Tracksuit bottoms - mottled grey\\",\\"1, 1, 1, 1\\",\\"ZO0403504035, ZO0553005530, ZO0519905199, ZO0528605286\\",\\"0, 0, 0, 0\\",\\"50, 11.992, 28.984, 24.984\\",\\"50, 11.992, 28.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0403504035, ZO0553005530, ZO0519905199, ZO0528605286\\",\\"115.938\\",\\"115.938\\",4,4,order,abd +bQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Nash\\",\\"Fitzgerald Nash\\",MALE,11,Nash,Nash,\\"(empty)\\",Friday,4,\\"fitzgerald@nash-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561564,\\"sold_product_561564_6597, sold_product_561564_12482\\",\\"sold_product_561564_6597, sold_product_561564_12482\\",\\"17.984, 60\\",\\"17.984, 60\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"9.531, 30\\",\\"17.984, 60\\",\\"6,597, 12,482\\",\\"Jumper - dark grey multicolor, Across body bag - black\\",\\"Jumper - dark grey multicolor, Across body bag - black\\",\\"1, 1\\",\\"ZO0451204512, ZO0463804638\\",\\"0, 0\\",\\"17.984, 60\\",\\"17.984, 60\\",\\"0, 0\\",\\"ZO0451204512, ZO0463804638\\",78,78,2,2,order,fuzzy +cAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Hopkins\\",\\"Elyssa Hopkins\\",FEMALE,27,Hopkins,Hopkins,\\"(empty)\\",Friday,4,\\"elyssa@hopkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561444,\\"sold_product_561444_21181, sold_product_561444_11368\\",\\"sold_product_561444_21181, sold_product_561444_11368\\",\\"21.984, 33\\",\\"21.984, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"10.563, 15.18\\",\\"21.984, 33\\",\\"21,181, 11,368\\",\\"Cardigan - beige, Slip-ons - beige \\",\\"Cardigan - beige, Slip-ons - beige \\",\\"1, 1\\",\\"ZO0651806518, ZO0369703697\\",\\"0, 0\\",\\"21.984, 33\\",\\"21.984, 33\\",\\"0, 0\\",\\"ZO0651806518, ZO0369703697\\",\\"54.969\\",\\"54.969\\",2,2,order,elyssa +cQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Brady\\",\\"Betty Brady\\",FEMALE,44,Brady,Brady,\\"(empty)\\",Friday,4,\\"betty@brady-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561482,\\"sold_product_561482_8985, sold_product_561482_15058\\",\\"sold_product_561482_8985, sold_product_561482_15058\\",\\"60, 33\\",\\"60, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"27.594, 16.172\\",\\"60, 33\\",\\"8,985, 15,058\\",\\"Light jacket - cognac, Faux leather jacket - pink\\",\\"Light jacket - cognac, Faux leather jacket - pink\\",\\"1, 1\\",\\"ZO0184901849, ZO0174301743\\",\\"0, 0\\",\\"60, 33\\",\\"60, 33\\",\\"0, 0\\",\\"ZO0184901849, ZO0174301743\\",93,93,2,2,order,betty +jgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Mostafa,Mostafa,\\"Mostafa Hopkins\\",\\"Mostafa Hopkins\\",MALE,9,Hopkins,Hopkins,\\"(empty)\\",Friday,4,\\"mostafa@hopkins-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562456,\\"sold_product_562456_11345, sold_product_562456_15411\\",\\"sold_product_562456_11345, sold_product_562456_15411\\",\\"7.988, 16.984\\",\\"7.988, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"3.76, 7.82\\",\\"7.988, 16.984\\",\\"11,345, 15,411\\",\\"Tie - grey, Belt - black\\",\\"Tie - grey, Belt - black\\",\\"1, 1\\",\\"ZO0276302763, ZO0701407014\\",\\"0, 0\\",\\"7.988, 16.984\\",\\"7.988, 16.984\\",\\"0, 0\\",\\"ZO0276302763, ZO0701407014\\",\\"24.984\\",\\"24.984\\",2,2,order,mostafa +jwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Tyler\\",\\"Rabbia Al Tyler\\",FEMALE,5,Tyler,Tyler,\\"(empty)\\",Friday,4,\\"rabbia al@tyler-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562499,\\"sold_product_562499_5501, sold_product_562499_20439\\",\\"sold_product_562499_5501, sold_product_562499_20439\\",\\"75, 22.984\\",\\"75, 22.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"40.5, 11.492\\",\\"75, 22.984\\",\\"5,501, 20,439\\",\\"Ankle boots - Midnight Blue, Blouse - black\\",\\"Ankle boots - Midnight Blue, Blouse - black\\",\\"1, 1\\",\\"ZO0244802448, ZO0105701057\\",\\"0, 0\\",\\"75, 22.984\\",\\"75, 22.984\\",\\"0, 0\\",\\"ZO0244802448, ZO0105701057\\",98,98,2,2,order,rabbia +kAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri James\\",\\"Yuri James\\",MALE,21,James,James,\\"(empty)\\",Friday,4,\\"yuri@james-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562152,\\"sold_product_562152_17873, sold_product_562152_19670\\",\\"sold_product_562152_17873, sold_product_562152_19670\\",\\"10.992, 37\\",\\"10.992, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"5.602, 19.594\\",\\"10.992, 37\\",\\"17,873, 19,670\\",\\"Sports shirt - Seashell, Tracksuit top - black\\",\\"Sports shirt - Seashell, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0616606166, ZO0589705897\\",\\"0, 0\\",\\"10.992, 37\\",\\"10.992, 37\\",\\"0, 0\\",\\"ZO0616606166, ZO0589705897\\",\\"47.969\\",\\"47.969\\",2,2,order,yuri +kQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Gibbs\\",\\"Wilhemina St. Gibbs\\",FEMALE,17,Gibbs,Gibbs,\\"(empty)\\",Friday,4,\\"wilhemina st.@gibbs-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562192,\\"sold_product_562192_18762, sold_product_562192_21085\\",\\"sold_product_562192_18762, sold_product_562192_21085\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"8.656, 7.988\\",\\"16.984, 16.984\\",\\"18,762, 21,085\\",\\"Watch - nude, Vest - black\\",\\"Watch - nude, Vest - black\\",\\"1, 1\\",\\"ZO0079700797, ZO0168201682\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0079700797, ZO0168201682\\",\\"33.969\\",\\"33.969\\",2,2,order,wilhemina +lAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Jim,Jim,\\"Jim Graves\\",\\"Jim Graves\\",MALE,41,Graves,Graves,\\"(empty)\\",Friday,4,\\"jim@graves-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",562528,\\"sold_product_562528_11997, sold_product_562528_14014\\",\\"sold_product_562528_11997, sold_product_562528_14014\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9.172, 20.156\\",\\"16.984, 42\\",\\"11,997, 14,014\\",\\"College - Polo shirt - dark red, Weekend bag - dark brown\\",\\"College - Polo shirt - dark red, Weekend bag - dark brown\\",\\"1, 1\\",\\"ZO0522905229, ZO0608606086\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0522905229, ZO0608606086\\",\\"58.969\\",\\"58.969\\",2,2,order,jim +mgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Lewis\\",\\"Tariq Lewis\\",MALE,25,Lewis,Lewis,\\"(empty)\\",Friday,4,\\"tariq@lewis-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Oceanavigations, Low Tide Media, Elitelligence\\",\\"Oceanavigations, Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",715286,\\"sold_product_715286_19758, sold_product_715286_12040, sold_product_715286_3096, sold_product_715286_13247\\",\\"sold_product_715286_19758, sold_product_715286_12040, sold_product_715286_3096, sold_product_715286_13247\\",\\"50, 24.984, 24.984, 11.992\\",\\"50, 24.984, 24.984, 11.992\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Oceanavigations, Low Tide Media, Elitelligence\\",\\"Oceanavigations, Oceanavigations, Low Tide Media, Elitelligence\\",\\"25, 12.492, 11.25, 5.641\\",\\"50, 24.984, 24.984, 11.992\\",\\"19,758, 12,040, 3,096, 13,247\\",\\"Sweatshirt - grey multicolor, Shirt - navy, Jumper - dark blue, Pyjama bottoms - light grey multicolor\\",\\"Sweatshirt - grey multicolor, Shirt - navy, Jumper - dark blue, Pyjama bottoms - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0299802998, ZO0278702787, ZO0448104481, ZO0611906119\\",\\"0, 0, 0, 0\\",\\"50, 24.984, 24.984, 11.992\\",\\"50, 24.984, 24.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0299802998, ZO0278702787, ZO0448104481, ZO0611906119\\",\\"111.938\\",\\"111.938\\",4,4,order,tariq +vQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Mckenzie\\",\\"Jackson Mckenzie\\",MALE,13,Mckenzie,Mckenzie,\\"(empty)\\",Friday,4,\\"jackson@mckenzie-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561210,\\"sold_product_561210_11019, sold_product_561210_7024\\",\\"sold_product_561210_11019, sold_product_561210_7024\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"16.813, 9\\",\\"33, 16.984\\",\\"11,019, 7,024\\",\\"Sandals - black, 3 PACK - Basic T-shirt - white/black/grey\\",\\"Sandals - black, 3 PACK - Basic T-shirt - white/black/grey\\",\\"1, 1\\",\\"ZO0407404074, ZO0473704737\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0407404074, ZO0473704737\\",\\"49.969\\",\\"49.969\\",2,2,order,jackson +zwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Jim,Jim,\\"Jim Jensen\\",\\"Jim Jensen\\",MALE,41,Jensen,Jensen,\\"(empty)\\",Friday,4,\\"jim@jensen-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562337,\\"sold_product_562337_18692, sold_product_562337_15189\\",\\"sold_product_562337_18692, sold_product_562337_15189\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"12.992, 35.75\\",\\"24.984, 65\\",\\"18,692, 15,189\\",\\"High-top trainers - green, Crossover Strap Bag\\",\\"High-top trainers - green, Crossover Strap Bag\\",\\"1, 1\\",\\"ZO0513005130, ZO0463704637\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0513005130, ZO0463704637\\",90,90,2,2,order,jim +5gMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Lamb\\",\\"Sultan Al Lamb\\",MALE,19,Lamb,Lamb,\\"(empty)\\",Friday,4,\\"sultan al@lamb-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"(empty), Elitelligence, Microlutions, Spritechnologies\\",\\"(empty), Elitelligence, Microlutions, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",713242,\\"sold_product_713242_12836, sold_product_713242_20514, sold_product_713242_19994, sold_product_713242_11377\\",\\"sold_product_713242_12836, sold_product_713242_20514, sold_product_713242_19994, sold_product_713242_11377\\",\\"165, 24.984, 6.988, 10.992\\",\\"165, 24.984, 6.988, 10.992\\",\\"Men's Shoes, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"(empty), Elitelligence, Microlutions, Spritechnologies\\",\\"(empty), Elitelligence, Microlutions, Spritechnologies\\",\\"80.875, 11.5, 3.631, 5.711\\",\\"165, 24.984, 6.988, 10.992\\",\\"12,836, 20,514, 19,994, 11,377\\",\\"Lace-ups - brown, Jumper - black, STAY TRUE 2 PACK - Socks - white/grey/black, Swimming shorts - dark red\\",\\"Lace-ups - brown, Jumper - black, STAY TRUE 2 PACK - Socks - white/grey/black, Swimming shorts - dark red\\",\\"1, 1, 1, 1\\",\\"ZO0482004820, ZO0577105771, ZO0130201302, ZO0629006290\\",\\"0, 0, 0, 0\\",\\"165, 24.984, 6.988, 10.992\\",\\"165, 24.984, 6.988, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0482004820, ZO0577105771, ZO0130201302, ZO0629006290\\",208,208,4,4,order,sultan +JQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Palmer\\",\\"Boris Palmer\\",MALE,36,Palmer,Palmer,\\"(empty)\\",Friday,4,\\"boris@palmer-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561657,\\"sold_product_561657_13024, sold_product_561657_23055\\",\\"sold_product_561657_13024, sold_product_561657_23055\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"12, 21.828\\",\\"24.984, 42\\",\\"13,024, 23,055\\",\\"Tracksuit bottoms - red, Waistcoat - black\\",\\"Tracksuit bottoms - red, Waistcoat - black\\",\\"1, 1\\",\\"ZO0111701117, ZO0288002880\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0111701117, ZO0288002880\\",67,67,2,2,order,boris +JgMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Mccarthy\\",\\"Elyssa Mccarthy\\",FEMALE,27,Mccarthy,Mccarthy,\\"(empty)\\",Friday,4,\\"elyssa@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561254,\\"sold_product_561254_12768, sold_product_561254_20992\\",\\"sold_product_561254_12768, sold_product_561254_20992\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"5.5, 14.211\\",\\"10.992, 28.984\\",\\"12,768, 20,992\\",\\"Snood - nude, Ankle boots - black\\",\\"Snood - nude, Ankle boots - black\\",\\"1, 1\\",\\"ZO0081400814, ZO0022500225\\",\\"0, 0\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"0, 0\\",\\"ZO0081400814, ZO0022500225\\",\\"39.969\\",\\"39.969\\",2,2,order,elyssa +JwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Jimenez\\",\\"Sonya Jimenez\\",FEMALE,28,Jimenez,Jimenez,\\"(empty)\\",Friday,4,\\"sonya@jimenez-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561808,\\"sold_product_561808_17597, sold_product_561808_23716\\",\\"sold_product_561808_17597, sold_product_561808_23716\\",\\"13.992, 60\\",\\"13.992, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"7.27, 29.406\\",\\"13.992, 60\\",\\"17,597, 23,716\\",\\"Print T-shirt - rose, Espadrilles - gold\\",\\"Print T-shirt - rose, Espadrilles - gold\\",\\"1, 1\\",\\"ZO0161401614, ZO0670406704\\",\\"0, 0\\",\\"13.992, 60\\",\\"13.992, 60\\",\\"0, 0\\",\\"ZO0161401614, ZO0670406704\\",74,74,2,2,order,sonya +SAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Baker\\",\\"Abdulraheem Al Baker\\",MALE,33,Baker,Baker,\\"(empty)\\",Friday,4,\\"abdulraheem al@baker-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Microlutions, Spritechnologies\\",\\"Microlutions, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562394,\\"sold_product_562394_11570, sold_product_562394_15124\\",\\"sold_product_562394_11570, sold_product_562394_15124\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Spritechnologies\\",\\"Microlutions, Spritechnologies\\",\\"9.172, 5.5\\",\\"16.984, 10.992\\",\\"11,570, 15,124\\",\\"Print T-shirt - beige, Print T-shirt - dark denim\\",\\"Print T-shirt - beige, Print T-shirt - dark denim\\",\\"1, 1\\",\\"ZO0116701167, ZO0618106181\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0116701167, ZO0618106181\\",\\"27.984\\",\\"27.984\\",2,2,order,abdulraheem +igMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Taylor\\",\\"Wilhemina St. Taylor\\",FEMALE,17,Taylor,Taylor,\\"(empty)\\",Friday,4,\\"wilhemina st.@taylor-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Angeldale, Champion Arts, Gnomehouse, Spherecords\\",\\"Angeldale, Champion Arts, Gnomehouse, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",731424,\\"sold_product_731424_18737, sold_product_731424_18573, sold_product_731424_19121, sold_product_731424_11250\\",\\"sold_product_731424_18737, sold_product_731424_18573, sold_product_731424_19121, sold_product_731424_11250\\",\\"65, 11.992, 65, 7.988\\",\\"65, 11.992, 65, 7.988\\",\\"Women's Shoes, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Champion Arts, Gnomehouse, Spherecords\\",\\"Angeldale, Champion Arts, Gnomehouse, Spherecords\\",\\"31.844, 5.52, 33.781, 3.68\\",\\"65, 11.992, 65, 7.988\\",\\"18,737, 18,573, 19,121, 11,250\\",\\"Lace-ups - black, Print T-shirt - light grey, Ankle boots - khaki, Top - light grey \\",\\"Lace-ups - black, Print T-shirt - light grey, Ankle boots - khaki, Top - light grey \\",\\"1, 1, 1, 1\\",\\"ZO0668706687, ZO0494004940, ZO0326003260, ZO0644206442\\",\\"0, 0, 0, 0\\",\\"65, 11.992, 65, 7.988\\",\\"65, 11.992, 65, 7.988\\",\\"0, 0, 0, 0\\",\\"ZO0668706687, ZO0494004940, ZO0326003260, ZO0644206442\\",150,150,4,4,order,wilhemina +pgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Walters\\",\\"Mary Walters\\",FEMALE,20,Walters,Walters,\\"(empty)\\",Friday,4,\\"mary@walters-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562425,\\"sold_product_562425_22514, sold_product_562425_21356\\",\\"sold_product_562425_22514, sold_product_562425_21356\\",\\"50, 33\\",\\"50, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"26.984, 16.5\\",\\"50, 33\\",\\"22,514, 21,356\\",\\"Ankle boots - grey, Jersey dress - peacoat\\",\\"Ankle boots - grey, Jersey dress - peacoat\\",\\"1, 1\\",\\"ZO0377603776, ZO0050500505\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0377603776, ZO0050500505\\",83,83,2,2,order,mary +pwMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Robert,Robert,\\"Robert Ruiz\\",\\"Robert Ruiz\\",MALE,29,Ruiz,Ruiz,\\"(empty)\\",Friday,4,\\"robert@ruiz-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562464,\\"sold_product_562464_16779, sold_product_562464_24522\\",\\"sold_product_562464_16779, sold_product_562464_24522\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"11.539, 6\\",\\"20.984, 11.992\\",\\"16,779, 24,522\\",\\"Belt - light brown, Long sleeved top - off-white\\",\\"Belt - light brown, Long sleeved top - off-white\\",\\"1, 1\\",\\"ZO0462004620, ZO0568005680\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0462004620, ZO0568005680\\",\\"32.969\\",\\"32.969\\",2,2,order,robert +qAMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Bryant\\",\\"Selena Bryant\\",FEMALE,42,Bryant,Bryant,\\"(empty)\\",Friday,4,\\"selena@bryant-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562516,\\"sold_product_562516_23076, sold_product_562516_13345\\",\\"sold_product_562516_23076, sold_product_562516_13345\\",\\"42, 7.988\\",\\"42, 7.988\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"21, 3.68\\",\\"42, 7.988\\",\\"23,076, 13,345\\",\\"Jeans Skinny Fit - blue, Snood - nude/lilac\\",\\"Jeans Skinny Fit - blue, Snood - nude/lilac\\",\\"1, 1\\",\\"ZO0271102711, ZO0081300813\\",\\"0, 0\\",\\"42, 7.988\\",\\"42, 7.988\\",\\"0, 0\\",\\"ZO0271102711, ZO0081300813\\",\\"49.969\\",\\"49.969\\",2,2,order,selena +qQMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Marwan,Marwan,\\"Marwan Webb\\",\\"Marwan Webb\\",MALE,51,Webb,Webb,\\"(empty)\\",Friday,4,\\"marwan@webb-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562161,\\"sold_product_562161_11902, sold_product_562161_24125\\",\\"sold_product_562161_11902, sold_product_562161_24125\\",\\"13.992, 65\\",\\"13.992, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"7.551, 31.203\\",\\"13.992, 65\\",\\"11,902, 24,125\\",\\"3 PACK - Shorts - black, Lace-up boots - black\\",\\"3 PACK - Shorts - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0477504775, ZO0694406944\\",\\"0, 0\\",\\"13.992, 65\\",\\"13.992, 65\\",\\"0, 0\\",\\"ZO0477504775, ZO0694406944\\",79,79,2,2,order,marwan +qgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Dawson\\",\\"Jim Dawson\\",MALE,41,Dawson,Dawson,\\"(empty)\\",Friday,4,\\"jim@dawson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562211,\\"sold_product_562211_17044, sold_product_562211_19937\\",\\"sold_product_562211_17044, sold_product_562211_19937\\",\\"10.992, 7.988\\",\\"10.992, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"6.039, 4\\",\\"10.992, 7.988\\",\\"17,044, 19,937\\",\\"Sports shirt - bright white, Basic T-shirt - rose\\",\\"Sports shirt - bright white, Basic T-shirt - rose\\",\\"1, 1\\",\\"ZO0616806168, ZO0551805518\\",\\"0, 0\\",\\"10.992, 7.988\\",\\"10.992, 7.988\\",\\"0, 0\\",\\"ZO0616806168, ZO0551805518\\",\\"18.984\\",\\"18.984\\",2,2,order,jim +tAMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Selena,Selena,\\"Selena Graham\\",\\"Selena Graham\\",FEMALE,42,Graham,Graham,\\"(empty)\\",Friday,4,\\"selena@graham-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Pyramidustries active, Low Tide Media\\",\\"Pyramidustries active, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561831,\\"sold_product_561831_14088, sold_product_561831_20294\\",\\"sold_product_561831_14088, sold_product_561831_20294\\",\\"33, 60\\",\\"33, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Low Tide Media\\",\\"Pyramidustries active, Low Tide Media\\",\\"16.813, 33\\",\\"33, 60\\",\\"14,088, 20,294\\",\\"Tights - duffle bag , Lace-ups - grey\\",\\"Tights - duffle bag , Lace-ups - grey\\",\\"1, 1\\",\\"ZO0225102251, ZO0368803688\\",\\"0, 0\\",\\"33, 60\\",\\"33, 60\\",\\"0, 0\\",\\"ZO0225102251, ZO0368803688\\",93,93,2,2,order,selena +tQMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Potter\\",\\"Robbie Potter\\",MALE,48,Potter,Potter,\\"(empty)\\",Friday,4,\\"robbie@potter-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561864,\\"sold_product_561864_14054, sold_product_561864_20029\\",\\"sold_product_561864_14054, sold_product_561864_20029\\",\\"75, 85\\",\\"75, 85\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"36, 43.344\\",\\"75, 85\\",\\"14,054, 20,029\\",\\"Parka - olive, Lace-up boots - Burly Wood\\",\\"Parka - olive, Lace-up boots - Burly Wood\\",\\"1, 1\\",\\"ZO0287002870, ZO0692206922\\",\\"0, 0\\",\\"75, 85\\",\\"75, 85\\",\\"0, 0\\",\\"ZO0287002870, ZO0692206922\\",160,160,2,2,order,robbie +tgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Austin\\",\\"Abigail Austin\\",FEMALE,46,Austin,Austin,\\"(empty)\\",Friday,4,\\"abigail@austin-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561907,\\"sold_product_561907_17540, sold_product_561907_16988\\",\\"sold_product_561907_17540, sold_product_561907_16988\\",\\"60, 60\\",\\"60, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"29.406, 30.594\\",\\"60, 60\\",\\"17,540, 16,988\\",\\"Maxi dress - silver blue, Classic heels - black\\",\\"Maxi dress - silver blue, Classic heels - black\\",\\"1, 1\\",\\"ZO0042300423, ZO0321403214\\",\\"0, 0\\",\\"60, 60\\",\\"60, 60\\",\\"0, 0\\",\\"ZO0042300423, ZO0321403214\\",120,120,2,2,order,abigail +vAMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Kamal,Kamal,\\"Kamal Boone\\",\\"Kamal Boone\\",MALE,39,Boone,Boone,\\"(empty)\\",Friday,4,\\"kamal@boone-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561245,\\"sold_product_561245_18213, sold_product_561245_17792\\",\\"sold_product_561245_18213, sold_product_561245_17792\\",\\"10.992, 34\\",\\"10.992, 34\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.711, 16.313\\",\\"10.992, 34\\",\\"18,213, 17,792\\",\\"Print T-shirt - white, Briefcase - brown\\",\\"Print T-shirt - white, Briefcase - brown\\",\\"1, 1\\",\\"ZO0554305543, ZO0468204682\\",\\"0, 0\\",\\"10.992, 34\\",\\"10.992, 34\\",\\"0, 0\\",\\"ZO0554305543, ZO0468204682\\",\\"44.969\\",\\"44.969\\",2,2,order,kamal +vQMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Rowe\\",\\"Clarice Rowe\\",FEMALE,18,Rowe,Rowe,\\"(empty)\\",Friday,4,\\"clarice@rowe-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561785,\\"sold_product_561785_15024, sold_product_561785_24186\\",\\"sold_product_561785_15024, sold_product_561785_24186\\",\\"60, 33\\",\\"60, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"31.797, 17.813\\",\\"60, 33\\",\\"15,024, 24,186\\",\\"Cocktail dress / Party dress - black, Beaded Occasion Dress\\",\\"Cocktail dress / Party dress - black, Beaded Occasion Dress\\",\\"1, 1\\",\\"ZO0048600486, ZO0155201552\\",\\"0, 0\\",\\"60, 33\\",\\"60, 33\\",\\"0, 0\\",\\"ZO0048600486, ZO0155201552\\",93,93,2,2,order,clarice +YQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Harmon\\",\\"Betty Harmon\\",FEMALE,44,Harmon,Harmon,\\"(empty)\\",Friday,4,\\"betty@harmon-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561505,\\"sold_product_561505_21534, sold_product_561505_20521\\",\\"sold_product_561505_21534, sold_product_561505_20521\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"9.656, 10.703\\",\\"20.984, 20.984\\",\\"21,534, 20,521\\",\\"Vest - black and silver, Hoodie - dark grey multicolor\\",\\"Vest - black and silver, Hoodie - dark grey multicolor\\",\\"1, 1\\",\\"ZO0164001640, ZO0179301793\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0164001640, ZO0179301793\\",\\"41.969\\",\\"41.969\\",2,2,order,betty +agMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Thad,Thad,\\"Thad Gregory\\",\\"Thad Gregory\\",MALE,30,Gregory,Gregory,\\"(empty)\\",Friday,4,\\"thad@gregory-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562403,\\"sold_product_562403_16259, sold_product_562403_15999\\",\\"sold_product_562403_16259, sold_product_562403_15999\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"21, 11.328\\",\\"42, 20.984\\",\\"16,259, 15,999\\",\\"Weekend bag - dark brown , Shirt - charcoal\\",\\"Weekend bag - dark brown , Shirt - charcoal\\",\\"1, 1\\",\\"ZO0471504715, ZO0524405244\\",\\"0, 0\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"0, 0\\",\\"ZO0471504715, ZO0524405244\\",\\"62.969\\",\\"62.969\\",2,2,order,thad +cQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Tariq,Tariq,\\"Tariq King\\",\\"Tariq King\\",MALE,25,King,King,\\"(empty)\\",Friday,4,\\"tariq@king-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561342,\\"sold_product_561342_16000, sold_product_561342_18188\\",\\"sold_product_561342_16000, sold_product_561342_18188\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.289, 17.484\\",\\"20.984, 33\\",\\"16,000, 18,188\\",\\"Shirt - Medium Slate Blue, Smart lace-ups - cognac\\",\\"Shirt - Medium Slate Blue, Smart lace-ups - cognac\\",\\"1, 1\\",\\"ZO0524505245, ZO0388003880\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0524505245, ZO0388003880\\",\\"53.969\\",\\"53.969\\",2,2,order,tariq +1gMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Turner\\",\\"Pia Turner\\",FEMALE,45,Turner,Turner,\\"(empty)\\",Friday,4,\\"pia@turner-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562060,\\"sold_product_562060_15481, sold_product_562060_8432\\",\\"sold_product_562060_15481, sold_product_562060_8432\\",\\"33, 22.984\\",\\"33, 22.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"15.18, 11.953\\",\\"33, 22.984\\",\\"15,481, 8,432\\",\\"Blazer - creme, Vest - black\\",\\"Blazer - creme, Vest - black\\",\\"1, 1\\",\\"ZO0067300673, ZO0062100621\\",\\"0, 0\\",\\"33, 22.984\\",\\"33, 22.984\\",\\"0, 0\\",\\"ZO0067300673, ZO0062100621\\",\\"55.969\\",\\"55.969\\",2,2,order,pia +1wMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Perkins\\",\\"Abigail Perkins\\",FEMALE,46,Perkins,Perkins,\\"(empty)\\",Friday,4,\\"abigail@perkins-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562094,\\"sold_product_562094_4898, sold_product_562094_20011\\",\\"sold_product_562094_4898, sold_product_562094_20011\\",\\"90, 33\\",\\"90, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"45, 15.844\\",\\"90, 33\\",\\"4,898, 20,011\\",\\"Boots - cognac, Jumpsuit - black\\",\\"Boots - cognac, Jumpsuit - black\\",\\"1, 1\\",\\"ZO0374003740, ZO0146401464\\",\\"0, 0\\",\\"90, 33\\",\\"90, 33\\",\\"0, 0\\",\\"ZO0374003740, ZO0146401464\\",123,123,2,2,order,abigail +2AMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Jenkins\\",\\"Robbie Jenkins\\",MALE,48,Jenkins,Jenkins,\\"(empty)\\",Friday,4,\\"robbie@jenkins-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562236,\\"sold_product_562236_24934, sold_product_562236_14426\\",\\"sold_product_562236_24934, sold_product_562236_14426\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"22.5, 5.82\\",\\"50, 10.992\\",\\"24,934, 14,426\\",\\"Lace-up boots - resin coffee, Print T-shirt - grey multicolor\\",\\"Lace-up boots - resin coffee, Print T-shirt - grey multicolor\\",\\"1, 1\\",\\"ZO0403504035, ZO0438304383\\",\\"0, 0\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"0, 0\\",\\"ZO0403504035, ZO0438304383\\",\\"60.969\\",\\"60.969\\",2,2,order,robbie +2QMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Kim\\",\\"Mary Kim\\",FEMALE,20,Kim,Kim,\\"(empty)\\",Friday,4,\\"mary@kim-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562304,\\"sold_product_562304_5945, sold_product_562304_22770\\",\\"sold_product_562304_5945, sold_product_562304_22770\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"11.5, 19.734\\",\\"24.984, 42\\",\\"5,945, 22,770\\",\\"Ankle boots - black, Jumper - black/grey\\",\\"Ankle boots - black, Jumper - black/grey\\",\\"1, 1\\",\\"ZO0025000250, ZO0232702327\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0025000250, ZO0232702327\\",67,67,2,2,order,mary +FwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Thad,Thad,\\"Thad Perkins\\",\\"Thad Perkins\\",MALE,30,Perkins,Perkins,\\"(empty)\\",Friday,4,\\"thad@perkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Microlutions, Angeldale\\",\\"Microlutions, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562390,\\"sold_product_562390_19623, sold_product_562390_12060\\",\\"sold_product_562390_19623, sold_product_562390_12060\\",\\"33, 50\\",\\"33, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Angeldale\\",\\"Microlutions, Angeldale\\",\\"15.844, 25.984\\",\\"33, 50\\",\\"19,623, 12,060\\",\\"Jumper - navy blazer, Lace-ups - black/red\\",\\"Jumper - navy blazer, Lace-ups - black/red\\",\\"1, 1\\",\\"ZO0121701217, ZO0680806808\\",\\"0, 0\\",\\"33, 50\\",\\"33, 50\\",\\"0, 0\\",\\"ZO0121701217, ZO0680806808\\",83,83,2,2,order,thad +3QMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Tariq,Tariq,\\"Tariq Foster\\",\\"Tariq Foster\\",MALE,25,Foster,Foster,\\"(empty)\\",Friday,4,\\"tariq@foster-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Microlutions, Oceanavigations, Low Tide Media\\",\\"Microlutions, Oceanavigations, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",719041,\\"sold_product_719041_17412, sold_product_719041_17871, sold_product_719041_1720, sold_product_719041_15515\\",\\"sold_product_719041_17412, sold_product_719041_17871, sold_product_719041_1720, sold_product_719041_15515\\",\\"14.992, 14.992, 50, 50\\",\\"14.992, 14.992, 50, 50\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Microlutions, Oceanavigations, Low Tide Media, Oceanavigations\\",\\"Microlutions, Oceanavigations, Low Tide Media, Oceanavigations\\",\\"7.5, 6.898, 24.5, 23\\",\\"14.992, 14.992, 50, 50\\",\\"17,412, 17,871, 1,720, 15,515\\",\\"Print T-shirt - black, Print T-shirt - multicolored, Lace-ups - tan, Light jacket - dark blue\\",\\"Print T-shirt - black, Print T-shirt - multicolored, Lace-ups - tan, Light jacket - dark blue\\",\\"1, 1, 1, 1\\",\\"ZO0117701177, ZO0292902929, ZO0387403874, ZO0286902869\\",\\"0, 0, 0, 0\\",\\"14.992, 14.992, 50, 50\\",\\"14.992, 14.992, 50, 50\\",\\"0, 0, 0, 0\\",\\"ZO0117701177, ZO0292902929, ZO0387403874, ZO0286902869\\",130,130,4,4,order,tariq +IAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Lawrence\\",\\"Wagdi Lawrence\\",MALE,15,Lawrence,Lawrence,\\"(empty)\\",Friday,4,\\"wagdi@lawrence-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561604,\\"sold_product_561604_24731, sold_product_561604_19673\\",\\"sold_product_561604_24731, sold_product_561604_19673\\",\\"24.984, 7.988\\",\\"24.984, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"13.242, 4.148\\",\\"24.984, 7.988\\",\\"24,731, 19,673\\",\\"Tracksuit bottoms - mottled grey, Basic T-shirt - black\\",\\"Tracksuit bottoms - mottled grey, Basic T-shirt - black\\",\\"1, 1\\",\\"ZO0529605296, ZO0435404354\\",\\"0, 0\\",\\"24.984, 7.988\\",\\"24.984, 7.988\\",\\"0, 0\\",\\"ZO0529605296, ZO0435404354\\",\\"32.969\\",\\"32.969\\",2,2,order,wagdi +IwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Mary,Mary,\\"Mary Fletcher\\",\\"Mary Fletcher\\",FEMALE,20,Fletcher,Fletcher,\\"(empty)\\",Friday,4,\\"mary@fletcher-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561455,\\"sold_product_561455_12855, sold_product_561455_5588\\",\\"sold_product_561455_12855, sold_product_561455_5588\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"14.492, 19.313\\",\\"28.984, 42\\",\\"12,855, 5,588\\",\\"Blazer - weiu00df/rosa, Ankle boots - teak\\",\\"Blazer - weiu00df/rosa, Ankle boots - teak\\",\\"1, 1\\",\\"ZO0182001820, ZO0018500185\\",\\"0, 0\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"0, 0\\",\\"ZO0182001820, ZO0018500185\\",71,71,2,2,order,mary +JAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Mccarthy\\",\\"Robbie Mccarthy\\",MALE,48,Mccarthy,Mccarthy,\\"(empty)\\",Friday,4,\\"robbie@mccarthy-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561509,\\"sold_product_561509_18177, sold_product_561509_2401\\",\\"sold_product_561509_18177, sold_product_561509_2401\\",\\"10.992, 65\\",\\"10.992, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"5.82, 33.781\\",\\"10.992, 65\\",\\"18,177, 2,401\\",\\"Print T-shirt - navy, Boots - dark brown\\",\\"Print T-shirt - navy, Boots - dark brown\\",\\"1, 1\\",\\"ZO0438404384, ZO0405504055\\",\\"0, 0\\",\\"10.992, 65\\",\\"10.992, 65\\",\\"0, 0\\",\\"ZO0438404384, ZO0405504055\\",76,76,2,2,order,robbie +ggMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Caldwell\\",\\"Fitzgerald Caldwell\\",MALE,11,Caldwell,Caldwell,\\"(empty)\\",Friday,4,\\"fitzgerald@caldwell-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562439,\\"sold_product_562439_18548, sold_product_562439_23459\\",\\"sold_product_562439_18548, sold_product_562439_23459\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.492, 18.141\\",\\"20.984, 33\\",\\"18,548, 23,459\\",\\"Shorts - multicoloured, Smart lace-ups - dark brown\\",\\"Shorts - multicoloured, Smart lace-ups - dark brown\\",\\"1, 1\\",\\"ZO0533105331, ZO0384703847\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0533105331, ZO0384703847\\",\\"53.969\\",\\"53.969\\",2,2,order,fuzzy +gwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Schultz\\",\\"Wilhemina St. Schultz\\",FEMALE,17,Schultz,Schultz,\\"(empty)\\",Friday,4,\\"wilhemina st.@schultz-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562165,\\"sold_product_562165_12949, sold_product_562165_23197\\",\\"sold_product_562165_12949, sold_product_562165_23197\\",\\"33, 60\\",\\"33, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"15.844, 28.203\\",\\"33, 60\\",\\"12,949, 23,197\\",\\"Summer jacket - dark blue, Maxi dress - eclipse\\",\\"Summer jacket - dark blue, Maxi dress - eclipse\\",\\"1, 1\\",\\"ZO0173701737, ZO0337903379\\",\\"0, 0\\",\\"33, 60\\",\\"33, 60\\",\\"0, 0\\",\\"ZO0173701737, ZO0337903379\\",93,93,2,2,order,wilhemina +2AMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Gibbs\\",\\"Jackson Gibbs\\",MALE,13,Gibbs,Gibbs,\\"(empty)\\",Friday,4,\\"jackson@gibbs-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Elitelligence, Spritechnologies, Angeldale\\",\\"Oceanavigations, Elitelligence, Spritechnologies, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",719343,\\"sold_product_719343_24169, sold_product_719343_18391, sold_product_719343_20707, sold_product_719343_21209\\",\\"sold_product_719343_24169, sold_product_719343_18391, sold_product_719343_20707, sold_product_719343_21209\\",\\"46, 24.984, 24.984, 65\\",\\"46, 24.984, 24.984, 65\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Elitelligence, Spritechnologies, Angeldale\\",\\"Oceanavigations, Elitelligence, Spritechnologies, Angeldale\\",\\"22.078, 12.492, 12.492, 31.203\\",\\"46, 24.984, 24.984, 65\\",\\"24,169, 18,391, 20,707, 21,209\\",\\"Jumper - navy, Tracksuit top - mottled grey, Tracksuit top - black, Boots - sand\\",\\"Jumper - navy, Tracksuit top - mottled grey, Tracksuit top - black, Boots - sand\\",\\"1, 1, 1, 1\\",\\"ZO0299002990, ZO0584005840, ZO0628406284, ZO0694306943\\",\\"0, 0, 0, 0\\",\\"46, 24.984, 24.984, 65\\",\\"46, 24.984, 24.984, 65\\",\\"0, 0, 0, 0\\",\\"ZO0299002990, ZO0584005840, ZO0628406284, ZO0694306943\\",161,161,4,4,order,jackson +2wMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Gilbert\\",\\"Abd Gilbert\\",MALE,52,Gilbert,Gilbert,\\"(empty)\\",Friday,4,\\"abd@gilbert-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",718183,\\"sold_product_718183_23834, sold_product_718183_11105, sold_product_718183_22142, sold_product_718183_2361\\",\\"sold_product_718183_23834, sold_product_718183_11105, sold_product_718183_22142, sold_product_718183_2361\\",\\"7.988, 13.992, 24.984, 60\\",\\"7.988, 13.992, 24.984, 60\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Oceanavigations\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Oceanavigations\\",\\"4.07, 7.27, 11.5, 30\\",\\"7.988, 13.992, 24.984, 60\\",\\"23,834, 11,105, 22,142, 2,361\\",\\"3 PACK - Socks - blue/grey, 3 PACK - Shorts - black, Jeans Skinny Fit - petrol, Lace-up boots - dark brown\\",\\"3 PACK - Socks - blue/grey, 3 PACK - Shorts - black, Jeans Skinny Fit - petrol, Lace-up boots - dark brown\\",\\"1, 1, 1, 1\\",\\"ZO0481004810, ZO0476104761, ZO0284102841, ZO0256102561\\",\\"0, 0, 0, 0\\",\\"7.988, 13.992, 24.984, 60\\",\\"7.988, 13.992, 24.984, 60\\",\\"0, 0, 0, 0\\",\\"ZO0481004810, ZO0476104761, ZO0284102841, ZO0256102561\\",\\"106.938\\",\\"106.938\\",4,4,order,abd +wgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Hayes\\",\\"Pia Hayes\\",FEMALE,45,Hayes,Hayes,\\"(empty)\\",Friday,4,\\"pia@hayes-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561215,\\"sold_product_561215_11054, sold_product_561215_25101\\",\\"sold_product_561215_11054, sold_product_561215_25101\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"10.703, 44.188\\",\\"20.984, 85\\",\\"11,054, 25,101\\",\\"Tote bag - cognac/blue, Ankle boots - Blue Violety\\",\\"Tote bag - cognac/blue, Ankle boots - Blue Violety\\",\\"1, 1\\",\\"ZO0196401964, ZO0673906739\\",\\"0, 0\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"0, 0\\",\\"ZO0196401964, ZO0673906739\\",106,106,2,2,order,pia +\\"_QMtOW0BH63Xcmy45m1S\\",ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Gibbs\\",\\"Yasmine Gibbs\\",FEMALE,43,Gibbs,Gibbs,\\"(empty)\\",Friday,4,\\"yasmine@gibbs-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561377,\\"sold_product_561377_24916, sold_product_561377_22033\\",\\"sold_product_561377_24916, sold_product_561377_22033\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"13.742, 21.406\\",\\"24.984, 42\\",\\"24,916, 22,033\\",\\"A-line skirt - blue denim, Summer jacket - bordeaux/black\\",\\"A-line skirt - blue denim, Summer jacket - bordeaux/black\\",\\"1, 1\\",\\"ZO0147901479, ZO0185401854\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0147901479, ZO0185401854\\",67,67,2,2,order,yasmine +EwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Romero\\",\\"Wilhemina St. Romero\\",FEMALE,17,Romero,Romero,\\"(empty)\\",Friday,4,\\"wilhemina st.@romero-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises, Spherecords\\",\\"Pyramidustries, Tigress Enterprises, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",726377,\\"sold_product_726377_16552, sold_product_726377_8806, sold_product_726377_14193, sold_product_726377_22412\\",\\"sold_product_726377_16552, sold_product_726377_8806, sold_product_726377_14193, sold_product_726377_22412\\",\\"14.992, 42, 20.984, 33\\",\\"14.992, 42, 20.984, 33\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Tigress Enterprises, Spherecords, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises, Spherecords, Tigress Enterprises\\",\\"6.898, 20.578, 11.117, 17.156\\",\\"14.992, 42, 20.984, 33\\",\\"16,552, 8,806, 14,193, 22,412\\",\\"Print T-shirt - black, Jumper - peacoat, Shift dress - dark blue, Jumper dress - black/grey\\",\\"Print T-shirt - black, Jumper - peacoat, Shift dress - dark blue, Jumper dress - black/grey\\",\\"1, 1, 1, 1\\",\\"ZO0167001670, ZO0070900709, ZO0636006360, ZO0051900519\\",\\"0, 0, 0, 0\\",\\"14.992, 42, 20.984, 33\\",\\"14.992, 42, 20.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0167001670, ZO0070900709, ZO0636006360, ZO0051900519\\",\\"110.938\\",\\"110.938\\",4,4,order,wilhemina +GgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes, Women's Accessories\\",\\"Women's Clothing, Women's Shoes, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Gomez\\",\\"Rabbia Al Gomez\\",FEMALE,5,Gomez,Gomez,\\"(empty)\\",Friday,4,\\"rabbia al@gomez-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",730333,\\"sold_product_730333_18676, sold_product_730333_12860, sold_product_730333_15759, sold_product_730333_24348\\",\\"sold_product_730333_18676, sold_product_730333_12860, sold_product_730333_15759, sold_product_730333_24348\\",\\"28.984, 50, 30.984, 50\\",\\"28.984, 50, 30.984, 50\\",\\"Women's Clothing, Women's Shoes, Women's Accessories, Women's Clothing\\",\\"Women's Clothing, Women's Shoes, Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Oceanavigations\\",\\"13.633, 23, 15.492, 26.484\\",\\"28.984, 50, 30.984, 50\\",\\"18,676, 12,860, 15,759, 24,348\\",\\"Blouse - peach whip, Wedge sandals - gold, Rucksack - black, Summer dress - dark blue\\",\\"Blouse - peach whip, Wedge sandals - gold, Rucksack - black, Summer dress - dark blue\\",\\"1, 1, 1, 1\\",\\"ZO0065000650, ZO0241802418, ZO0098400984, ZO0262102621\\",\\"0, 0, 0, 0\\",\\"28.984, 50, 30.984, 50\\",\\"28.984, 50, 30.984, 50\\",\\"0, 0, 0, 0\\",\\"ZO0065000650, ZO0241802418, ZO0098400984, ZO0262102621\\",160,160,4,4,order,rabbia +agMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Harvey\\",\\"Ahmed Al Harvey\\",MALE,4,Harvey,Harvey,\\"(empty)\\",Friday,4,\\"ahmed al@harvey-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",Microlutions,Microlutions,\\"Jun 20, 2019 @ 00:00:00.000\\",561542,\\"sold_product_561542_6512, sold_product_561542_17698\\",\\"sold_product_561542_6512, sold_product_561542_17698\\",\\"33, 75\\",\\"33, 75\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Microlutions\\",\\"Microlutions, Microlutions\\",\\"16.5, 37.5\\",\\"33, 75\\",\\"6,512, 17,698\\",\\"Jeans Tapered Fit - black denim, Faux leather jacket - black\\",\\"Jeans Tapered Fit - black denim, Faux leather jacket - black\\",\\"1, 1\\",\\"ZO0113701137, ZO0114201142\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0113701137, ZO0114201142\\",108,108,2,2,order,ahmed +awMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Pratt\\",\\"Jackson Pratt\\",MALE,13,Pratt,Pratt,\\"(empty)\\",Friday,4,\\"jackson@pratt-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561586,\\"sold_product_561586_13927, sold_product_561586_1557\\",\\"sold_product_561586_13927, sold_product_561586_1557\\",\\"42, 60\\",\\"42, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"21.406, 31.188\\",\\"42, 60\\",\\"13,927, 1,557\\",\\"Bomber Jacket - khaki, Lace-up boots - brown\\",\\"Bomber Jacket - khaki, Lace-up boots - brown\\",\\"1, 1\\",\\"ZO0540605406, ZO0401104011\\",\\"0, 0\\",\\"42, 60\\",\\"42, 60\\",\\"0, 0\\",\\"ZO0540605406, ZO0401104011\\",102,102,2,2,order,jackson +bgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Mcdonald\\",\\"Gwen Mcdonald\\",FEMALE,26,Mcdonald,Mcdonald,\\"(empty)\\",Friday,4,\\"gwen@mcdonald-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561442,\\"sold_product_561442_7232, sold_product_561442_10893\\",\\"sold_product_561442_7232, sold_product_561442_10893\\",\\"33, 9.992\\",\\"33, 9.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"15.508, 4.699\\",\\"33, 9.992\\",\\"7,232, 10,893\\",\\"Winter boots - black, 2 PACK - Leggings - black\\",\\"Winter boots - black, 2 PACK - Leggings - black\\",\\"1, 1\\",\\"ZO0030900309, ZO0212302123\\",\\"0, 0\\",\\"33, 9.992\\",\\"33, 9.992\\",\\"0, 0\\",\\"ZO0030900309, ZO0212302123\\",\\"42.969\\",\\"42.969\\",2,2,order,gwen +bwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Hampton\\",\\"Ahmed Al Hampton\\",MALE,4,Hampton,Hampton,\\"(empty)\\",Friday,4,\\"ahmed al@hampton-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561484,\\"sold_product_561484_24353, sold_product_561484_18666\\",\\"sold_product_561484_24353, sold_product_561484_18666\\",\\"75, 14.992\\",\\"75, 14.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"34.5, 7.199\\",\\"75, 14.992\\",\\"24,353, 18,666\\",\\"Lace-up boots - black/brown, Long sleeved top - white\\",\\"Lace-up boots - black/brown, Long sleeved top - white\\",\\"1, 1\\",\\"ZO0400304003, ZO0559405594\\",\\"0, 0\\",\\"75, 14.992\\",\\"75, 14.992\\",\\"0, 0\\",\\"ZO0400304003, ZO0559405594\\",90,90,2,2,order,ahmed +cAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Smith\\",\\"Clarice Smith\\",FEMALE,18,Smith,Smith,\\"(empty)\\",Friday,4,\\"clarice@smith-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Gnomehouse mom, Pyramidustries\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561325,\\"sold_product_561325_21224, sold_product_561325_11110\\",\\"sold_product_561325_21224, sold_product_561325_11110\\",\\"28.984, 28.984\\",\\"28.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Gnomehouse mom, Pyramidustries\\",\\"14.781, 15.359\\",\\"28.984, 28.984\\",\\"21,224, 11,110\\",\\"Blouse - red, Tracksuit top - black\\",\\"Blouse - red, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0234802348, ZO0178001780\\",\\"0, 0\\",\\"28.984, 28.984\\",\\"28.984, 28.984\\",\\"0, 0\\",\\"ZO0234802348, ZO0178001780\\",\\"57.969\\",\\"57.969\\",2,2,order,clarice +jgMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Cross\\",\\"Abigail Cross\\",FEMALE,46,Cross,Cross,\\"(empty)\\",Friday,4,\\"abigail@cross-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562463,\\"sold_product_562463_16341, sold_product_562463_25127\\",\\"sold_product_562463_16341, sold_product_562463_25127\\",\\"65, 50\\",\\"65, 50\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"29.906, 27.484\\",\\"65, 50\\",\\"16,341, 25,127\\",\\"Handbag - black, Maxi dress - red ochre\\",\\"Handbag - black, Maxi dress - red ochre\\",\\"1, 1\\",\\"ZO0700107001, ZO0341303413\\",\\"0, 0\\",\\"65, 50\\",\\"65, 50\\",\\"0, 0\\",\\"ZO0700107001, ZO0341303413\\",115,115,2,2,order,abigail +jwMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Hansen\\",\\"Selena Hansen\\",FEMALE,42,Hansen,Hansen,\\"(empty)\\",Friday,4,\\"selena@hansen-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",Spherecords,Spherecords,\\"Jun 20, 2019 @ 00:00:00.000\\",562513,\\"sold_product_562513_8078, sold_product_562513_9431\\",\\"sold_product_562513_8078, sold_product_562513_9431\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spherecords\\",\\"Spherecords, Spherecords\\",\\"5.82, 12\\",\\"10.992, 24.984\\",\\"8,078, 9,431\\",\\"Long sleeved top - white, Pyjama set - grey/pink\\",\\"Long sleeved top - white, Pyjama set - grey/pink\\",\\"1, 1\\",\\"ZO0640906409, ZO0660206602\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0640906409, ZO0660206602\\",\\"35.969\\",\\"35.969\\",2,2,order,selena +kAMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Estrada\\",\\"Abd Estrada\\",MALE,52,Estrada,Estrada,\\"(empty)\\",Friday,4,\\"abd@estrada-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562166,\\"sold_product_562166_16566, sold_product_562166_16701\\",\\"sold_product_562166_16566, sold_product_562166_16701\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"39, 7.988\\",\\"75, 16.984\\",\\"16,566, 16,701\\",\\"Boots - grey, 3 PACK - Basic T-shirt - white\\",\\"Boots - grey, 3 PACK - Basic T-shirt - white\\",\\"1, 1\\",\\"ZO0692406924, ZO0473504735\\",\\"0, 0\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"0, 0\\",\\"ZO0692406924, ZO0473504735\\",92,92,2,2,order,abd +mgMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Eddie,Eddie,\\"Eddie King\\",\\"Eddie King\\",MALE,38,King,King,\\"(empty)\\",Friday,4,\\"eddie@king-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spherecords, Elitelligence, Oceanavigations\\",\\"Low Tide Media, Spherecords, Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",714021,\\"sold_product_714021_21164, sold_product_714021_13240, sold_product_714021_1704, sold_product_714021_15243\\",\\"sold_product_714021_21164, sold_product_714021_13240, sold_product_714021_1704, sold_product_714021_15243\\",\\"10.992, 7.988, 33, 65\\",\\"10.992, 7.988, 33, 65\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Spherecords, Elitelligence, Oceanavigations\\",\\"Low Tide Media, Spherecords, Elitelligence, Oceanavigations\\",\\"5.93, 3.84, 15.508, 31.203\\",\\"10.992, 7.988, 33, 65\\",\\"21,164, 13,240, 1,704, 15,243\\",\\"Long sleeved top - dark blue, 5 PACK - Socks - black, High-top trainers - black, Trousers - bordeaux multicolor\\",\\"Long sleeved top - dark blue, 5 PACK - Socks - black, High-top trainers - black, Trousers - bordeaux multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0436904369, ZO0664106641, ZO0514805148, ZO0283302833\\",\\"0, 0, 0, 0\\",\\"10.992, 7.988, 33, 65\\",\\"10.992, 7.988, 33, 65\\",\\"0, 0, 0, 0\\",\\"ZO0436904369, ZO0664106641, ZO0514805148, ZO0283302833\\",\\"116.938\\",\\"116.938\\",4,4,order,eddie +FgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Men's Shoes\\",\\"Women's Accessories, Men's Shoes\\",EUR,Frances,Frances,\\"Frances Butler\\",\\"Frances Butler\\",FEMALE,49,Butler,Butler,\\"(empty)\\",Friday,4,\\"frances@butler-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",Oceanavigations,Oceanavigations,\\"Jun 20, 2019 @ 00:00:00.000\\",562041,\\"sold_product_562041_17117, sold_product_562041_2398\\",\\"sold_product_562041_17117, sold_product_562041_2398\\",\\"110, 60\\",\\"110, 60\\",\\"Women's Accessories, Men's Shoes\\",\\"Women's Accessories, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"52.813, 29.406\\",\\"110, 60\\",\\"17,117, 2,398\\",\\"Weekend bag - cognac, Lace-ups - Midnight Blue\\",\\"Weekend bag - cognac, Lace-ups - Midnight Blue\\",\\"1, 1\\",\\"ZO0320303203, ZO0252802528\\",\\"0, 0\\",\\"110, 60\\",\\"110, 60\\",\\"0, 0\\",\\"ZO0320303203, ZO0252802528\\",170,170,2,2,order,frances +FwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Stewart\\",\\"Rabbia Al Stewart\\",FEMALE,5,Stewart,Stewart,\\"(empty)\\",Friday,4,\\"rabbia al@stewart-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562116,\\"sold_product_562116_5339, sold_product_562116_17619\\",\\"sold_product_562116_5339, sold_product_562116_17619\\",\\"75, 60\\",\\"75, 60\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"38.25, 29.406\\",\\"75, 60\\",\\"5,339, 17,619\\",\\"Ankle boots - black, Lace-ups - silver\\",\\"Ankle boots - black, Lace-ups - silver\\",\\"1, 1\\",\\"ZO0247002470, ZO0322703227\\",\\"0, 0\\",\\"75, 60\\",\\"75, 60\\",\\"0, 0\\",\\"ZO0247002470, ZO0322703227\\",135,135,2,2,order,rabbia +GAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",EUR,Robert,Robert,\\"Robert Hart\\",\\"Robert Hart\\",MALE,29,Hart,Hart,\\"(empty)\\",Friday,4,\\"robert@hart-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562281,\\"sold_product_562281_17836, sold_product_562281_15582\\",\\"sold_product_562281_17836, sold_product_562281_15582\\",\\"85, 13.992\\",\\"85, 13.992\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"42.5, 7.691\\",\\"85, 13.992\\",\\"17,836, 15,582\\",\\"Casual lace-ups - black, Belt - dark brown \\",\\"Casual lace-ups - black, Belt - dark brown \\",\\"1, 1\\",\\"ZO0683106831, ZO0317803178\\",\\"0, 0\\",\\"85, 13.992\\",\\"85, 13.992\\",\\"0, 0\\",\\"ZO0683106831, ZO0317803178\\",99,99,2,2,order,robert +IwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,George,George,\\"George King\\",\\"George King\\",MALE,32,King,King,\\"(empty)\\",Friday,4,\\"george@king-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562442,\\"sold_product_562442_24776, sold_product_562442_20891\\",\\"sold_product_562442_24776, sold_product_562442_20891\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"15.844, 4\\",\\"33, 7.988\\",\\"24,776, 20,891\\",\\"Watch - black, Basic T-shirt - khaki\\",\\"Watch - black, Basic T-shirt - khaki\\",\\"1, 1\\",\\"ZO0126901269, ZO0563705637\\",\\"0, 0\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"0, 0\\",\\"ZO0126901269, ZO0563705637\\",\\"40.969\\",\\"40.969\\",2,2,order,george +JAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Brady\\",\\"Fitzgerald Brady\\",MALE,11,Brady,Brady,\\"(empty)\\",Friday,4,\\"fitzgerald@brady-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562149,\\"sold_product_562149_16955, sold_product_562149_6827\\",\\"sold_product_562149_16955, sold_product_562149_6827\\",\\"200, 33\\",\\"200, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"92, 17.156\\",\\"200, 33\\",\\"16,955, 6,827\\",\\"Classic coat - navy, Denim jacket - black denim\\",\\"Classic coat - navy, Denim jacket - black denim\\",\\"1, 1\\",\\"ZO0291402914, ZO0539305393\\",\\"0, 0\\",\\"200, 33\\",\\"200, 33\\",\\"0, 0\\",\\"ZO0291402914, ZO0539305393\\",233,233,2,2,order,fuzzy +JgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Haynes\\",\\"George Haynes\\",MALE,32,Haynes,Haynes,\\"(empty)\\",Friday,4,\\"george@haynes-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",562553,\\"sold_product_562553_15384, sold_product_562553_11950\\",\\"sold_product_562553_15384, sold_product_562553_11950\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"17.156, 5.391\\",\\"33, 10.992\\",\\"15,384, 11,950\\",\\"Denim jacket - grey, Seratonin - Long sleeved top - dark blue\\",\\"Denim jacket - grey, Seratonin - Long sleeved top - dark blue\\",\\"1, 1\\",\\"ZO0525005250, ZO0547205472\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0525005250, ZO0547205472\\",\\"43.969\\",\\"43.969\\",2,2,order,george +bAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Bradley\\",\\"Hicham Bradley\\",MALE,8,Bradley,Bradley,\\"(empty)\\",Friday,4,\\"hicham@bradley-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561677,\\"sold_product_561677_13662, sold_product_561677_20832\\",\\"sold_product_561677_13662, sold_product_561677_20832\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"9.656, 14.781\\",\\"20.984, 28.984\\",\\"13,662, 20,832\\",\\"Tracksuit bottoms - dark blue, Sweatshirt - black\\",\\"Tracksuit bottoms - dark blue, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0525605256, ZO0126001260\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0525605256, ZO0126001260\\",\\"49.969\\",\\"49.969\\",2,2,order,hicham +bQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Ramsey\\",\\"Abd Ramsey\\",MALE,52,Ramsey,Ramsey,\\"(empty)\\",Friday,4,\\"abd@ramsey-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561217,\\"sold_product_561217_17853, sold_product_561217_20690\\",\\"sold_product_561217_17853, sold_product_561217_20690\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"11.25, 18.141\\",\\"24.984, 33\\",\\"17,853, 20,690\\",\\"Shirt - white blue, Sweatshirt - black\\",\\"Shirt - white blue, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0417904179, ZO0125501255\\",\\"0, 0\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"0, 0\\",\\"ZO0417904179, ZO0125501255\\",\\"57.969\\",\\"57.969\\",2,2,order,abd +bgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Tyler\\",\\"Rabbia Al Tyler\\",FEMALE,5,Tyler,Tyler,\\"(empty)\\",Friday,4,\\"rabbia al@tyler-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561251,\\"sold_product_561251_23966, sold_product_561251_18479\\",\\"sold_product_561251_23966, sold_product_561251_18479\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"13.492, 29.906\\",\\"24.984, 65\\",\\"23,966, 18,479\\",\\"Sweatshirt - grey/off-white, Ankle boots - black\\",\\"Sweatshirt - grey/off-white, Ankle boots - black\\",\\"1, 1\\",\\"ZO0502905029, ZO0249102491\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0502905029, ZO0249102491\\",90,90,2,2,order,rabbia +bwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Muniz,Muniz,\\"Muniz Pope\\",\\"Muniz Pope\\",MALE,37,Pope,Pope,\\"(empty)\\",Friday,4,\\"muniz@pope-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561291,\\"sold_product_561291_11706, sold_product_561291_1176\\",\\"sold_product_561291_11706, sold_product_561291_1176\\",\\"100, 42\\",\\"100, 42\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"49, 21.828\\",\\"100, 42\\",\\"11,706, 1,176\\",\\"Weekend bag - dark brown, Trainers - black\\",\\"Weekend bag - dark brown, Trainers - black\\",\\"1, 1\\",\\"ZO0701907019, ZO0395203952\\",\\"0, 0\\",\\"100, 42\\",\\"100, 42\\",\\"0, 0\\",\\"ZO0701907019, ZO0395203952\\",142,142,2,2,order,muniz +cAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Morris\\",\\"Boris Morris\\",MALE,36,Morris,Morris,\\"(empty)\\",Friday,4,\\"boris@morris-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561316,\\"sold_product_561316_18944, sold_product_561316_6709\\",\\"sold_product_561316_18944, sold_product_561316_6709\\",\\"24.984, 90\\",\\"24.984, 90\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.5, 45\\",\\"24.984, 90\\",\\"18,944, 6,709\\",\\"Shirt - white, Classic coat - navy\\",\\"Shirt - white, Classic coat - navy\\",\\"1, 1\\",\\"ZO0524305243, ZO0290702907\\",\\"0, 0\\",\\"24.984, 90\\",\\"24.984, 90\\",\\"0, 0\\",\\"ZO0524305243, ZO0290702907\\",115,115,2,2,order,boris +cQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Lewis\\",\\"Wilhemina St. Lewis\\",FEMALE,17,Lewis,Lewis,\\"(empty)\\",Friday,4,\\"wilhemina st.@lewis-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561769,\\"sold_product_561769_18758, sold_product_561769_12114\\",\\"sold_product_561769_18758, sold_product_561769_12114\\",\\"33, 29.984\\",\\"33, 29.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"14.852, 16.188\\",\\"33, 29.984\\",\\"18,758, 12,114\\",\\"Cardigan - sand multicolor/black, Jersey dress - black/white\\",\\"Cardigan - sand multicolor/black, Jersey dress - black/white\\",\\"1, 1\\",\\"ZO0106601066, ZO0038300383\\",\\"0, 0\\",\\"33, 29.984\\",\\"33, 29.984\\",\\"0, 0\\",\\"ZO0106601066, ZO0038300383\\",\\"62.969\\",\\"62.969\\",2,2,order,wilhemina +cgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Clarice,Clarice,\\"Clarice Adams\\",\\"Clarice Adams\\",FEMALE,18,Adams,Adams,\\"(empty)\\",Friday,4,\\"clarice@adams-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561784,\\"sold_product_561784_19114, sold_product_561784_21141\\",\\"sold_product_561784_19114, sold_product_561784_21141\\",\\"7.988, 21.984\\",\\"7.988, 21.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"4.309, 11.867\\",\\"7.988, 21.984\\",\\"19,114, 21,141\\",\\"Top - black/white, Xanadu - Across body bag - black\\",\\"Top - black/white, Xanadu - Across body bag - black\\",\\"1, 1\\",\\"ZO0644306443, ZO0205102051\\",\\"0, 0\\",\\"7.988, 21.984\\",\\"7.988, 21.984\\",\\"0, 0\\",\\"ZO0644306443, ZO0205102051\\",\\"29.984\\",\\"29.984\\",2,2,order,clarice +cwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Carr\\",\\"Elyssa Carr\\",FEMALE,27,Carr,Carr,\\"(empty)\\",Friday,4,\\"elyssa@carr-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561815,\\"sold_product_561815_20116, sold_product_561815_24086\\",\\"sold_product_561815_20116, sold_product_561815_24086\\",\\"33, 21.984\\",\\"33, 21.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"15.844, 11.43\\",\\"33, 21.984\\",\\"20,116, 24,086\\",\\"Handbag - Blue Violety, Long sleeved top - peacoat\\",\\"Handbag - Blue Violety, Long sleeved top - peacoat\\",\\"1, 1\\",\\"ZO0091100911, ZO0231102311\\",\\"0, 0\\",\\"33, 21.984\\",\\"33, 21.984\\",\\"0, 0\\",\\"ZO0091100911, ZO0231102311\\",\\"54.969\\",\\"54.969\\",2,2,order,elyssa +ngMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Mclaughlin\\",\\"Rabbia Al Mclaughlin\\",FEMALE,5,Mclaughlin,Mclaughlin,\\"(empty)\\",Friday,4,\\"rabbia al@mclaughlin-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spherecords, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"Spherecords, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"Jun 20, 2019 @ 00:00:00.000\\",724573,\\"sold_product_724573_12483, sold_product_724573_21459, sold_product_724573_9400, sold_product_724573_16900\\",\\"sold_product_724573_12483, sold_product_724573_21459, sold_product_724573_9400, sold_product_724573_16900\\",\\"24.984, 42, 24.984, 24.984\\",\\"24.984, 42, 24.984, 24.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"Spherecords, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"12.742, 21.828, 12.992, 13.742\\",\\"24.984, 42, 24.984, 24.984\\",\\"12,483, 21,459, 9,400, 16,900\\",\\"Jumper - beige multicolor, Summer dress - black, Jersey dress - navy, Jersey dress - black/white\\",\\"Jumper - beige multicolor, Summer dress - black, Jersey dress - navy, Jersey dress - black/white\\",\\"1, 1, 1, 1\\",\\"ZO0653306533, ZO0261702617, ZO0036800368, ZO0490704907\\",\\"0, 0, 0, 0\\",\\"24.984, 42, 24.984, 24.984\\",\\"24.984, 42, 24.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0653306533, ZO0261702617, ZO0036800368, ZO0490704907\\",\\"116.938\\",\\"116.938\\",4,4,order,rabbia +zwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Hernandez\\",\\"Wilhemina St. Hernandez\\",FEMALE,17,Hernandez,Hernandez,\\"(empty)\\",Friday,4,\\"wilhemina st.@hernandez-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561937,\\"sold_product_561937_23134, sold_product_561937_14750\\",\\"sold_product_561937_23134, sold_product_561937_14750\\",\\"7.988, 50\\",\\"7.988, 50\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"3.68, 26.984\\",\\"7.988, 50\\",\\"23,134, 14,750\\",\\"Basic T-shirt - dark grey multicolor, High heeled sandals - pink\\",\\"Basic T-shirt - dark grey multicolor, High heeled sandals - pink\\",\\"1, 1\\",\\"ZO0638606386, ZO0371503715\\",\\"0, 0\\",\\"7.988, 50\\",\\"7.988, 50\\",\\"0, 0\\",\\"ZO0638606386, ZO0371503715\\",\\"57.969\\",\\"57.969\\",2,2,order,wilhemina +0AMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Bryan\\",\\"Youssef Bryan\\",MALE,31,Bryan,Bryan,\\"(empty)\\",Friday,4,\\"youssef@bryan-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561966,\\"sold_product_561966_23691, sold_product_561966_20112\\",\\"sold_product_561966_23691, sold_product_561966_20112\\",\\"28.984, 25.984\\",\\"28.984, 25.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"13.922, 12.477\\",\\"28.984, 25.984\\",\\"23,691, 20,112\\",\\"Sweatshirt - black, Shirt - blue\\",\\"Sweatshirt - black, Shirt - blue\\",\\"1, 1\\",\\"ZO0124201242, ZO0413604136\\",\\"0, 0\\",\\"28.984, 25.984\\",\\"28.984, 25.984\\",\\"0, 0\\",\\"ZO0124201242, ZO0413604136\\",\\"54.969\\",\\"54.969\\",2,2,order,youssef +0QMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Cortez\\",\\"Stephanie Cortez\\",FEMALE,6,Cortez,Cortez,\\"(empty)\\",Friday,4,\\"stephanie@cortez-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561522,\\"sold_product_561522_15509, sold_product_561522_16044\\",\\"sold_product_561522_15509, sold_product_561522_16044\\",\\"11.992, 50\\",\\"11.992, 50\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"6.469, 25\\",\\"11.992, 50\\",\\"15,509, 16,044\\",\\"Scarf - grey, Summer dress - navy blazer\\",\\"Scarf - grey, Summer dress - navy blazer\\",\\"1, 1\\",\\"ZO0194601946, ZO0340403404\\",\\"0, 0\\",\\"11.992, 50\\",\\"11.992, 50\\",\\"0, 0\\",\\"ZO0194601946, ZO0340403404\\",\\"61.969\\",\\"61.969\\",2,2,order,stephanie +7wMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Gregory\\",\\"Abd Gregory\\",MALE,52,Gregory,Gregory,\\"(empty)\\",Friday,4,\\"abd@gregory-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561330,\\"sold_product_561330_18701, sold_product_561330_11884\\",\\"sold_product_561330_18701, sold_product_561330_11884\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"34.438, 10.578\\",\\"65, 22.984\\",\\"18,701, 11,884\\",\\"Lace-up boots - taupe, Jumper - navy\\",\\"Lace-up boots - taupe, Jumper - navy\\",\\"1, 1\\",\\"ZO0691106911, ZO0295902959\\",\\"0, 0\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"0, 0\\",\\"ZO0691106911, ZO0295902959\\",88,88,2,2,order,abd +gwMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Jimenez\\",\\"Wilhemina St. Jimenez\\",FEMALE,17,Jimenez,Jimenez,\\"(empty)\\",Friday,4,\\"wilhemina st.@jimenez-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"{ + \\"\\"coordinates\\"\\": [ + 7.4, + 43.7 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",726879,\\"sold_product_726879_7151, sold_product_726879_13075, sold_product_726879_13564, sold_product_726879_15989\\",\\"sold_product_726879_7151, sold_product_726879_13075, sold_product_726879_13564, sold_product_726879_15989\\",\\"42, 10.992, 16.984, 28.984\\",\\"42, 10.992, 16.984, 28.984\\",\\"Women's Shoes, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Spherecords, Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Spherecords, Tigress Enterprises, Tigress Enterprises\\",\\"22.25, 5.82, 9.344, 13.633\\",\\"42, 10.992, 16.984, 28.984\\",\\"7,151, 13,075, 13,564, 15,989\\",\\"Ankle boots - black, Body - black, Clutch - black, A-line skirt - blue\\",\\"Ankle boots - black, Body - black, Clutch - black, A-line skirt - blue\\",\\"1, 1, 1, 1\\",\\"ZO0020100201, ZO0659406594, ZO0087900879, ZO0032700327\\",\\"0, 0, 0, 0\\",\\"42, 10.992, 16.984, 28.984\\",\\"42, 10.992, 16.984, 28.984\\",\\"0, 0, 0, 0\\",\\"ZO0020100201, ZO0659406594, ZO0087900879, ZO0032700327\\",\\"98.938\\",\\"98.938\\",4,4,order,wilhemina +hAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Abbott\\",\\"Elyssa Abbott\\",FEMALE,27,Abbott,Abbott,\\"(empty)\\",Friday,4,\\"elyssa@abbott-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Tigress Enterprises, Oceanavigations, Champion Arts\\",\\"Tigress Enterprises, Oceanavigations, Champion Arts\\",\\"Jun 20, 2019 @ 00:00:00.000\\",725944,\\"sold_product_725944_16292, sold_product_725944_18842, sold_product_725944_25188, sold_product_725944_15449\\",\\"sold_product_725944_16292, sold_product_725944_18842, sold_product_725944_25188, sold_product_725944_15449\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"Women's Accessories, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Accessories, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"11.25, 8.156, 15.648, 5.281\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"16,292, 18,842, 25,188, 15,449\\",\\"Watch - rose gold-coloured, Print T-shirt - black, Blouse - peacoat, Print T-shirt - coral\\",\\"Watch - rose gold-coloured, Print T-shirt - black, Blouse - peacoat, Print T-shirt - coral\\",\\"1, 1, 1, 1\\",\\"ZO0079200792, ZO0263902639, ZO0065900659, ZO0492304923\\",\\"0, 0, 0, 0\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0079200792, ZO0263902639, ZO0065900659, ZO0492304923\\",\\"81.938\\",\\"81.938\\",4,4,order,elyssa +jAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Dennis\\",\\"Elyssa Dennis\\",FEMALE,27,Dennis,Dennis,\\"(empty)\\",Friday,4,\\"elyssa@dennis-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Oceanavigations\\",\\"Spherecords, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562572,\\"sold_product_562572_13412, sold_product_562572_19097\\",\\"sold_product_562572_13412, sold_product_562572_19097\\",\\"13.992, 60\\",\\"13.992, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Oceanavigations\\",\\"Spherecords, Oceanavigations\\",\\"7.551, 29.406\\",\\"13.992, 60\\",\\"13,412, 19,097\\",\\"Blouse - off white, Ankle boots - camel\\",\\"Blouse - off white, Ankle boots - camel\\",\\"1, 1\\",\\"ZO0649706497, ZO0249202492\\",\\"0, 0\\",\\"13.992, 60\\",\\"13.992, 60\\",\\"0, 0\\",\\"ZO0649706497, ZO0249202492\\",74,74,2,2,order,elyssa +nAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Stephanie,Stephanie,\\"Stephanie Marshall\\",\\"Stephanie Marshall\\",FEMALE,6,Marshall,Marshall,\\"(empty)\\",Friday,4,\\"stephanie@marshall-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562035,\\"sold_product_562035_9471, sold_product_562035_21453\\",\\"sold_product_562035_9471, sold_product_562035_21453\\",\\"42, 13.992\\",\\"42, 13.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"22.672, 7\\",\\"42, 13.992\\",\\"9,471, 21,453\\",\\"Summer dress - black/june bug, Handbag - black\\",\\"Summer dress - black/june bug, Handbag - black\\",\\"1, 1\\",\\"ZO0334403344, ZO0205002050\\",\\"0, 0\\",\\"42, 13.992\\",\\"42, 13.992\\",\\"0, 0\\",\\"ZO0334403344, ZO0205002050\\",\\"55.969\\",\\"55.969\\",2,2,order,stephanie +nQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Hodges\\",\\"Robbie Hodges\\",MALE,48,Hodges,Hodges,\\"(empty)\\",Friday,4,\\"robbie@hodges-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",562112,\\"sold_product_562112_6789, sold_product_562112_20433\\",\\"sold_product_562112_6789, sold_product_562112_20433\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.703, 5.82\\",\\"20.984, 10.992\\",\\"6,789, 20,433\\",\\"Chinos - blue, Long sleeved top - black/white\\",\\"Chinos - blue, Long sleeved top - black/white\\",\\"1, 1\\",\\"ZO0527405274, ZO0547005470\\",\\"0, 0\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"0, 0\\",\\"ZO0527405274, ZO0547005470\\",\\"31.984\\",\\"31.984\\",2,2,order,robbie +ngMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Ball\\",\\"Clarice Ball\\",FEMALE,18,Ball,Ball,\\"(empty)\\",Friday,4,\\"clarice@ball-family.zzz\\",Birmingham,Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -1.9, + 52.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Birmingham,\\"Tigress Enterprises Curvy, Karmanite\\",\\"Tigress Enterprises Curvy, Karmanite\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562275,\\"sold_product_562275_19153, sold_product_562275_12720\\",\\"sold_product_562275_19153, sold_product_562275_12720\\",\\"29.984, 70\\",\\"29.984, 70\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Karmanite\\",\\"Tigress Enterprises Curvy, Karmanite\\",\\"14.992, 37.094\\",\\"29.984, 70\\",\\"19,153, 12,720\\",\\"Cardigan - jade, Sandals - black\\",\\"Cardigan - jade, Sandals - black\\",\\"1, 1\\",\\"ZO0106301063, ZO0703507035\\",\\"0, 0\\",\\"29.984, 70\\",\\"29.984, 70\\",\\"0, 0\\",\\"ZO0106301063, ZO0703507035\\",100,100,2,2,order,clarice +nwMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Greer\\",\\"Mostafa Greer\\",MALE,9,Greer,Greer,\\"(empty)\\",Friday,4,\\"mostafa@greer-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562287,\\"sold_product_562287_3022, sold_product_562287_23056\\",\\"sold_product_562287_3022, sold_product_562287_23056\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"9.172, 28.797\\",\\"16.984, 60\\",\\"3,022, 23,056\\",\\"3 PACK - Basic T-shirt - white, Suit jacket - grey multicolor\\",\\"3 PACK - Basic T-shirt - white, Suit jacket - grey multicolor\\",\\"1, 1\\",\\"ZO0473104731, ZO0274302743\\",\\"0, 0\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"0, 0\\",\\"ZO0473104731, ZO0274302743\\",77,77,2,2,order,mostafa +rgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Schultz\\",\\"Tariq Schultz\\",MALE,25,Schultz,Schultz,\\"(empty)\\",Friday,4,\\"tariq@schultz-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562404,\\"sold_product_562404_19679, sold_product_562404_22477\\",\\"sold_product_562404_19679, sold_product_562404_22477\\",\\"28.984, 22.984\\",\\"28.984, 22.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"15.648, 12.18\\",\\"28.984, 22.984\\",\\"19,679, 22,477\\",\\"Hoodie - black/dark blue/white, Jumper - khaki\\",\\"Hoodie - black/dark blue/white, Jumper - khaki\\",\\"1, 1\\",\\"ZO0584205842, ZO0299102991\\",\\"0, 0\\",\\"28.984, 22.984\\",\\"28.984, 22.984\\",\\"0, 0\\",\\"ZO0584205842, ZO0299102991\\",\\"51.969\\",\\"51.969\\",2,2,order,tariq +1QMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Abbott\\",\\"Hicham Abbott\\",MALE,8,Abbott,Abbott,\\"(empty)\\",Friday,4,\\"hicham@abbott-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562099,\\"sold_product_562099_18906, sold_product_562099_21672\\",\\"sold_product_562099_18906, sold_product_562099_21672\\",\\"13.992, 16.984\\",\\"13.992, 16.984\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"6.578, 9\\",\\"13.992, 16.984\\",\\"18,906, 21,672\\",\\"Belt - black, Polo shirt - black multicolor\\",\\"Belt - black, Polo shirt - black multicolor\\",\\"1, 1\\",\\"ZO0317903179, ZO0443904439\\",\\"0, 0\\",\\"13.992, 16.984\\",\\"13.992, 16.984\\",\\"0, 0\\",\\"ZO0317903179, ZO0443904439\\",\\"30.984\\",\\"30.984\\",2,2,order,hicham +1gMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Morrison\\",\\"Boris Morrison\\",MALE,36,Morrison,Morrison,\\"(empty)\\",Friday,4,\\"boris@morrison-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562298,\\"sold_product_562298_22860, sold_product_562298_11728\\",\\"sold_product_562298_22860, sold_product_562298_11728\\",\\"24.984, 18.984\\",\\"24.984, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"11.5, 8.547\\",\\"24.984, 18.984\\",\\"22,860, 11,728\\",\\"Shirt - offwhite, Sweatshirt - red\\",\\"Shirt - offwhite, Sweatshirt - red\\",\\"1, 1\\",\\"ZO0280002800, ZO0583105831\\",\\"0, 0\\",\\"24.984, 18.984\\",\\"24.984, 18.984\\",\\"0, 0\\",\\"ZO0280002800, ZO0583105831\\",\\"43.969\\",\\"43.969\\",2,2,order,boris +3QMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Oliver,Oliver,\\"Oliver Rios\\",\\"Oliver Rios\\",MALE,7,Rios,Rios,\\"(empty)\\",Friday,4,\\"oliver@rios-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562025,\\"sold_product_562025_18322, sold_product_562025_1687\\",\\"sold_product_562025_18322, sold_product_562025_1687\\",\\"14.992, 80\\",\\"14.992, 80\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"7.352, 43.188\\",\\"14.992, 80\\",\\"18,322, 1,687\\",\\"Print T-shirt - grey, Lace-ups - whisky\\",\\"Print T-shirt - grey, Lace-ups - whisky\\",\\"1, 1\\",\\"ZO0558205582, ZO0682406824\\",\\"0, 0\\",\\"14.992, 80\\",\\"14.992, 80\\",\\"0, 0\\",\\"ZO0558205582, ZO0682406824\\",95,95,2,2,order,oliver +hAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Palmer\\",\\"Rabbia Al Palmer\\",FEMALE,5,Palmer,Palmer,\\"(empty)\\",Friday,4,\\"rabbia al@palmer-family.zzz\\",Dubai,Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 55.3, + 25.3 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Dubai,\\"Spherecords, Pyramidustries, Tigress Enterprises\\",\\"Spherecords, Pyramidustries, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",732071,\\"sold_product_732071_23772, sold_product_732071_22922, sold_product_732071_24589, sold_product_732071_24761\\",\\"sold_product_732071_23772, sold_product_732071_22922, sold_product_732071_24589, sold_product_732071_24761\\",\\"18.984, 33, 24.984, 20.984\\",\\"18.984, 33, 24.984, 20.984\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Pyramidustries, Tigress Enterprises, Tigress Enterprises\\",\\"Spherecords, Pyramidustries, Tigress Enterprises, Tigress Enterprises\\",\\"10.25, 15.508, 13.492, 10.289\\",\\"18.984, 33, 24.984, 20.984\\",\\"23,772, 22,922, 24,589, 24,761\\",\\"Jumper - turquoise, Jersey dress - dark red, Boots - black, Vest - black\\",\\"Jumper - turquoise, Jersey dress - dark red, Boots - black, Vest - black\\",\\"1, 1, 1, 1\\",\\"ZO0655406554, ZO0154001540, ZO0030300303, ZO0061100611\\",\\"0, 0, 0, 0\\",\\"18.984, 33, 24.984, 20.984\\",\\"18.984, 33, 24.984, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0655406554, ZO0154001540, ZO0030300303, ZO0061100611\\",\\"97.938\\",\\"97.938\\",4,4,order,rabbia +kQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Yahya,Yahya,\\"Yahya King\\",\\"Yahya King\\",MALE,23,King,King,\\"(empty)\\",Friday,4,\\"yahya@king-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, (empty)\\",\\"Low Tide Media, (empty)\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561383,\\"sold_product_561383_15806, sold_product_561383_12605\\",\\"sold_product_561383_15806, sold_product_561383_12605\\",\\"13.992, 155\\",\\"13.992, 155\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, (empty)\\",\\"Low Tide Media, (empty)\\",\\"7.27, 82.125\\",\\"13.992, 155\\",\\"15,806, 12,605\\",\\"Belt - dark brown, Lace-ups - taupe\\",\\"Belt - dark brown, Lace-ups - taupe\\",\\"1, 1\\",\\"ZO0461804618, ZO0481404814\\",\\"0, 0\\",\\"13.992, 155\\",\\"13.992, 155\\",\\"0, 0\\",\\"ZO0461804618, ZO0481404814\\",169,169,2,2,order,yahya +kgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Strickland\\",\\"Sonya Strickland\\",FEMALE,28,Strickland,Strickland,\\"(empty)\\",Friday,4,\\"sonya@strickland-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"{ + \\"\\"coordinates\\"\\": [ + -74.1, + 4.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Bogota D.C.\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561825,\\"sold_product_561825_23332, sold_product_561825_8218\\",\\"sold_product_561825_23332, sold_product_561825_8218\\",\\"18.984, 17.984\\",\\"18.984, 17.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"9.117, 9.531\\",\\"18.984, 17.984\\",\\"23,332, 8,218\\",\\"Vest - black/dark green, Sweatshirt - rose\\",\\"Vest - black/dark green, Sweatshirt - rose\\",\\"1, 1\\",\\"ZO0062500625, ZO0179801798\\",\\"0, 0\\",\\"18.984, 17.984\\",\\"18.984, 17.984\\",\\"0, 0\\",\\"ZO0062500625, ZO0179801798\\",\\"36.969\\",\\"36.969\\",2,2,order,sonya +kwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Meyer\\",\\"Abd Meyer\\",MALE,52,Meyer,Meyer,\\"(empty)\\",Friday,4,\\"abd@meyer-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561870,\\"sold_product_561870_18909, sold_product_561870_18272\\",\\"sold_product_561870_18909, sold_product_561870_18272\\",\\"65, 12.992\\",\\"65, 12.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"33.125, 6.109\\",\\"65, 12.992\\",\\"18,909, 18,272\\",\\"Cardigan - grey multicolor, Sports shirt - dark grey multicolor\\",\\"Cardigan - grey multicolor, Sports shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0450904509, ZO0615906159\\",\\"0, 0\\",\\"65, 12.992\\",\\"65, 12.992\\",\\"0, 0\\",\\"ZO0450904509, ZO0615906159\\",78,78,2,2,order,abd +wwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Salazar\\",\\"Elyssa Salazar\\",FEMALE,27,Salazar,Salazar,\\"(empty)\\",Friday,4,\\"elyssa@salazar-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",Oceanavigations,Oceanavigations,\\"Jun 20, 2019 @ 00:00:00.000\\",561569,\\"sold_product_561569_22788, sold_product_561569_20475\\",\\"sold_product_561569_22788, sold_product_561569_20475\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"9.867, 15.359\\",\\"20.984, 28.984\\",\\"22,788, 20,475\\",\\"Print T-shirt - white/black, Blouse - red\\",\\"Print T-shirt - white/black, Blouse - red\\",\\"1, 1\\",\\"ZO0264602646, ZO0265202652\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0264602646, ZO0265202652\\",\\"49.969\\",\\"49.969\\",2,2,order,elyssa +hAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Brock\\",\\"Robert Brock\\",MALE,29,Brock,Brock,\\"(empty)\\",Friday,4,\\"robert@brock-family.zzz\\",\\"-\\",Asia,SA,\\"{ + \\"\\"coordinates\\"\\": [ + 45, + 25 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561935,\\"sold_product_561935_20811, sold_product_561935_19107\\",\\"sold_product_561935_20811, sold_product_561935_19107\\",\\"37, 50\\",\\"37, 50\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"17.391, 26.984\\",\\"37, 50\\",\\"20,811, 19,107\\",\\"Shirt - white/red, Suit jacket - navy\\",\\"Shirt - white/red, Suit jacket - navy\\",\\"1, 1\\",\\"ZO0417404174, ZO0275702757\\",\\"0, 0\\",\\"37, 50\\",\\"37, 50\\",\\"0, 0\\",\\"ZO0417404174, ZO0275702757\\",87,87,2,2,order,robert +hQMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Graves\\",\\"Abdulraheem Al Graves\\",MALE,33,Graves,Graves,\\"(empty)\\",Friday,4,\\"abdulraheem al@graves-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561976,\\"sold_product_561976_16395, sold_product_561976_2982\\",\\"sold_product_561976_16395, sold_product_561976_2982\\",\\"42, 33\\",\\"42, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"19.313, 17.484\\",\\"42, 33\\",\\"16,395, 2,982\\",\\"Lace-ups - black, Jumper - multicoloured\\",\\"Lace-ups - black, Jumper - multicoloured\\",\\"1, 1\\",\\"ZO0392703927, ZO0452004520\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0392703927, ZO0452004520\\",75,75,2,2,order,abdulraheem +swMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Accessories, Men's Accessories, Men's Shoes\\",\\"Women's Accessories, Men's Accessories, Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Goodman\\",\\"Sultan Al Goodman\\",MALE,19,Goodman,Goodman,\\"(empty)\\",Friday,4,\\"sultan al@goodman-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Elitelligence, Oceanavigations, Angeldale\\",\\"Elitelligence, Oceanavigations, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",717426,\\"sold_product_717426_20776, sold_product_717426_13026, sold_product_717426_11738, sold_product_717426_15588\\",\\"sold_product_717426_20776, sold_product_717426_13026, sold_product_717426_11738, sold_product_717426_15588\\",\\"24.984, 100, 14.992, 20.984\\",\\"24.984, 100, 14.992, 20.984\\",\\"Women's Accessories, Men's Accessories, Men's Shoes, Women's Accessories\\",\\"Women's Accessories, Men's Accessories, Men's Shoes, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Oceanavigations, Elitelligence, Angeldale\\",\\"Elitelligence, Oceanavigations, Elitelligence, Angeldale\\",\\"12, 48, 7.5, 11.539\\",\\"24.984, 100, 14.992, 20.984\\",\\"20,776, 13,026, 11,738, 15,588\\",\\"Sports bag - navy/cognac, Weekend bag - dark brown, Espadrilles - navy, Wallet - cognac\\",\\"Sports bag - navy/cognac, Weekend bag - dark brown, Espadrilles - navy, Wallet - cognac\\",\\"1, 1, 1, 1\\",\\"ZO0606006060, ZO0314703147, ZO0518005180, ZO0702907029\\",\\"0, 0, 0, 0\\",\\"24.984, 100, 14.992, 20.984\\",\\"24.984, 100, 14.992, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0606006060, ZO0314703147, ZO0518005180, ZO0702907029\\",161,161,4,4,order,sultan +ywMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Jacobs\\",\\"Abd Jacobs\\",MALE,52,Jacobs,Jacobs,\\"(empty)\\",Friday,4,\\"abd@jacobs-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 20, 2019 @ 00:00:00.000\\",719082,\\"sold_product_719082_23782, sold_product_719082_12684, sold_product_719082_19741, sold_product_719082_19989\\",\\"sold_product_719082_23782, sold_product_719082_12684, sold_product_719082_19741, sold_product_719082_19989\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Shoes\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Microlutions, Elitelligence, Elitelligence\\",\\"Elitelligence, Microlutions, Elitelligence, Elitelligence\\",\\"15.07, 7.5, 7.988, 15.648\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"23,782, 12,684, 19,741, 19,989\\",\\"Tracksuit top - black, Print T-shirt - navy blazer, Trainers - black, Trainers - grey\\",\\"Tracksuit top - black, Print T-shirt - navy blazer, Trainers - black, Trainers - grey\\",\\"1, 1, 1, 1\\",\\"ZO0591005910, ZO0116501165, ZO0507505075, ZO0514305143\\",\\"0, 0, 0, 0\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"0, 0, 0, 0\\",\\"ZO0591005910, ZO0116501165, ZO0507505075, ZO0514305143\\",\\"89.938\\",\\"89.938\\",4,4,order,abd +0wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Pope\\",\\"Jackson Pope\\",MALE,13,Pope,Pope,\\"(empty)\\",Friday,4,\\"jackson@pope-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -118.2, + 34.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",California,\\"Elitelligence, Microlutions, Oceanavigations\\",\\"Elitelligence, Microlutions, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",715688,\\"sold_product_715688_19518, sold_product_715688_21048, sold_product_715688_12333, sold_product_715688_21005\\",\\"sold_product_715688_19518, sold_product_715688_21048, sold_product_715688_12333, sold_product_715688_21005\\",\\"33, 14.992, 16.984, 20.984\\",\\"33, 14.992, 16.984, 20.984\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Microlutions, Elitelligence, Oceanavigations\\",\\"Elitelligence, Microlutions, Elitelligence, Oceanavigations\\",\\"16.813, 6.75, 7.648, 9.656\\",\\"33, 14.992, 16.984, 20.984\\",\\"19,518, 21,048, 12,333, 21,005\\",\\"Sweatshirt - mottled grey, Print T-shirt - bright white, Tracksuit top - black, Formal shirt - white\\",\\"Sweatshirt - mottled grey, Print T-shirt - bright white, Tracksuit top - black, Formal shirt - white\\",\\"1, 1, 1, 1\\",\\"ZO0585505855, ZO0121001210, ZO0583005830, ZO0279402794\\",\\"0, 0, 0, 0\\",\\"33, 14.992, 16.984, 20.984\\",\\"33, 14.992, 16.984, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0585505855, ZO0121001210, ZO0583005830, ZO0279402794\\",\\"85.938\\",\\"85.938\\",4,4,order,jackson +1QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Bryan\\",\\"Elyssa Bryan\\",FEMALE,27,Bryan,Bryan,\\"(empty)\\",Friday,4,\\"elyssa@bryan-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Low Tide Media, Pyramidustries, Pyramidustries active\\",\\"Low Tide Media, Pyramidustries, Pyramidustries active\\",\\"Jun 20, 2019 @ 00:00:00.000\\",729671,\\"sold_product_729671_5140, sold_product_729671_12381, sold_product_729671_16267, sold_product_729671_20230\\",\\"sold_product_729671_5140, sold_product_729671_12381, sold_product_729671_16267, sold_product_729671_20230\\",\\"60, 16.984, 24.984, 24.984\\",\\"60, 16.984, 24.984, 24.984\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Pyramidustries, Pyramidustries active, Pyramidustries\\",\\"Low Tide Media, Pyramidustries, Pyramidustries active, Pyramidustries\\",\\"30, 7.648, 12.492, 12\\",\\"60, 16.984, 24.984, 24.984\\",\\"5,140, 12,381, 16,267, 20,230\\",\\"Ankle boots - onix, Sweatshirt - rose, Tights - black, Sandals - silver\\",\\"Ankle boots - onix, Sweatshirt - rose, Tights - black, Sandals - silver\\",\\"1, 1, 1, 1\\",\\"ZO0375303753, ZO0178301783, ZO0226002260, ZO0137601376\\",\\"0, 0, 0, 0\\",\\"60, 16.984, 24.984, 24.984\\",\\"60, 16.984, 24.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0375303753, ZO0178301783, ZO0226002260, ZO0137601376\\",\\"126.938\\",\\"126.938\\",4,4,order,elyssa +" `; diff --git a/x-pack/test/functional/apps/discover/feature_controls/discover_spaces.ts b/x-pack/test/functional/apps/discover/feature_controls/discover_spaces.ts index c245b45917497..5e14cc6201ec2 100644 --- a/x-pack/test/functional/apps/discover/feature_controls/discover_spaces.ts +++ b/x-pack/test/functional/apps/discover/feature_controls/discover_spaces.ts @@ -28,6 +28,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRange(); } + // FLAKY https://github.com/elastic/kibana/issues/113067 describe('spaces', () => { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 32ed5af506cc3..99bdb20580ce8 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -14,22 +14,36 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const browser = getService('browser'); + const retry = getService('retry'); const PageObjects = getPageObjects(['reporting', 'common', 'discover', 'timePicker']); const filterBar = getService('filterBar'); const ecommerceSOPath = 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json'; const setFieldsFromSource = async (setValue: boolean) => { await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': setValue }); + await browser.refresh(); }; - // Failing: See https://github.com/elastic/kibana/issues/112164 - describe.skip('Discover CSV Export', () => { + const getReport = async () => { + await PageObjects.reporting.openCsvReportingPanel(); + await PageObjects.reporting.clickGenerateReportButton(); + + const url = await PageObjects.reporting.getReportURL(60000); + const res = await PageObjects.reporting.getResponse(url); + + expect(res.status).to.equal(200); + expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); + return res; + }; + + describe('Discover CSV Export', () => { before('initialize tests', async () => { log.debug('ReportingPage:initTests'); await esArchiver.load('x-pack/test/functional/es_archives/reporting/ecommerce'); await kibanaServer.importExport.load(ecommerceSOPath); await browser.setWindowSize(1600, 850); }); + after('clean up archives', async () => { await esArchiver.unload('x-pack/test/functional/es_archives/reporting/ecommerce'); await kibanaServer.importExport.unload(ecommerceSOPath); @@ -38,6 +52,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { refresh: true, body: { query: { match_all: {} } }, }); + await esArchiver.emptyKibanaIndex(); }); describe('Check Available', () => { @@ -53,26 +68,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.reporting.openCsvReportingPanel(); expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); }); - - it('remains available regardless of the saved search state', async () => { - // create new search, csv export is not available - await PageObjects.discover.clickNewSearchButton(); - await PageObjects.reporting.setTimepickerInDataRange(); - await PageObjects.reporting.openCsvReportingPanel(); - expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); - // save search, csv export is available - await PageObjects.discover.saveSearch('my search - expectEnabledGenerateReportButton 2'); - await PageObjects.reporting.openCsvReportingPanel(); - expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); - // add filter, csv export is not available - await filterBar.addFilter('currency', 'is', 'EUR'); - await PageObjects.reporting.openCsvReportingPanel(); - expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); - // save search again, csv export is available - await PageObjects.discover.saveSearch('my search - expectEnabledGenerateReportButton 2'); - await PageObjects.reporting.openCsvReportingPanel(); - expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); - }); }); describe('Generate CSV: new search', () => { @@ -83,92 +78,51 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('generates a report from a new search with data: default', async () => { await PageObjects.discover.clickNewSearchButton(); - await PageObjects.reporting.setTimepickerInDataRange(); - await PageObjects.discover.saveSearch('my search - with data - expectReportCanBeCreated'); - await PageObjects.reporting.openCsvReportingPanel(); - await PageObjects.reporting.clickGenerateReportButton(); - - const url = await PageObjects.reporting.getReportURL(60000); - const res = await PageObjects.reporting.getResponse(url); - - expect(res.status).to.equal(200); - expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); - - const csvFile = res.text; - const lines = csvFile.trim().split('\n'); - - // verifies the beginning and end of the text - expectSnapshot(lines.slice(0, 100)).toMatch(); - expectSnapshot(lines.slice(-100)).toMatch(); - - expectSnapshot(csvFile.length).toMatchInline(`5093456`); - expectSnapshot(lines.length).toMatchInline(`32726`); - }); - - it('generates a report from a new search with data: discover:searchFieldsFromSource', async () => { - await setFieldsFromSource(true); - await PageObjects.discover.clickNewSearchButton(); - await PageObjects.reporting.setTimepickerInDataRange(); - await PageObjects.discover.saveSearch( - 'my search - with fieldsFromSource data - expectReportCanBeCreated' - ); - await PageObjects.reporting.openCsvReportingPanel(); - await PageObjects.reporting.clickGenerateReportButton(); + await PageObjects.reporting.setTimepickerInEcommerceDataRange(); - const url = await PageObjects.reporting.getReportURL(60000); - const res = await PageObjects.reporting.getResponse(url); + await PageObjects.discover.saveSearch('my search - with data - expectReportCanBeCreated'); + const res = await getReport(); expect(res.status).to.equal(200); expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); const csvFile = res.text; - const lines = csvFile.trim().split('\n'); - - // verifies the beginning and end of the text - expectSnapshot(lines.slice(0, 100)).toMatch(); - expectSnapshot(lines.slice(-100)).toMatch(); - - expectSnapshot(csvFile.length).toMatchInline(`5093456`); - expectSnapshot(lines.length).toMatchInline(`32726`); - - await setFieldsFromSource(false); + expectSnapshot(csvFile).toMatch(); }); it('generates a report with no data', async () => { - await PageObjects.reporting.setTimepickerInNoDataRange(); + await PageObjects.reporting.setTimepickerInEcommerceNoDataRange(); await PageObjects.discover.saveSearch('my search - no data - expectReportCanBeCreated'); - await PageObjects.reporting.openCsvReportingPanel(); - await PageObjects.reporting.clickGenerateReportButton(); - const url = await PageObjects.reporting.getReportURL(60000); - const res = await PageObjects.reporting.getResponse(url); - - expect(res.status).to.equal(200); - expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); - expectSnapshot(res.text).toMatchInline(` - " - " - `); + const res = await getReport(); + expect(res.text).to.be(`\n`); }); - }); - describe('Generate CSV: archived search', () => { - const setupPage = async () => { + // FIXME: https://github.com/elastic/kibana/issues/112186 + it.skip('generates a large export', async () => { const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; const toTime = 'Aug 23, 2019 @ 16:18:51.821'; await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - }; - - const getReport = async () => { - await PageObjects.reporting.openCsvReportingPanel(); - await PageObjects.reporting.clickGenerateReportButton(); + await PageObjects.discover.selectIndexPattern('ecommerce'); + await PageObjects.discover.clickNewSearchButton(); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('4,675'); + }); + await PageObjects.discover.saveSearch('large export'); - const url = await PageObjects.reporting.getReportURL(60000); - const res = await PageObjects.reporting.getResponse(url); + // match file length, the beginning and the end of the csv file contents + const { text: csvFile } = await getReport(); + expect(csvFile.length).to.be(4954749); + expectSnapshot(csvFile.slice(0, 5000)).toMatch(); + expectSnapshot(csvFile.slice(-5000)).toMatch(); + }); + }); - expect(res.status).to.equal(200); - expect(res.get('content-type')).to.equal('text/csv; charset=utf-8'); - return res; + describe('Generate CSV: archived search', () => { + const setupPage = async () => { + const fromTime = 'Jun 22, 2019 @ 00:00:00.000'; + const toTime = 'Jun 26, 2019 @ 23:30:00.000'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); }; before(async () => { @@ -186,130 +140,43 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('generates a report with data', async () => { await setupPage(); await PageObjects.discover.loadSavedSearch('Ecommerce Data'); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('740'); + }); const { text: csvFile } = await getReport(); - const lines = csvFile.trim().split('\n'); - expectSnapshot(csvFile.length).toMatchInline(`782100`); - expectSnapshot(lines.length).toMatchInline(`4676`); - - // match the beginning and the end of the csv file contents - expectSnapshot(lines.slice(0, 10)).toMatchInline(` - Array [ - "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\"", - ] - `); - expectSnapshot(lines.slice(-10)).toMatchInline(` - Array [ - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,550580,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0144801448, ZO0219602196\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,33,551324,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0316803168, ZO0566905669\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,551355,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0313403134, ZO0561205612\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,28,550957,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0133101331, ZO0189401894\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,39,551154,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0466704667, ZO0617306173\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,551204,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0212602126, ZO0200702007\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,550466,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0260702607, ZO0363203632\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,550503,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0587505875, ZO0566405664\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,550538,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0699406994, ZO0246202462\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,550568,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0388403884, ZO0447604476\\"", - ] - `); + expectSnapshot(csvFile).toMatch(); }); it('generates a report with filtered data', async () => { await setupPage(); await PageObjects.discover.loadSavedSearch('Ecommerce Data'); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('740'); + }); - // filter and re-save + // filter await filterBar.addFilter('category', 'is', `Men's Shoes`); - await PageObjects.discover.saveSearch(`Ecommerce Data: EUR Filtered`); // renamed the search + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('154'); + }); const { text: csvFile } = await getReport(); - const lines = csvFile.trim().split('\n'); - expectSnapshot(csvFile.length).toMatchInline(`165557`); - expectSnapshot(lines.length).toMatchInline(`945`); - - // match the beginning and the end of the csv file contents - expectSnapshot(lines.slice(0, 10)).toMatchInline(` - Array [ - "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,591148,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0290302903, ZO0513705137\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,591562,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0544305443, ZO0108001080\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,591411,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0693506935, ZO0532405324\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,38,722629,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0424204242, ZO0403504035, ZO0506705067, ZO0395603956\\"", - ] - `); - expectSnapshot(lines.slice(-10)).toMatchInline(` - Array [ - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,550425,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0256602566, ZO0516305163\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719265,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0619506195, ZO0297802978, ZO0125001250, ZO0693306933\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,550990,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0404404044, ZO0570605706\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,7,550663,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0560905609\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,551697,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0387903879, ZO0693206932\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,550784,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0683206832, ZO0687706877\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,15,550412,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0508905089, ZO0681206812\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,551556,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0512405124, ZO0551405514\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,550473,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0688006880, ZO0450504505\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,550568,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0388403884, ZO0447604476\\"", - ] - `); - - await PageObjects.discover.saveSearch(`Ecommerce Data`); // rename the search back for the next test + expectSnapshot(csvFile).toMatch(); }); it('generates a report with discover:searchFieldsFromSource = true', async () => { await setupPage(); await PageObjects.discover.loadSavedSearch('Ecommerce Data'); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('740'); + }); + await setFieldsFromSource(true); - await browser.refresh(); const { text: csvFile } = await getReport(); - const lines = csvFile.trim().split('\n'); - expectSnapshot(csvFile.length).toMatchInline(`165753`); - expectSnapshot(lines.length).toMatchInline(`945`); - - // match the beginning and the end of the csv file contents - expectSnapshot(lines.slice(0, 10)).toMatchInline(` - Array [ - "\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,591148,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0290302903, ZO0513705137\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,591562,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0544305443, ZO0108001080\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,591411,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0693506935, ZO0532405324\\"", - "\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,38,722629,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0424204242, ZO0403504035, ZO0506705067, ZO0395603956\\"", - ] - `); - expectSnapshot(lines.slice(-10)).toMatchInline(` - Array [ - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,550425,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0256602566, ZO0516305163\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719265,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0619506195, ZO0297802978, ZO0125001250, ZO0693306933\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,550990,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0404404044, ZO0570605706\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,7,550663,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0560905609\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,551697,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0387903879, ZO0693206932\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,550784,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0683206832, ZO0687706877\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,15,550412,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0508905089, ZO0681206812\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,551556,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0512405124, ZO0551405514\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,550473,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0688006880, ZO0450504505\\"", - "\\"Jun 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,550568,3,\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"ZO0388403884, ZO0447604476\\"", - ] - `); + expectSnapshot(csvFile).toMatch(); await setFieldsFromSource(false); }); diff --git a/x-pack/test/functional/apps/discover/saved_searches.ts b/x-pack/test/functional/apps/discover/saved_searches.ts index 1d8de9fe9fb6d..ec649935adec2 100644 --- a/x-pack/test/functional/apps/discover/saved_searches.ts +++ b/x-pack/test/functional/apps/discover/saved_searches.ts @@ -18,7 +18,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const panelActionsTimeRange = getService('dashboardPanelTimeRange'); const ecommerceSOPath = 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json'; - describe('Discover Saved Searches', () => { + // FLAKY https://github.com/elastic/kibana/issues/104578 + describe.skip('Discover Saved Searches', () => { before('initialize tests', async () => { await esArchiver.load('x-pack/test/functional/es_archives/reporting/ecommerce'); await kibanaServer.importExport.load(ecommerceSOPath); diff --git a/x-pack/test/functional/apps/lens/formula.ts b/x-pack/test/functional/apps/lens/formula.ts index f645b2c64629c..a8d074ad0631b 100644 --- a/x-pack/test/functional/apps/lens/formula.ts +++ b/x-pack/test/functional/apps/lens/formula.ts @@ -236,6 +236,38 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); }); + it('should keep the formula if the user does not fully transition to a static value', async () => { + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + await PageObjects.lens.goToTimeRange(); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'average', + field: 'bytes', + }); + + await PageObjects.lens.createLayer('threshold'); + + await PageObjects.lens.configureDimension( + { + dimension: 'lnsXY_yThresholdLeftPanel > lns-dimensionTrigger', + operation: 'formula', + formula: `count()`, + keepOpen: true, + }, + 1 + ); + + await PageObjects.lens.switchToStaticValue(); + await PageObjects.lens.closeDimensionEditor(); + await PageObjects.common.sleep(1000); + + expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_yThresholdLeftPanel', 0)).to.eql( + 'count()' + ); + }); + it('should allow numeric only formulas', async () => { await PageObjects.visualize.navigateToNewVisualization(); await PageObjects.visualize.clickVisType('lens'); diff --git a/x-pack/test/functional/apps/lens/index.ts b/x-pack/test/functional/apps/lens/index.ts index 09bbda595d55c..50dbe05df166c 100644 --- a/x-pack/test/functional/apps/lens/index.ts +++ b/x-pack/test/functional/apps/lens/index.ts @@ -25,10 +25,14 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await esArchiver.unload('x-pack/test/functional/es_archives/lens/basic'); }); + describe('', function () { + this.tags(['ciGroup3', 'skipFirefox']); + loadTestFile(require.resolve('./smokescreen')); + }); + describe('', function () { this.tags(['ciGroup4', 'skipFirefox']); - loadTestFile(require.resolve('./smokescreen')); loadTestFile(require.resolve('./add_to_dashboard')); loadTestFile(require.resolve('./table')); loadTestFile(require.resolve('./runtime_fields')); @@ -43,6 +47,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./lens_tagging')); loadTestFile(require.resolve('./formula')); loadTestFile(require.resolve('./heatmap')); + loadTestFile(require.resolve('./thresholds')); loadTestFile(require.resolve('./inspector')); // has to be last one in the suite because it overrides saved objects diff --git a/x-pack/test/functional/apps/lens/smokescreen.ts b/x-pack/test/functional/apps/lens/smokescreen.ts index 6d9360ac32b4b..ff5bae8aa7e61 100644 --- a/x-pack/test/functional/apps/lens/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/smokescreen.ts @@ -180,6 +180,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); }); + it('should not show static value tab for data layers', async () => { + await PageObjects.lens.openDimensionEditor('lnsXY_yDimensionPanel > lns-dimensionTrigger'); + // Quick functions and Formula tabs should be visible + expect(await testSubjects.exists('lens-dimensionTabs-quickFunctions')).to.eql(true); + expect(await testSubjects.exists('lens-dimensionTabs-formula')).to.eql(true); + // Static value tab should not be visible + expect(await testSubjects.exists('lens-dimensionTabs-static_value')).to.eql(false); + + await PageObjects.lens.closeDimensionEditor(); + }); + it('should be able to add very long labels and still be able to remove a dimension', async () => { await PageObjects.lens.openDimensionEditor('lnsXY_yDimensionPanel > lns-dimensionTrigger'); const longLabel = diff --git a/x-pack/test/functional/apps/lens/thresholds.ts b/x-pack/test/functional/apps/lens/thresholds.ts new file mode 100644 index 0000000000000..bf6535acc7c8e --- /dev/null +++ b/x-pack/test/functional/apps/lens/thresholds.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['visualize', 'lens', 'common', 'header']); + const find = getService('find'); + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + + describe('lens thresholds tests', () => { + it('should show a disabled threshold layer button if no data dimension is defined', async () => { + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + + await testSubjects.click('lnsLayerAddButton'); + await retry.waitFor('wait for layer popup to appear', async () => + testSubjects.exists(`lnsLayerAddButton-threshold`) + ); + expect( + await (await testSubjects.find(`lnsLayerAddButton-threshold`)).getAttribute('disabled') + ).to.be('true'); + }); + + it('should add a threshold layer with a static value in it', async () => { + await PageObjects.lens.goToTimeRange(); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + field: '@timestamp', + }); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'average', + field: 'bytes', + }); + + await PageObjects.lens.createLayer('threshold'); + + expect((await find.allByCssSelector(`[data-test-subj^="lns-layerPanel-"]`)).length).to.eql(2); + expect( + await ( + await testSubjects.find('lnsXY_yThresholdLeftPanel > lns-dimensionTrigger') + ).getVisibleText() + ).to.eql('Static value: 4992.44'); + }); + + it('should create a dynamic threshold when dragging a field to a threshold dimension group', async () => { + await PageObjects.lens.dragFieldToDimensionTrigger( + 'bytes', + 'lnsXY_yThresholdLeftPanel > lns-empty-dimension' + ); + + expect(await PageObjects.lens.getDimensionTriggersTexts('lnsXY_yThresholdLeftPanel')).to.eql([ + 'Static value: 4992.44', + 'Median of bytes', + ]); + }); + }); +} diff --git a/x-pack/test/functional/apps/maps/layer_errors.js b/x-pack/test/functional/apps/maps/layer_errors.js index 64973461c107b..23cbc8c51835c 100644 --- a/x-pack/test/functional/apps/maps/layer_errors.js +++ b/x-pack/test/functional/apps/maps/layer_errors.js @@ -104,24 +104,6 @@ export default function ({ getPageObjects }) { }); }); - describe('KibanaRegionmapSource with missing region map configuration', () => { - const MISSING_REGION_NAME = 'nameThatDoesNotExitForKibanaRegionmapSource'; - const LAYER_NAME = 'Custom_vector_shapes'; - - it('should diplay error message in layer panel', async () => { - const errorMsg = await PageObjects.maps.getLayerErrorText(LAYER_NAME); - expect(errorMsg).to.equal( - `Unable to find map.regionmap configuration for ${MISSING_REGION_NAME}` - ); - }); - - it('should allow deletion of layer', async () => { - await PageObjects.maps.removeLayer(LAYER_NAME); - const exists = await PageObjects.maps.doesLayerExist(LAYER_NAME); - expect(exists).to.be(false); - }); - }); - describe('KibanaTilemapSource with missing map.tilemap.url configuration', () => { const LAYER_NAME = 'Custom_TMS'; diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts b/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts index 3622c5dba1696..4373da71512e4 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts @@ -63,8 +63,7 @@ export default function ({ getService }: FtrProviderContext) { const ml = getService('ml'); const elasticChart = getService('elasticChart'); - // Failing: See https://github.com/elastic/kibana/issues/112405 - describe.skip('anomaly explorer', function () { + describe('anomaly explorer', function () { this.tags(['mlqa']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/date_nanos_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection/date_nanos_job.ts index ca330bb8e6a0a..d351e8f7057e4 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/date_nanos_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/date_nanos_job.ts @@ -114,8 +114,7 @@ export default function ({ getService }: FtrProviderContext) { }, ]; - // Failing: See https://github.com/elastic/kibana/issues/112194 - describe.skip('job on data set with date_nanos time field', function () { + describe('job on data set with date_nanos time field', function () { this.tags(['mlqa']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/event_rate_nanos'); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/multi_metric_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection/multi_metric_job.ts index 9cc570256f8f1..0c1b1620eb413 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/multi_metric_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/multi_metric_job.ts @@ -71,8 +71,7 @@ export default function ({ getService }: FtrProviderContext) { const calendarId = `wizard-test-calendar_${Date.now()}`; - // Failing: See https://github.com/elastic/kibana/issues/112174 - describe.skip('multi metric', function () { + describe('multi metric', function () { this.tags(['mlqa']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/saved_search_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection/saved_search_job.ts index 1637369142aa2..fb10414d2d9ef 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/saved_search_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/saved_search_job.ts @@ -265,8 +265,7 @@ export default function ({ getService }: FtrProviderContext) { }, ]; - // Failing: See https://github.com/elastic/kibana/issues/104174 - describe.skip('saved search', function () { + describe('saved search', function () { this.tags(['mlqa']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); diff --git a/x-pack/test/functional/apps/ml/index.ts b/x-pack/test/functional/apps/ml/index.ts index eaf626618726a..d4bf9a22367bf 100644 --- a/x-pack/test/functional/apps/ml/index.ts +++ b/x-pack/test/functional/apps/ml/index.ts @@ -53,7 +53,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); describe('', function () { - this.tags('ciGroup13'); + this.tags('ciGroup8'); before(async () => { await ml.securityCommon.createMlRoles(); diff --git a/x-pack/test/functional/apps/rollup_job/tsvb.js b/x-pack/test/functional/apps/rollup_job/tsvb.js index 3b216bfb34b9b..4ef918aab09e4 100644 --- a/x-pack/test/functional/apps/rollup_job/tsvb.js +++ b/x-pack/test/functional/apps/rollup_job/tsvb.js @@ -43,6 +43,7 @@ export default function ({ getService, getPageObjects }) { await kibanaServer.uiSettings.replace({ defaultIndex: 'rollup', }); + await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': true }); }); it('create rollup tsvb', async () => { @@ -110,6 +111,7 @@ export default function ({ getService, getPageObjects }) { await kibanaServer.importExport.unload( 'x-pack/test/functional/fixtures/kbn_archiver/rollup/rollup.json' ); + await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': false }); await security.testUser.restoreDefaults(); }); }); diff --git a/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts b/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts index 3d4c30c1bfdd6..58f08a1dfb9f7 100644 --- a/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts +++ b/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts @@ -14,6 +14,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'security', 'error', 'savedObjects']); const kibanaServer = getService('kibanaServer'); let version: string = ''; + const find = getService('find'); describe('feature controls saved objects management', () => { before(async () => { @@ -108,12 +109,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(actual).to.be(true); }); }); - - describe('edit visualization', () => { + // From https://github.com/elastic/kibana/issues/59588 edit view became read-only json view + // test description changed from "edit" to "inspect" + // Skipping the test to allow code owners to delete or modify the test. + describe('inspect visualization', () => { before(async () => { await PageObjects.common.navigateToUrl( 'management', - 'kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed', + 'kibana/objects/visualization/75c3e060-1e7c-11e9-8488-65449e65d0ed', { shouldLoginIfPrompted: false, shouldUseHashForSubUrl: false, @@ -125,11 +128,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await testSubjects.existOrFail('savedObjectEditDelete'); }); - it('shows save button', async () => { + // no longer a feature + it.skip('shows save button', async () => { await testSubjects.existOrFail('savedObjectEditSave'); }); - it('has inputs without readonly attributes', async () => { + // no longer a feature + it.skip('has inputs without readonly attributes', async () => { const form = await testSubjects.find('savedObjectEditForm'); const inputs = await form.findAllByCssSelector('input'); expect(inputs.length).to.be.greaterThan(0); @@ -223,17 +228,30 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('edit visualization', () => { + // From https://github.com/elastic/kibana/issues/59588 edit view became read-only json view + // test description changed from "edit" to "inspect" + // Skipping the test to allow code owners to delete or modify the test. + describe('inspect visualization', () => { before(async () => { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaSavedObjects(); + const objects = await PageObjects.savedObjects.getRowTitles(); + expect(objects.includes('A Pie')).to.be(true); + await PageObjects.savedObjects.clickInspectByTitle('A Pie'); await PageObjects.common.navigateToUrl( 'management', - 'kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed', + 'kibana/objects/visualization/75c3e060-1e7c-11e9-8488-65449e65d0ed', { shouldLoginIfPrompted: false, shouldUseHashForSubUrl: false, } ); - await testSubjects.existOrFail('savedObjectsEdit'); + }); + + it('allows viewing the object', async () => { + const inspectContainer = await find.byClassName('kibanaCodeEditor'); + const visibleContainerText = await inspectContainer.getVisibleText(); + expect(visibleContainerText.includes('A Pie')); }); it('does not show delete button', async () => { @@ -244,7 +262,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await testSubjects.missingOrFail('savedObjectEditSave'); }); - it('has inputs with only readonly attributes', async () => { + // No longer a feature + it.skip('has inputs with only readonly attributes', async () => { const form = await testSubjects.find('savedObjectEditForm'); const inputs = await form.findAllByCssSelector('input'); expect(inputs.length).to.be.greaterThan(0); @@ -309,11 +328,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('edit visualization', () => { + describe('inspect visualization', () => { it('redirects to management home', async () => { await PageObjects.common.navigateToUrl( 'management', - 'kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed', + 'kibana/objects/visualization/75c3e060-1e7c-11e9-8488-65449e65d0ed', { shouldLoginIfPrompted: false, ensureCurrentUrl: false, diff --git a/x-pack/test/functional/apps/saved_objects_management/spaces_integration.ts b/x-pack/test/functional/apps/saved_objects_management/spaces_integration.ts index 28d04c1f9c54c..e4da0b341dce9 100644 --- a/x-pack/test/functional/apps/saved_objects_management/spaces_integration.ts +++ b/x-pack/test/functional/apps/saved_objects_management/spaces_integration.ts @@ -14,7 +14,6 @@ const getSpacePrefix = (spaceId: string) => { export default function ({ getPageObjects, getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const testSubjects = getService('testSubjects'); const PageObjects = getPageObjects([ 'common', 'security', @@ -22,9 +21,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'spaceSelector', 'settings', ]); + const find = getService('find'); const spaceId = 'space_1'; + const textIncludesAll = (text: string, items: string[]) => { + const bools = items.map((item) => !!text.includes(item)); + return bools.every((currBool) => currBool === true); + }; + describe('spaces integration', () => { before(async () => { await esArchiver.load( @@ -54,9 +59,19 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.common.waitUntilUrlIncludes(getSpacePrefix(spaceId)); - expect(await testSubjects.getAttribute(`savedObjects-editField-title`, 'value')).to.eql( - 'A Pie' - ); + const inspectContainer = await find.byClassName('kibanaCodeEditor'); + const visibleContainerText = await inspectContainer.getVisibleText(); + expect( + textIncludesAll(visibleContainerText, [ + 'A Pie', + 'title', + 'id', + 'type', + 'attributes', + 'references', + ]) + ).to.be(true); + expect(visibleContainerText.includes('A Pie')); }); }); } diff --git a/x-pack/test/functional/apps/uptime/certificates.ts b/x-pack/test/functional/apps/uptime/certificates.ts index 70affdf836072..610f07c183782 100644 --- a/x-pack/test/functional/apps/uptime/certificates.ts +++ b/x-pack/test/functional/apps/uptime/certificates.ts @@ -9,19 +9,27 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { makeCheck } from '../../../api_integration/apis/uptime/rest/helper/make_checks'; import { getSha256 } from '../../../api_integration/apis/uptime/rest/helper/make_tls'; +const BLANK_INDEX_PATH = 'x-pack/test/functional/es_archives/uptime/blank'; + export default ({ getPageObjects, getService }: FtrProviderContext) => { const { uptime } = getPageObjects(['uptime']); const uptimeService = getService('uptime'); + const esArchiver = getService('esArchiver'); const es = getService('es'); describe('certificates', function () { describe('empty certificates', function () { before(async () => { + await esArchiver.load(BLANK_INDEX_PATH); await makeCheck({ es }); await uptime.goToRoot(true); }); + after(async () => { + await esArchiver.unload(BLANK_INDEX_PATH); + }); + it('go to certs page', async () => { await uptimeService.common.waitUntilDataIsLoaded(); await uptimeService.cert.hasViewCertButton(); @@ -34,10 +42,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('with certs', function () { before(async () => { + await esArchiver.load(BLANK_INDEX_PATH); await makeCheck({ es, tls: true }); await uptime.goToRoot(true); }); + after(async () => { + await esArchiver.unload(BLANK_INDEX_PATH); + }); + beforeEach(async () => { await makeCheck({ es, tls: true }); }); diff --git a/x-pack/test/functional/apps/uptime/index.ts b/x-pack/test/functional/apps/uptime/index.ts index 501fec5002666..ef5a4e576da88 100644 --- a/x-pack/test/functional/apps/uptime/index.ts +++ b/x-pack/test/functional/apps/uptime/index.ts @@ -42,7 +42,7 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => { const uptime = getService('uptime'); describe('Uptime app', function () { - this.tags('ciGroup6'); + this.tags('ciGroup10'); beforeEach('delete settings', async () => { await deleteUptimeSettingsObject(server); @@ -80,5 +80,9 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => { loadTestFile(require.resolve('./ml_anomaly')); loadTestFile(require.resolve('./feature_controls')); }); + + describe('mappings error state', () => { + loadTestFile(require.resolve('./missing_mappings')); + }); }); }; diff --git a/x-pack/test/functional/apps/uptime/missing_mappings.ts b/x-pack/test/functional/apps/uptime/missing_mappings.ts new file mode 100644 index 0000000000000..2483aa45ecef9 --- /dev/null +++ b/x-pack/test/functional/apps/uptime/missing_mappings.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; +import { makeCheck } from '../../../api_integration/apis/uptime/rest/helper/make_checks'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const { common } = getPageObjects(['common']); + const uptimeService = getService('uptime'); + + const es = getService('es'); + describe('missing mappings', function () { + before(async () => { + await makeCheck({ es }); + await common.navigateToApp('uptime'); + }); + + it('redirects to mappings error page', async () => { + await uptimeService.common.hasMappingsError(); + }); + }); +}; diff --git a/x-pack/test/functional/apps/uptime/synthetics_integration.ts b/x-pack/test/functional/apps/uptime/synthetics_integration.ts index 1fe13227d2546..e403c4d25097c 100644 --- a/x-pack/test/functional/apps/uptime/synthetics_integration.ts +++ b/x-pack/test/functional/apps/uptime/synthetics_integration.ts @@ -130,7 +130,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); describe('When on the Synthetics Integration Policy Create Page', function () { - this.tags(['ciGroup6']); + this.tags(['ciGroup10']); const basicConfig = { name: monitorName, apmServiceName: 'Sample APM Service', diff --git a/x-pack/test/functional/apps/visualize/reporting.ts b/x-pack/test/functional/apps/visualize/reporting.ts index 1e629927ffb4d..6ad1069fade20 100644 --- a/x-pack/test/functional/apps/visualize/reporting.ts +++ b/x-pack/test/functional/apps/visualize/reporting.ts @@ -20,6 +20,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'reporting', 'common', 'dashboard', + 'timePicker', 'visualize', 'visEditor', ]); @@ -52,7 +53,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('becomes available when saved', async () => { - await PageObjects.reporting.setTimepickerInDataRange(); + const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; + const toTime = 'Aug 23, 2019 @ 16:18:51.821'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + await PageObjects.visEditor.clickBucket('X-axis'); await PageObjects.visEditor.selectAggregation('Date Histogram'); await PageObjects.visEditor.clickGo(); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 95a962388cdd6..daa3ef3872cfb 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -32,7 +32,6 @@ export default async function ({ readConfigFile }) { resolve(__dirname, './apps/discover'), resolve(__dirname, './apps/security'), resolve(__dirname, './apps/spaces'), - resolve(__dirname, './apps/lens'), resolve(__dirname, './apps/logstash'), resolve(__dirname, './apps/grok_debugger'), resolve(__dirname, './apps/infra'), @@ -58,6 +57,7 @@ export default async function ({ readConfigFile }) { resolve(__dirname, './apps/reporting_management'), resolve(__dirname, './apps/management'), resolve(__dirname, './apps/reporting'), + resolve(__dirname, './apps/lens'), // smokescreen tests cause flakiness in other tests // This license_management file must be last because it is destructive. resolve(__dirname, './apps/license_management'), diff --git a/x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions/data.json.gz b/x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions/data.json.gz new file mode 100644 index 0000000000000..5f73dfd89d166 Binary files /dev/null and b/x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions/data.json.gz differ diff --git a/x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions/mappings.json b/x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions/mappings.json new file mode 100644 index 0000000000000..c6b71a2613859 --- /dev/null +++ b/x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions/mappings.json @@ -0,0 +1,2954 @@ +{ + "type": "index", + "value": { + "aliases": { + ".kibana": { + }, + ".kibana_7.13.4": { + } + }, + "index": ".kibana_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "action": "6e96ac5e648f57523879661ea72525b7", + "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", + "alert": "d75d3b0e95fe394753d73d8f7952cd7d", + "api_key_pending_invalidation": "16f515278a295f6245149ad7c5ddedb7", + "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", + "apm-telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "app_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "application_usage_daily": "43b8830d5d0df85a6823d290885fc9fd", + "application_usage_totals": "3d1b76c39bfb2cc8296b024d73854724", + "application_usage_transactional": "3d1b76c39bfb2cc8296b024d73854724", + "canvas-element": "7390014e1091044523666d97247392fc", + "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", + "canvas-workpad-template": "ae2673f678281e2c055d764b153e9715", + "cases": "7c28a18fbac7c2a4e79449e9802ef476", + "cases-comments": "112cefc2b6737e613a8ef033234755e6", + "cases-configure": "387c5f3a3bda7e0ae0dd4e106f914a69", + "cases-connector-mappings": "6bc7e49411d38be4969dc6aa8bd43776", + "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", + "config": "c63748b75f39d0c54de12d12c1ccbc20", + "core-usage-stats": "3d1b76c39bfb2cc8296b024d73854724", + "coreMigrationVersion": "2f4316de49999235636386fe51dc06c1", + "dashboard": "40554caf09725935e2c02e02563a2d07", + "endpoint:user-artifact": "4a11183eee21e6fbad864f7a30b39ad0", + "endpoint:user-artifact-manifest": "a0d7b04ad405eed54d76e279c3727862", + "enterprise_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "epm-packages": "0cbbb16506734d341a96aaed65ec6413", + "epm-packages-assets": "44621b2f6052ef966da47b7c3a00f33b", + "exception-list": "baf108c9934dda844921f692a513adae", + "exception-list-agnostic": "baf108c9934dda844921f692a513adae", + "file-upload-usage-collection-telemetry": "a34fbb8e3263d105044869264860c697", + "fleet-agent-actions": "9511b565b1cc6441a42033db3d5de8e9", + "fleet-agents": "59fd74f819f028f8555776db198d2562", + "fleet-enrollment-api-keys": "a69ef7ae661dab31561d6c6f052ef2a7", + "fleet-preconfiguration-deletion-record": "4c36f199189a367e43541f236141204c", + "graph-workspace": "27a94b2edcb0610c6aea54a7c56d7752", + "index-pattern": "45915a1ad866812242df474eb0479052", + "infrastructure-ui-source": "3d1b76c39bfb2cc8296b024d73854724", + "ingest-agent-policies": "cb4dbcc5a695e53f40a359303cb6286f", + "ingest-outputs": "1acb789ca37cbee70259ca79e124d9ad", + "ingest-package-policies": "c91ca97b1ff700f0fc64dc6b13d65a85", + "ingest_manager_settings": "f159646d76ab261bfbf8ef504d9631e4", + "inventory-view": "3d1b76c39bfb2cc8296b024d73854724", + "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", + "legacy-url-alias": "3d1b76c39bfb2cc8296b024d73854724", + "lens": "52346cfec69ff7b47d5f0c12361a2797", + "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", + "map": "9134b47593116d7953f6adba096fc463", + "maps-telemetry": "5ef305b18111b77789afefbd36b66171", + "metrics-explorer-view": "3d1b76c39bfb2cc8296b024d73854724", + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "ml-job": "3bb64c31915acf93fc724af137a0891b", + "ml-module": "46ef4f0d6682636f0fff9799d6a2d7ac", + "monitoring-telemetry": "2669d5ec15e82391cf58df4294ee9c68", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "originId": "2f4316de49999235636386fe51dc06c1", + "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", + "search": "db2c00e39b36f40930a3b9fc71c823e1", + "search-session": "4e238afeeaa2550adef326e140454265", + "search-telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "security-rule": "8ae39a88fc70af3375b7050e8d8d5cc7", + "security-solution-signals-migration": "72761fd374ca11122ac8025a92b84fca", + "siem-detection-engine-rule-actions": "6569b288c169539db10cb262bf79de18", + "siem-detection-engine-rule-status": "ae783f41c6937db6b7a2ef5c93a9e9b0", + "siem-ui-timeline": "3e97beae13cdfc6d62bc1846119f7276", + "siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084", + "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29", + "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", + "spaces-usage-stats": "3d1b76c39bfb2cc8296b024d73854724", + "tag": "83d55da58f6530f7055415717ec06474", + "telemetry": "36a616f7026dfa617d6655df850fe16d", + "timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf", + "type": "2f4316de49999235636386fe51dc06c1", + "ui-counter": "0d409297dc5ebe1e3a1da691c6ee32e3", + "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0", + "upgrade-assistant-reindex-operation": "215107c281839ea9b3ad5f6419819763", + "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", + "uptime-dynamic-settings": "3d1b76c39bfb2cc8296b024d73854724", + "url": "c7f66a0df8b1b52f17c28c4adb111105", + "usage-counters": "8cc260bdceffec4ffc3ad165c97dc1b4", + "visualization": "f819cf6636b75c9e76ba733a0c6ef355", + "workplace_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724" + } + }, + "dynamic": "strict", + "properties": { + "action": { + "properties": { + "actionTypeId": { + "type": "keyword" + }, + "config": { + "enabled": false, + "type": "object" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "secrets": { + "type": "binary" + } + } + }, + "action_task_params": { + "properties": { + "actionId": { + "type": "keyword" + }, + "apiKey": { + "type": "binary" + }, + "params": { + "enabled": false, + "type": "object" + } + } + }, + "alert": { + "properties": { + "actions": { + "properties": { + "actionRef": { + "type": "keyword" + }, + "actionTypeId": { + "type": "keyword" + }, + "group": { + "type": "keyword" + }, + "params": { + "enabled": false, + "type": "object" + } + }, + "type": "nested" + }, + "alertTypeId": { + "type": "keyword" + }, + "apiKey": { + "type": "binary" + }, + "apiKeyOwner": { + "type": "keyword" + }, + "consumer": { + "type": "keyword" + }, + "createdAt": { + "type": "date" + }, + "createdBy": { + "type": "keyword" + }, + "enabled": { + "type": "boolean" + }, + "executionStatus": { + "properties": { + "error": { + "properties": { + "message": { + "type": "keyword" + }, + "reason": { + "type": "keyword" + } + } + }, + "lastExecutionDate": { + "type": "date" + }, + "status": { + "type": "keyword" + } + } + }, + "meta": { + "properties": { + "versionApiKeyLastmodified": { + "type": "keyword" + } + } + }, + "muteAll": { + "type": "boolean" + }, + "mutedInstanceIds": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "notifyWhen": { + "type": "keyword" + }, + "params": { + "ignore_above": 4096, + "type": "flattened" + }, + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } + }, + "scheduledTaskId": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "throttle": { + "type": "keyword" + }, + "updatedAt": { + "type": "date" + }, + "updatedBy": { + "type": "keyword" + } + } + }, + "api_key_pending_invalidation": { + "properties": { + "apiKeyId": { + "type": "keyword" + }, + "createdAt": { + "type": "date" + } + } + }, + "apm-indices": { + "properties": { + "apm_oss": { + "properties": { + "errorIndices": { + "type": "keyword" + }, + "metricsIndices": { + "type": "keyword" + }, + "onboardingIndices": { + "type": "keyword" + }, + "sourcemapIndices": { + "type": "keyword" + }, + "spanIndices": { + "type": "keyword" + }, + "transactionIndices": { + "type": "keyword" + } + } + } + } + }, + "apm-telemetry": { + "dynamic": "false", + "type": "object" + }, + "app_search_telemetry": { + "dynamic": "false", + "type": "object" + }, + "application_usage_daily": { + "dynamic": "false", + "properties": { + "timestamp": { + "type": "date" + } + } + }, + "application_usage_totals": { + "dynamic": "false", + "type": "object" + }, + "application_usage_transactional": { + "dynamic": "false", + "type": "object" + }, + "canvas-element": { + "dynamic": "false", + "properties": { + "@created": { + "type": "date" + }, + "@timestamp": { + "type": "date" + }, + "content": { + "type": "text" + }, + "help": { + "type": "text" + }, + "image": { + "type": "text" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "canvas-workpad": { + "dynamic": "false", + "properties": { + "@created": { + "type": "date" + }, + "@timestamp": { + "type": "date" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "canvas-workpad-template": { + "dynamic": "false", + "properties": { + "help": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "tags": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "template_key": { + "type": "keyword" + } + } + }, + "cases": { + "properties": { + "closed_at": { + "type": "date" + }, + "closed_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "connector": { + "properties": { + "fields": { + "properties": { + "key": { + "type": "text" + }, + "value": { + "type": "text" + } + } + }, + "id": { + "type": "keyword" + }, + "name": { + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "created_at": { + "type": "date" + }, + "created_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "description": { + "type": "text" + }, + "external_service": { + "properties": { + "connector_id": { + "type": "keyword" + }, + "connector_name": { + "type": "keyword" + }, + "external_id": { + "type": "keyword" + }, + "external_title": { + "type": "text" + }, + "external_url": { + "type": "text" + }, + "pushed_at": { + "type": "date" + }, + "pushed_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "settings": { + "properties": { + "syncAlerts": { + "type": "boolean" + } + } + }, + "status": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "title": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "cases-comments": { + "properties": { + "alertId": { + "type": "keyword" + }, + "associationType": { + "type": "keyword" + }, + "comment": { + "type": "text" + }, + "created_at": { + "type": "date" + }, + "created_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "index": { + "type": "keyword" + }, + "pushed_at": { + "type": "date" + }, + "pushed_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "cases-configure": { + "properties": { + "closure_type": { + "type": "keyword" + }, + "connector": { + "properties": { + "fields": { + "properties": { + "key": { + "type": "text" + }, + "value": { + "type": "text" + } + } + }, + "id": { + "type": "keyword" + }, + "name": { + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "created_at": { + "type": "date" + }, + "created_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "cases-connector-mappings": { + "properties": { + "mappings": { + "properties": { + "action_type": { + "type": "keyword" + }, + "source": { + "type": "keyword" + }, + "target": { + "type": "keyword" + } + } + } + } + }, + "cases-user-actions": { + "properties": { + "action": { + "type": "keyword" + }, + "action_at": { + "type": "date" + }, + "action_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "action_field": { + "type": "keyword" + }, + "new_value": { + "type": "text" + }, + "old_value": { + "type": "text" + } + } + }, + "config": { + "dynamic": "false", + "properties": { + "buildNum": { + "type": "keyword" + } + } + }, + "core-usage-stats": { + "dynamic": "false", + "type": "object" + }, + "coreMigrationVersion": { + "type": "keyword" + }, + "dashboard": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "optionsJSON": { + "index": false, + "type": "text" + }, + "panelsJSON": { + "index": false, + "type": "text" + }, + "refreshInterval": { + "properties": { + "display": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "pause": { + "doc_values": false, + "index": false, + "type": "boolean" + }, + "section": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "value": { + "doc_values": false, + "index": false, + "type": "integer" + } + } + }, + "timeFrom": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "timeRestore": { + "doc_values": false, + "index": false, + "type": "boolean" + }, + "timeTo": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "endpoint:user-artifact": { + "properties": { + "body": { + "type": "binary" + }, + "compressionAlgorithm": { + "index": false, + "type": "keyword" + }, + "created": { + "index": false, + "type": "date" + }, + "decodedSha256": { + "index": false, + "type": "keyword" + }, + "decodedSize": { + "index": false, + "type": "long" + }, + "encodedSha256": { + "type": "keyword" + }, + "encodedSize": { + "index": false, + "type": "long" + }, + "encryptionAlgorithm": { + "index": false, + "type": "keyword" + }, + "identifier": { + "type": "keyword" + } + } + }, + "endpoint:user-artifact-manifest": { + "properties": { + "artifacts": { + "properties": { + "artifactId": { + "index": false, + "type": "keyword" + }, + "policyId": { + "index": false, + "type": "keyword" + } + }, + "type": "nested" + }, + "created": { + "index": false, + "type": "date" + }, + "schemaVersion": { + "type": "keyword" + }, + "semanticVersion": { + "index": false, + "type": "keyword" + } + } + }, + "enterprise_search_telemetry": { + "dynamic": "false", + "type": "object" + }, + "epm-packages": { + "properties": { + "es_index_patterns": { + "enabled": false, + "type": "object" + }, + "install_source": { + "type": "keyword" + }, + "install_started_at": { + "type": "date" + }, + "install_status": { + "type": "keyword" + }, + "install_version": { + "type": "keyword" + }, + "installed_es": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "installed_kibana": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "internal": { + "type": "boolean" + }, + "name": { + "type": "keyword" + }, + "package_assets": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "removable": { + "type": "boolean" + }, + "version": { + "type": "keyword" + } + } + }, + "epm-packages-assets": { + "properties": { + "asset_path": { + "type": "keyword" + }, + "data_base64": { + "type": "binary" + }, + "data_utf8": { + "index": false, + "type": "text" + }, + "install_source": { + "type": "keyword" + }, + "media_type": { + "type": "keyword" + }, + "package_name": { + "type": "keyword" + }, + "package_version": { + "type": "keyword" + } + } + }, + "exception-list": { + "properties": { + "_tags": { + "type": "keyword" + }, + "comments": { + "properties": { + "comment": { + "type": "keyword" + }, + "created_at": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "updated_at": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "created_at": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "entries": { + "properties": { + "entries": { + "properties": { + "field": { + "type": "keyword" + }, + "operator": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + } + } + }, + "field": { + "type": "keyword" + }, + "list": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "operator": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + } + } + }, + "immutable": { + "type": "boolean" + }, + "item_id": { + "type": "keyword" + }, + "list_id": { + "type": "keyword" + }, + "list_type": { + "type": "keyword" + }, + "meta": { + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + }, + "os_types": { + "type": "keyword" + }, + "tags": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + }, + "tie_breaker_id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "exception-list-agnostic": { + "properties": { + "_tags": { + "type": "keyword" + }, + "comments": { + "properties": { + "comment": { + "type": "keyword" + }, + "created_at": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "updated_at": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "created_at": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "entries": { + "properties": { + "entries": { + "properties": { + "field": { + "type": "keyword" + }, + "operator": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + } + } + }, + "field": { + "type": "keyword" + }, + "list": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "operator": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + } + } + }, + "immutable": { + "type": "boolean" + }, + "item_id": { + "type": "keyword" + }, + "list_id": { + "type": "keyword" + }, + "list_type": { + "type": "keyword" + }, + "meta": { + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + }, + "os_types": { + "type": "keyword" + }, + "tags": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + }, + "tie_breaker_id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "file-upload-usage-collection-telemetry": { + "properties": { + "file_upload": { + "properties": { + "index_creation_count": { + "type": "long" + } + } + } + } + }, + "fleet-agent-actions": { + "properties": { + "ack_data": { + "type": "text" + }, + "agent_id": { + "type": "keyword" + }, + "created_at": { + "type": "date" + }, + "data": { + "type": "binary" + }, + "policy_id": { + "type": "keyword" + }, + "policy_revision": { + "type": "integer" + }, + "sent_at": { + "type": "date" + }, + "type": { + "type": "keyword" + } + } + }, + "fleet-agents": { + "properties": { + "access_api_key_id": { + "type": "keyword" + }, + "active": { + "type": "boolean" + }, + "current_error_events": { + "index": false, + "type": "text" + }, + "default_api_key": { + "type": "binary" + }, + "default_api_key_id": { + "type": "keyword" + }, + "enrolled_at": { + "type": "date" + }, + "last_checkin": { + "type": "date" + }, + "last_checkin_status": { + "type": "keyword" + }, + "last_updated": { + "type": "date" + }, + "local_metadata": { + "type": "flattened" + }, + "packages": { + "type": "keyword" + }, + "policy_id": { + "type": "keyword" + }, + "policy_revision": { + "type": "integer" + }, + "type": { + "type": "keyword" + }, + "unenrolled_at": { + "type": "date" + }, + "unenrollment_started_at": { + "type": "date" + }, + "updated_at": { + "type": "date" + }, + "upgrade_started_at": { + "type": "date" + }, + "upgraded_at": { + "type": "date" + }, + "user_provided_metadata": { + "type": "flattened" + }, + "version": { + "type": "keyword" + } + } + }, + "fleet-enrollment-api-keys": { + "properties": { + "active": { + "type": "boolean" + }, + "api_key": { + "type": "binary" + }, + "api_key_id": { + "type": "keyword" + }, + "created_at": { + "type": "date" + }, + "expire_at": { + "type": "date" + }, + "name": { + "type": "keyword" + }, + "policy_id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + }, + "fleet-preconfiguration-deletion-record": { + "properties": { + "id": { + "type": "keyword" + } + } + }, + "graph-workspace": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "legacyIndexPatternRef": { + "index": false, + "type": "text" + }, + "numLinks": { + "type": "integer" + }, + "numVertices": { + "type": "integer" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "wsState": { + "type": "text" + } + } + }, + "index-pattern": { + "dynamic": "false", + "properties": { + "title": { + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "infrastructure-ui-source": { + "dynamic": "false", + "type": "object" + }, + "ingest-agent-policies": { + "properties": { + "description": { + "type": "text" + }, + "is_default": { + "type": "boolean" + }, + "is_default_fleet_server": { + "type": "boolean" + }, + "is_managed": { + "type": "boolean" + }, + "is_preconfigured": { + "type": "keyword" + }, + "monitoring_enabled": { + "index": false, + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "namespace": { + "type": "keyword" + }, + "package_policies": { + "type": "keyword" + }, + "revision": { + "type": "integer" + }, + "status": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "ingest-outputs": { + "properties": { + "ca_sha256": { + "index": false, + "type": "keyword" + }, + "config": { + "type": "flattened" + }, + "config_yaml": { + "type": "text" + }, + "hosts": { + "type": "keyword" + }, + "is_default": { + "type": "boolean" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "ingest-package-policies": { + "properties": { + "created_at": { + "type": "date" + }, + "created_by": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "enabled": { + "type": "boolean" + }, + "inputs": { + "enabled": false, + "properties": { + "compiled_input": { + "type": "flattened" + }, + "config": { + "type": "flattened" + }, + "enabled": { + "type": "boolean" + }, + "streams": { + "properties": { + "compiled_stream": { + "type": "flattened" + }, + "config": { + "type": "flattened" + }, + "data_stream": { + "properties": { + "dataset": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "keyword" + }, + "vars": { + "type": "flattened" + } + }, + "type": "nested" + }, + "type": { + "type": "keyword" + }, + "vars": { + "type": "flattened" + } + }, + "type": "nested" + }, + "name": { + "type": "keyword" + }, + "namespace": { + "type": "keyword" + }, + "output_id": { + "type": "keyword" + }, + "package": { + "properties": { + "name": { + "type": "keyword" + }, + "title": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "policy_id": { + "type": "keyword" + }, + "revision": { + "type": "integer" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "ingest_manager_settings": { + "properties": { + "fleet_server_hosts": { + "type": "keyword" + }, + "has_seen_add_data_notice": { + "index": false, + "type": "boolean" + }, + "has_seen_fleet_migration_notice": { + "index": false, + "type": "boolean" + } + } + }, + "inventory-view": { + "dynamic": "false", + "type": "object" + }, + "kql-telemetry": { + "properties": { + "optInCount": { + "type": "long" + }, + "optOutCount": { + "type": "long" + } + } + }, + "legacy-url-alias": { + "dynamic": "false", + "type": "object" + }, + "lens": { + "properties": { + "description": { + "type": "text" + }, + "expression": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "state": { + "type": "flattened" + }, + "title": { + "type": "text" + }, + "visualizationType": { + "type": "keyword" + } + } + }, + "lens-ui-telemetry": { + "properties": { + "count": { + "type": "integer" + }, + "date": { + "type": "date" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "map": { + "properties": { + "bounds": { + "dynamic": "false", + "type": "object" + }, + "description": { + "type": "text" + }, + "layerListJSON": { + "type": "text" + }, + "mapStateJSON": { + "type": "text" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "maps-telemetry": { + "enabled": false, + "type": "object" + }, + "metrics-explorer-view": { + "dynamic": "false", + "type": "object" + }, + "migrationVersion": { + "dynamic": "true", + "properties": { + "action": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "alert": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "cases": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "cases-comments": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "cases-configure": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "cases-user-actions": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "config": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "dashboard": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "exception-list-agnostic": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "index-pattern": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "ingest-agent-policies": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "ingest-outputs": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "ingest-package-policies": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "ingest_manager_settings": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "search": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "search-session": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "search-telemetry": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "siem-detection-engine-rule-actions": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "space": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "visualization": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "ml-job": { + "properties": { + "datafeed_id": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "job_id": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "ml-module": { + "dynamic": "false", + "properties": { + "datafeeds": { + "type": "object" + }, + "defaultIndexPattern": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "description": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "id": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "jobs": { + "type": "object" + }, + "logo": { + "type": "object" + }, + "query": { + "type": "object" + }, + "title": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "type": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "monitoring-telemetry": { + "properties": { + "reportedClusterUuids": { + "type": "keyword" + } + } + }, + "namespace": { + "type": "keyword" + }, + "namespaces": { + "type": "keyword" + }, + "originId": { + "type": "keyword" + }, + "query": { + "properties": { + "description": { + "type": "text" + }, + "filters": { + "enabled": false, + "type": "object" + }, + "query": { + "properties": { + "language": { + "type": "keyword" + }, + "query": { + "index": false, + "type": "keyword" + } + } + }, + "timefilter": { + "enabled": false, + "type": "object" + }, + "title": { + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "sample-data-telemetry": { + "properties": { + "installCount": { + "type": "long" + }, + "unInstallCount": { + "type": "long" + } + } + }, + "search": { + "properties": { + "columns": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "description": { + "type": "text" + }, + "grid": { + "enabled": false, + "type": "object" + }, + "hideChart": { + "doc_values": false, + "index": false, + "type": "boolean" + }, + "hits": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "sort": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "search-session": { + "properties": { + "appId": { + "type": "keyword" + }, + "completed": { + "type": "date" + }, + "created": { + "type": "date" + }, + "expires": { + "type": "date" + }, + "idMapping": { + "enabled": false, + "type": "object" + }, + "initialState": { + "enabled": false, + "type": "object" + }, + "name": { + "type": "keyword" + }, + "persisted": { + "type": "boolean" + }, + "realmName": { + "type": "keyword" + }, + "realmType": { + "type": "keyword" + }, + "restoreState": { + "enabled": false, + "type": "object" + }, + "sessionId": { + "type": "keyword" + }, + "status": { + "type": "keyword" + }, + "touched": { + "type": "date" + }, + "urlGeneratorId": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "search-telemetry": { + "dynamic": "false", + "type": "object" + }, + "security-rule": { + "dynamic": "false", + "properties": { + "name": { + "type": "keyword" + }, + "rule_id": { + "type": "keyword" + }, + "version": { + "type": "long" + } + } + }, + "security-solution-signals-migration": { + "properties": { + "created": { + "index": false, + "type": "date" + }, + "createdBy": { + "index": false, + "type": "text" + }, + "destinationIndex": { + "index": false, + "type": "keyword" + }, + "error": { + "index": false, + "type": "text" + }, + "sourceIndex": { + "type": "keyword" + }, + "status": { + "index": false, + "type": "keyword" + }, + "taskId": { + "index": false, + "type": "keyword" + }, + "updated": { + "index": false, + "type": "date" + }, + "updatedBy": { + "index": false, + "type": "text" + }, + "version": { + "type": "long" + } + } + }, + "siem-detection-engine-rule-actions": { + "properties": { + "actions": { + "properties": { + "action_type_id": { + "type": "keyword" + }, + "group": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "params": { + "enabled": false, + "type": "object" + } + } + }, + "alertThrottle": { + "type": "keyword" + }, + "ruleAlertId": { + "type": "keyword" + }, + "ruleThrottle": { + "type": "keyword" + } + } + }, + "siem-detection-engine-rule-status": { + "properties": { + "alertId": { + "type": "keyword" + }, + "bulkCreateTimeDurations": { + "type": "float" + }, + "gap": { + "type": "text" + }, + "lastFailureAt": { + "type": "date" + }, + "lastFailureMessage": { + "type": "text" + }, + "lastLookBackDate": { + "type": "date" + }, + "lastSuccessAt": { + "type": "date" + }, + "lastSuccessMessage": { + "type": "text" + }, + "searchAfterTimeDurations": { + "type": "float" + }, + "status": { + "type": "keyword" + }, + "statusDate": { + "type": "date" + } + } + }, + "siem-ui-timeline": { + "properties": { + "columns": { + "properties": { + "aggregatable": { + "type": "boolean" + }, + "category": { + "type": "keyword" + }, + "columnHeaderType": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "example": { + "type": "text" + }, + "id": { + "type": "keyword" + }, + "indexes": { + "type": "keyword" + }, + "name": { + "type": "text" + }, + "placeholder": { + "type": "text" + }, + "searchable": { + "type": "boolean" + }, + "type": { + "type": "keyword" + } + } + }, + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "dataProviders": { + "properties": { + "and": { + "properties": { + "enabled": { + "type": "boolean" + }, + "excluded": { + "type": "boolean" + }, + "id": { + "type": "keyword" + }, + "kqlQuery": { + "type": "text" + }, + "name": { + "type": "text" + }, + "queryMatch": { + "properties": { + "displayField": { + "type": "text" + }, + "displayValue": { + "type": "text" + }, + "field": { + "type": "text" + }, + "operator": { + "type": "text" + }, + "value": { + "type": "text" + } + } + }, + "type": { + "type": "text" + } + } + }, + "enabled": { + "type": "boolean" + }, + "excluded": { + "type": "boolean" + }, + "id": { + "type": "keyword" + }, + "kqlQuery": { + "type": "text" + }, + "name": { + "type": "text" + }, + "queryMatch": { + "properties": { + "displayField": { + "type": "text" + }, + "displayValue": { + "type": "text" + }, + "field": { + "type": "text" + }, + "operator": { + "type": "text" + }, + "value": { + "type": "text" + } + } + }, + "type": { + "type": "text" + } + } + }, + "dateRange": { + "properties": { + "end": { + "type": "date" + }, + "start": { + "type": "date" + } + } + }, + "description": { + "type": "text" + }, + "eqlOptions": { + "properties": { + "eventCategoryField": { + "type": "text" + }, + "query": { + "type": "text" + }, + "size": { + "type": "text" + }, + "tiebreakerField": { + "type": "text" + }, + "timestampField": { + "type": "text" + } + } + }, + "eventType": { + "type": "keyword" + }, + "excludedRowRendererIds": { + "type": "text" + }, + "favorite": { + "properties": { + "favoriteDate": { + "type": "date" + }, + "fullName": { + "type": "text" + }, + "keySearch": { + "type": "text" + }, + "userName": { + "type": "text" + } + } + }, + "filters": { + "properties": { + "exists": { + "type": "text" + }, + "match_all": { + "type": "text" + }, + "meta": { + "properties": { + "alias": { + "type": "text" + }, + "controlledBy": { + "type": "text" + }, + "disabled": { + "type": "boolean" + }, + "field": { + "type": "text" + }, + "formattedValue": { + "type": "text" + }, + "index": { + "type": "keyword" + }, + "key": { + "type": "keyword" + }, + "negate": { + "type": "boolean" + }, + "params": { + "type": "text" + }, + "type": { + "type": "keyword" + }, + "value": { + "type": "text" + } + } + }, + "missing": { + "type": "text" + }, + "query": { + "type": "text" + }, + "range": { + "type": "text" + }, + "script": { + "type": "text" + } + } + }, + "indexNames": { + "type": "text" + }, + "kqlMode": { + "type": "keyword" + }, + "kqlQuery": { + "properties": { + "filterQuery": { + "properties": { + "kuery": { + "properties": { + "expression": { + "type": "text" + }, + "kind": { + "type": "keyword" + } + } + }, + "serializedQuery": { + "type": "text" + } + } + } + } + }, + "savedQueryId": { + "type": "keyword" + }, + "sort": { + "dynamic": "false", + "properties": { + "columnId": { + "type": "keyword" + }, + "columnType": { + "type": "keyword" + }, + "sortDirection": { + "type": "keyword" + } + } + }, + "status": { + "type": "keyword" + }, + "templateTimelineId": { + "type": "text" + }, + "templateTimelineVersion": { + "type": "integer" + }, + "timelineType": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "siem-ui-timeline-note": { + "properties": { + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "eventId": { + "type": "keyword" + }, + "note": { + "type": "text" + }, + "timelineId": { + "type": "keyword" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "siem-ui-timeline-pinned-event": { + "properties": { + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "eventId": { + "type": "keyword" + }, + "timelineId": { + "type": "keyword" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "space": { + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "disabledFeatures": { + "type": "keyword" + }, + "imageUrl": { + "index": false, + "type": "text" + }, + "initials": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "spaces-usage-stats": { + "dynamic": "false", + "type": "object" + }, + "tag": { + "properties": { + "color": { + "type": "text" + }, + "description": { + "type": "text" + }, + "name": { + "type": "text" + } + } + }, + "telemetry": { + "properties": { + "allowChangingOptInStatus": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "lastReported": { + "type": "date" + }, + "lastVersionChecked": { + "type": "keyword" + }, + "reportFailureCount": { + "type": "integer" + }, + "reportFailureVersion": { + "type": "keyword" + }, + "sendUsageFrom": { + "type": "keyword" + }, + "userHasSeenNotice": { + "type": "boolean" + } + } + }, + "timelion-sheet": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "timelion_chart_height": { + "type": "integer" + }, + "timelion_columns": { + "type": "integer" + }, + "timelion_interval": { + "type": "keyword" + }, + "timelion_other_interval": { + "type": "keyword" + }, + "timelion_rows": { + "type": "integer" + }, + "timelion_sheet": { + "type": "text" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "type": { + "type": "keyword" + }, + "ui-counter": { + "properties": { + "count": { + "type": "integer" + } + } + }, + "ui-metric": { + "properties": { + "count": { + "type": "integer" + } + } + }, + "updated_at": { + "type": "date" + }, + "upgrade-assistant-reindex-operation": { + "properties": { + "errorMessage": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "indexName": { + "type": "keyword" + }, + "lastCompletedStep": { + "type": "long" + }, + "locked": { + "type": "date" + }, + "newIndexName": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "reindexOptions": { + "properties": { + "openAndClose": { + "type": "boolean" + }, + "queueSettings": { + "properties": { + "queuedAt": { + "type": "long" + }, + "startedAt": { + "type": "long" + } + } + } + } + }, + "reindexTaskId": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "reindexTaskPercComplete": { + "type": "float" + }, + "runningReindexCount": { + "type": "integer" + }, + "status": { + "type": "integer" + } + } + }, + "upgrade-assistant-telemetry": { + "properties": { + "features": { + "properties": { + "deprecation_logging": { + "properties": { + "enabled": { + "null_value": true, + "type": "boolean" + } + } + } + } + }, + "ui_open": { + "properties": { + "cluster": { + "null_value": 0, + "type": "long" + }, + "indices": { + "null_value": 0, + "type": "long" + }, + "overview": { + "null_value": 0, + "type": "long" + } + } + }, + "ui_reindex": { + "properties": { + "close": { + "null_value": 0, + "type": "long" + }, + "open": { + "null_value": 0, + "type": "long" + }, + "start": { + "null_value": 0, + "type": "long" + }, + "stop": { + "null_value": 0, + "type": "long" + } + } + } + } + }, + "uptime-dynamic-settings": { + "dynamic": "false", + "type": "object" + }, + "url": { + "properties": { + "accessCount": { + "type": "long" + }, + "accessDate": { + "type": "date" + }, + "createDate": { + "type": "date" + }, + "url": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "usage-counters": { + "dynamic": "false", + "properties": { + "domainId": { + "type": "keyword" + } + } + }, + "visualization": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "savedSearchRefName": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "index": false, + "type": "text" + }, + "version": { + "type": "integer" + }, + "visState": { + "index": false, + "type": "text" + } + } + }, + "workplace_search_telemetry": { + "dynamic": "false", + "type": "object" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "10", + "refresh_interval": "1s" + } + } + } +} \ No newline at end of file diff --git a/x-pack/test/functional/es_archives/infra/alerts_test_data/data.json.gz b/x-pack/test/functional/es_archives/infra/alerts_test_data/data.json.gz index 1c76205f4caa2..92815ba80a3a5 100644 Binary files a/x-pack/test/functional/es_archives/infra/alerts_test_data/data.json.gz and b/x-pack/test/functional/es_archives/infra/alerts_test_data/data.json.gz differ diff --git a/x-pack/test/functional/es_archives/security_solution/timelines/7.15.0/data.json.gz b/x-pack/test/functional/es_archives/security_solution/timelines/7.15.0/data.json.gz index e942ef732b22a..91e3e459f826b 100644 Binary files a/x-pack/test/functional/es_archives/security_solution/timelines/7.15.0/data.json.gz and b/x-pack/test/functional/es_archives/security_solution/timelines/7.15.0/data.json.gz differ diff --git a/x-pack/test/functional/fixtures/kbn_archiver/maps.json b/x-pack/test/functional/fixtures/kbn_archiver/maps.json index b17b4a64f3485..78e49997d5c9e 100644 --- a/x-pack/test/functional/fixtures/kbn_archiver/maps.json +++ b/x-pack/test/functional/fixtures/kbn_archiver/maps.json @@ -684,7 +684,7 @@ { "attributes": { "description": "", - "layerListJSON": "[{\"sourceDescriptor\":{\"type\":\"KIBANA_TILEMAP\"},\"id\":\"ap0ys\",\"label\":\"Custom_TMS\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"REGIONMAP_FILE\",\"name\":\"nameThatDoesNotExitForKibanaRegionmapSource\"},\"temporary\":false,\"id\":\"0sabv\",\"label\":\"Custom_vector_shapes\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#3cb44b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"idThatDoesNotExitForEMSTile\"},\"temporary\":false,\"id\":\"plw9l\",\"label\":\"EMS_tiles\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"VECTOR_TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"idThatDoesNotExitForEMSFileSource\"},\"temporary\":false,\"id\":\"2gro0\",\"label\":\"EMS_vector_shapes\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"id\":\"f67fe707-95dd-46d6-89b8-82617b251b61\",\"geoField\":\"geo.coordinates\",\"requestType\":\"grid\",\"resolution\":\"COARSE\",\"indexPatternRefName\":\"layer_4_source_index_pattern\",\"applyGlobalQuery\":true},\"temporary\":false,\"id\":\"pl5qd\",\"label\":\"\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"color\":\"Blues\",\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3}}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32,\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3}}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"id\":\"a07072bb-3a92-4320-bd37-250ef6d04db7\",\"type\":\"ES_SEARCH\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[],\"indexPatternRefName\":\"layer_5_source_index_pattern\",\"applyGlobalQuery\":true,\"scalingType\":\"LIMIT\"},\"temporary\":false,\"id\":\"9bw8h\",\"label\":\"\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[],\"indexPatternRefName\":\"layer_6_source_index_pattern\",\"applyGlobalQuery\":true,\"scalingType\":\"LIMIT\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1__855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"origin\":\"join\"},\"color\":\"Blues\",\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3}}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"indexPatternRefName\":\"layer_6_join_0_index_pattern\",\"applyGlobalQuery\":true,\"type\":\"ES_TERM_SOURCE\"}}]}]", + "layerListJSON": "[{\"sourceDescriptor\":{\"type\":\"KIBANA_TILEMAP\"},\"id\":\"ap0ys\",\"label\":\"Custom_TMS\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"idThatDoesNotExitForEMSTile\"},\"temporary\":false,\"id\":\"plw9l\",\"label\":\"EMS_tiles\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"VECTOR_TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"idThatDoesNotExitForEMSFileSource\"},\"temporary\":false,\"id\":\"2gro0\",\"label\":\"EMS_vector_shapes\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"id\":\"f67fe707-95dd-46d6-89b8-82617b251b61\",\"geoField\":\"geo.coordinates\",\"requestType\":\"grid\",\"resolution\":\"COARSE\",\"indexPatternRefName\":\"layer_4_source_index_pattern\",\"applyGlobalQuery\":true},\"temporary\":false,\"id\":\"pl5qd\",\"label\":\"\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"color\":\"Blues\",\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3}}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32,\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3}}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"id\":\"a07072bb-3a92-4320-bd37-250ef6d04db7\",\"type\":\"ES_SEARCH\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[],\"indexPatternRefName\":\"layer_5_source_index_pattern\",\"applyGlobalQuery\":true,\"scalingType\":\"LIMIT\"},\"temporary\":false,\"id\":\"9bw8h\",\"label\":\"\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[],\"indexPatternRefName\":\"layer_6_source_index_pattern\",\"applyGlobalQuery\":true,\"scalingType\":\"LIMIT\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1__855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"origin\":\"join\"},\"color\":\"Blues\",\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3}}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"indexPatternRefName\":\"layer_6_join_0_index_pattern\",\"applyGlobalQuery\":true,\"type\":\"ES_TERM_SOURCE\"}}]}]", "mapStateJSON": "{\"zoom\":0.71,\"center\":{\"lon\":0.10268,\"lat\":0},\"timeFilters\":{\"from\":\"now-7d\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"settings\":{\"autoFitToDataBounds\":false}}", "title": "layer with errors", "uiStateJSON": "{}" diff --git a/x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json b/x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json index 568b2e17a9332..c1274b4c78c90 100644 --- a/x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json +++ b/x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json @@ -11,8 +11,8 @@ }, "references": [], "type": "index-pattern", - "updated_at": "2019-12-11T23:24:13.381Z", - "version": "WzE3LDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzU1LDFd" } { @@ -39,8 +39,8 @@ } ], "type": "visualization", - "updated_at": "2020-04-08T23:24:05.971Z", - "version": "WzIwLDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzU2LDFd" } { @@ -67,8 +67,8 @@ } ], "type": "visualization", - "updated_at": "2020-04-10T00:34:44.700Z", - "version": "WzIzLDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzU3LDFd" } { @@ -110,8 +110,8 @@ } ], "type": "search", - "updated_at": "2019-12-11T23:24:28.540Z", - "version": "WzE4LDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzU4LDFd" } { @@ -139,8 +139,8 @@ } ], "type": "visualization", - "updated_at": "2021-01-07T00:23:04.624Z", - "version": "WzI3LDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzU5LDFd" } { @@ -167,8 +167,8 @@ } ], "type": "visualization", - "updated_at": "2020-04-08T23:24:42.460Z", - "version": "WzIxLDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzYwLDFd" } { @@ -189,8 +189,8 @@ }, "references": [], "type": "visualization", - "updated_at": "2020-04-10T00:36:17.053Z", - "version": "WzI0LDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzYxLDFd" } { @@ -217,8 +217,8 @@ } ], "type": "visualization", - "updated_at": "2020-04-10T00:33:44.909Z", - "version": "WzIyLDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzYyLDFd" } { @@ -283,8 +283,44 @@ } ], "type": "dashboard", - "updated_at": "2021-01-07T00:22:16.102Z", - "version": "WzI2LDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzYzLDFd" +} + +{ + "attributes": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}" + }, + "optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}", + "panelsJSON": "[{\"version\":\"8.0.0\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":0,\"w\":41,\"h\":20,\"i\":\"e80a3ff4-cb4a-479e-971d-438eeedd8b29\"},\"panelIndex\":\"e80a3ff4-cb4a-479e-971d-438eeedd8b29\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_e80a3ff4-cb4a-479e-971d-438eeedd8b29\"}]", + "refreshInterval": { + "pause": true, + "value": 0 + }, + "timeFrom": "2019-06-19T07:00:00.000Z", + "timeRestore": true, + "timeTo": "2019-06-22T07:00:00.000Z", + "title": "Ecom Dashboard - 3 Day Period", + "version": 1 + }, + "coreMigrationVersion": "8.0.0", + "id": "6c263e00-1c6d-11ea-a100-8589bb9d7c6b-COPY", + "migrationVersion": { + "dashboard": "7.14.0" + }, + "references": [ + { + "id": "6091ead0-1c6d-11ea-a100-8589bb9d7c6b", + "name": "e80a3ff4-cb4a-479e-971d-438eeedd8b29:panel_e80a3ff4-cb4a-479e-971d-438eeedd8b29", + "type": "search" + } + ], + "type": "dashboard", + "updated_at": "2021-09-20T23:42:15.675Z", + "version": "WzE2MiwxXQ==" } { @@ -344,8 +380,8 @@ } ], "type": "dashboard", - "updated_at": "2020-04-10T00:37:48.462Z", - "version": "WzE5LDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzY1LDFd" } { @@ -387,8 +423,8 @@ } ], "type": "search", - "updated_at": "2021-05-03T18:39:30.751Z", - "version": "WzI4LDJd" + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzY2LDFd" } { @@ -673,6 +709,6 @@ } ], "type": "dashboard", - "updated_at": "2021-05-03T18:39:45.983Z", - "version": "WzI5LDJd" -} \ No newline at end of file + "updated_at": "2021-09-20T23:37:22.367Z", + "version": "WzY3LDFd" +} diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 2e1151602f311..e26ea8f598c46 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -645,8 +645,21 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont /** * Adds a new layer to the chart, fails if the chart does not support new layers */ - async createLayer() { + async createLayer(layerType: string = 'data') { await testSubjects.click('lnsLayerAddButton'); + const layerCount = (await find.allByCssSelector(`[data-test-subj^="lns-layerPanel-"]`)) + .length; + + await retry.waitFor('check for layer type support', async () => { + const fasterChecks = await Promise.all([ + (await find.allByCssSelector(`[data-test-subj^="lns-layerPanel-"]`)).length > layerCount, + testSubjects.exists(`lnsLayerAddButton-${layerType}`), + ]); + return fasterChecks.filter(Boolean).length > 0; + }); + if (await testSubjects.exists(`lnsLayerAddButton-${layerType}`)) { + await testSubjects.click(`lnsLayerAddButton-${layerType}`); + } }, /** @@ -1075,6 +1088,10 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont await testSubjects.click('lens-dimensionTabs-formula'); }, + async switchToStaticValue() { + await testSubjects.click('lens-dimensionTabs-static_value'); + }, + async toggleFullscreen() { await testSubjects.click('lnsFormula-fullscreen'); }, diff --git a/x-pack/test/functional/page_objects/reporting_page.ts b/x-pack/test/functional/page_objects/reporting_page.ts index ca48cec092ecb..552d2c9c831bd 100644 --- a/x-pack/test/functional/page_objects/reporting_page.ts +++ b/x-pack/test/functional/page_objects/reporting_page.ts @@ -145,14 +145,18 @@ export class ReportingPageObject extends FtrService { return isToastPresent; } - async setTimepickerInDataRange() { + // set the time picker to a range matching 720 documents when using the + // reporting/ecommerce archive + async setTimepickerInEcommerceDataRange() { this.log.debug('Reporting:setTimepickerInDataRange'); - const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; - const toTime = 'Aug 23, 2019 @ 16:18:51.821'; + const fromTime = 'Jun 20, 2019 @ 00:00:00.000'; + const toTime = 'Jun 25, 2019 @ 00:00:00.000'; await this.timePicker.setAbsoluteRange(fromTime, toTime); } - async setTimepickerInNoDataRange() { + // set the time picker to a range matching 0 documents when using the + // reporting/ecommerce archive + async setTimepickerInEcommerceNoDataRange() { this.log.debug('Reporting:setTimepickerInNoDataRange'); const fromTime = 'Sep 19, 1999 @ 06:31:44.000'; const toTime = 'Sep 23, 1999 @ 18:31:44.000'; diff --git a/x-pack/test/functional/page_objects/search_sessions_management_page.ts b/x-pack/test/functional/page_objects/search_sessions_management_page.ts index 86391b568fdf2..15c87ea450425 100644 --- a/x-pack/test/functional/page_objects/search_sessions_management_page.ts +++ b/x-pack/test/functional/page_objects/search_sessions_management_page.ts @@ -38,6 +38,7 @@ export function SearchSessionsPageProvider({ getService, getPageObjects }: FtrPr mainUrl: $.findTestSubject('sessionManagementNameCol').text(), created: $.findTestSubject('sessionManagementCreatedCol').text(), expires: $.findTestSubject('sessionManagementExpiresCol').text(), + searchesCount: Number($.findTestSubject('sessionManagementNumSearchesCol').text()), app: $.findTestSubject('sessionManagementAppIcon').attr('data-test-app-id'), view: async () => { log.debug('management ui: view the session'); diff --git a/x-pack/test/functional/services/ml/job_table.ts b/x-pack/test/functional/services/ml/job_table.ts index 4a38aa4efe4dd..e1a675d760f2e 100644 --- a/x-pack/test/functional/services/ml/job_table.ts +++ b/x-pack/test/functional/services/ml/job_table.ts @@ -634,9 +634,11 @@ export function MachineLearningJobTableProvider( } // Save custom URL - await testSubjects.click('mlJobAddCustomUrl'); - const expectedIndex = existingCustomUrls.length; - await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label); + await retry.tryForTime(5000, async () => { + await testSubjects.click('mlJobAddCustomUrl'); + const expectedIndex = existingCustomUrls.length; + await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label); + }); // Save the job await this.saveEditJobFlyoutChanges(); @@ -654,9 +656,11 @@ export function MachineLearningJobTableProvider( await customUrls.setCustomUrlOtherTypeUrl(customUrl.url); // Save custom URL - await testSubjects.click('mlJobAddCustomUrl'); - const expectedIndex = existingCustomUrls.length; - await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label); + await retry.tryForTime(5000, async () => { + await testSubjects.click('mlJobAddCustomUrl'); + const expectedIndex = existingCustomUrls.length; + await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label); + }); // Save the job await this.saveEditJobFlyoutChanges(); diff --git a/x-pack/test/functional/services/observability/alerts.ts b/x-pack/test/functional/services/observability/alerts.ts index 8926d734d7313..435da8ad94037 100644 --- a/x-pack/test/functional/services/observability/alerts.ts +++ b/x-pack/test/functional/services/observability/alerts.ts @@ -17,6 +17,7 @@ const DATE_WITH_DATA = { }; const ALERTS_FLYOUT_SELECTOR = 'alertsFlyout'; +const COPY_TO_CLIPBOARD_BUTTON_SELECTOR = 'copy-to-clipboard'; const ALERTS_TABLE_CONTAINER_SELECTOR = 'events-viewer-panel'; const ACTION_COLUMN_INDEX = 1; @@ -77,7 +78,7 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP }; const clearQueryBar = async () => { - return await (await getQueryBar()).clearValueWithKeyboard({ charByChar: true }); + return await (await getQueryBar()).clearValueWithKeyboard(); }; const typeInQueryBar = async (query: string) => { @@ -132,6 +133,20 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP return await testSubjects.findAllDescendant('alertsFlyoutDescriptionListDescription', flyout); }; + // Cell actions + + const copyToClipboardButtonExists = async () => { + return await testSubjects.exists(COPY_TO_CLIPBOARD_BUTTON_SELECTOR); + }; + + const getCopyToClipboardButton = async () => { + return await testSubjects.find(COPY_TO_CLIPBOARD_BUTTON_SELECTOR); + }; + + const getFilterForValueButton = async () => { + return await testSubjects.find('filter-for-value'); + }; + const openActionsMenuForRow = async (rowIndex: number) => { const rows = await getTableCellsInRows(); const actionsOverflowButton = await testSubjects.findDescendant( @@ -163,6 +178,7 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP }; return { + getQueryBar, clearQueryBar, closeAlertsFlyout, getAlertsFlyout, @@ -171,6 +187,9 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP getAlertsFlyoutOrFail, getAlertsFlyoutTitle, getAlertsFlyoutViewInAppButtonOrFail, + getCopyToClipboardButton, + getFilterForValueButton, + copyToClipboardButtonExists, getNoDataStateOrFail, getTableCells, getTableCellsInRows, diff --git a/x-pack/test/functional/services/transform/security_common.ts b/x-pack/test/functional/services/transform/security_common.ts index bae31dffa1412..f27de80d26b2e 100644 --- a/x-pack/test/functional/services/transform/security_common.ts +++ b/x-pack/test/functional/services/transform/security_common.ts @@ -14,6 +14,7 @@ export type TransformSecurityCommon = ProvidedType res.ok({ body: 'content from kibana' }) ); } - async start(core: CoreStart) { - const config = await this.initializerContext.config - .create() - .pipe(take(1)) - .toPromise(); + start(core: CoreStart) { + const config = this.initializerContext.config.get(); const server = new Hapi.Server({ port: config.port, @@ -78,8 +75,9 @@ export class CorsTestPlugin implements Plugin { return h.response(renderBody(kibanaUrl)); }, }); - await server.start(); + server.start(); } + public stop() { if (this.server) { this.server.stop(); diff --git a/x-pack/test/functional_embedded/tests/iframe_embedded.ts b/x-pack/test/functional_embedded/tests/iframe_embedded.ts index 21bc19424c893..0e2a461dd15f9 100644 --- a/x-pack/test/functional_embedded/tests/iframe_embedded.ts +++ b/x-pack/test/functional_embedded/tests/iframe_embedded.ts @@ -17,7 +17,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const retry = getService('retry'); - describe('in iframe', () => { + // FLAKY https://github.com/elastic/kibana/issues/70928 + describe.skip('in iframe', () => { it('should open Kibana for logged-in user', async () => { const isChromeHiddenBefore = await PageObjects.common.isChromeHidden(); expect(isChromeHiddenBefore).to.be(true); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts index 2ce771f7b993f..88ba4c37559c5 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts @@ -103,7 +103,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('test.always-firing-SelectOption'); } - describe('create alert', function () { + // FLAKY https://github.com/elastic/kibana/issues/112749 + describe.skip('create alert', function () { before(async () => { await pageObjects.common.navigateToApp('triggersActions'); await testSubjects.click('rulesTab'); diff --git a/x-pack/test/observability_functional/apps/observability/alerts/index.ts b/x-pack/test/observability_functional/apps/observability/alerts/index.ts index 6b130ae0f6264..856d7e60996ec 100644 --- a/x-pack/test/observability_functional/apps/observability/alerts/index.ts +++ b/x-pack/test/observability_functional/apps/observability/alerts/index.ts @@ -14,11 +14,14 @@ async function asyncForEach(array: T[], callback: (item: T, index: number) => } } +const ACTIVE_ALERTS_CELL_COUNT = 48; +const RECOVERED_ALERTS_CELL_COUNT = 24; +const TOTAL_ALERTS_CELL_COUNT = 72; + export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); - // Failing: See https://github.com/elastic/kibana/issues/111907 - describe.skip('Observability alerts', function () { + describe('Observability alerts', function () { this.tags('includeFirefox'); const pageObjects = getPageObjects(['common']); @@ -41,9 +44,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('Renders the correct number of cells', async () => { - // NOTE: This isn't ideal, but EuiDataGrid doesn't really have the concept of "rows" - const cells = await observability.alerts.getTableCells(); - expect(cells.length).to.be(72); + await retry.try(async () => { + const cells = await observability.alerts.getTableCells(); + expect(cells.length).to.be(TOTAL_ALERTS_CELL_COUNT); + }); }); describe('Filtering', () => { @@ -67,7 +71,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await observability.alerts.submitQuery('kibana.alert.status: recovered'); await retry.try(async () => { const cells = await observability.alerts.getTableCells(); - expect(cells.length).to.be(24); + expect(cells.length).to.be(RECOVERED_ALERTS_CELL_COUNT); }); }); @@ -87,9 +91,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await (await testSubjects.find('superDatePickerToggleQuickMenuButton')).click(); // We shouldn't expect any data for the last 15 minutes await (await testSubjects.find('superDatePickerCommonlyUsed_Last_15 minutes')).click(); + await observability.alerts.getNoDataStateOrFail(); + await pageObjects.common.waitUntilUrlIncludes('rangeFrom=now-15m&rangeTo=now'); }); - await observability.alerts.getNoDataStateOrFail(); - await pageObjects.common.waitUntilUrlIncludes('rangeFrom=now-15m&rangeTo=now'); }); }); @@ -114,10 +118,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('Displays the correct title', async () => { - const titleText = await ( - await observability.alerts.getAlertsFlyoutTitle() - ).getVisibleText(); - expect(titleText).to.contain('Log threshold'); + await retry.try(async () => { + const titleText = await ( + await observability.alerts.getAlertsFlyoutTitle() + ).getVisibleText(); + expect(titleText).to.contain('Log threshold'); + }); }); it('Displays the correct content', async () => { @@ -156,6 +162,43 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); }); + + describe('Cell actions', () => { + beforeEach(async () => { + await retry.try(async () => { + const cells = await observability.alerts.getTableCells(); + const alertStatusCell = cells[2]; + await alertStatusCell.moveMouseTo(); + await retry.waitFor( + 'cell actions visible', + async () => await observability.alerts.copyToClipboardButtonExists() + ); + }); + }); + + afterEach(async () => { + await observability.alerts.clearQueryBar(); + }); + + it('Copy button works', async () => { + // NOTE: We don't have access to the clipboard in a headless environment, + // so we'll just check the button is clickable in the functional tests. + await (await observability.alerts.getCopyToClipboardButton()).click(); + }); + + it('Filter for value works', async () => { + await (await observability.alerts.getFilterForValueButton()).click(); + const queryBarValue = await ( + await observability.alerts.getQueryBar() + ).getAttribute('value'); + expect(queryBarValue).to.be('kibana.alert.status: "active"'); + // Wait for request + await retry.try(async () => { + const cells = await observability.alerts.getTableCells(); + expect(cells.length).to.be(ACTIVE_ALERTS_CELL_COUNT); + }); + }); + }); }); }); }; diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/download_csv_dashboard.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/download_csv_dashboard.snap index 6215ae7e11a4c..806fa16f56921 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/download_csv_dashboard.snap +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/download_csv_dashboard.snap @@ -2,42 +2,50 @@ exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with all fields when using defaults 1`] = ` "_id,_index,_score,_type,category,category.keyword,currency,customer_first_name,customer_first_name.keyword,customer_full_name,customer_full_name.keyword,customer_gender,customer_id,customer_last_name,customer_last_name.keyword,customer_phone,day_of_week,day_of_week_i,email,geoip.city_name,geoip.continent_name,geoip.country_iso_code,geoip.location,geoip.region_name,manufacturer,manufacturer.keyword,order_date,order_id,products._id,products._id.keyword,products.base_price,products.base_unit_price,products.category,products.category.keyword,products.created_on,products.discount_amount,products.discount_percentage,products.manufacturer,products.manufacturer.keyword,products.min_price,products.price,products.product_id,products.product_name,products.product_name.keyword,products.quantity,products.sku,products.tax_amount,products.taxful_price,products.taxless_price,products.unit_discount_amount,sku,taxful_total_price,taxless_total_price,total_quantity,total_unique_products,type,user -3AMtOW0BH63Xcmy432DJ,ecommerce,-,-,Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories,Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories,EUR,Sultan Al,Sultan Al,Sultan Al Boone,Sultan Al Boone,MALE,19,Boone,Boone,(empty),Saturday,5,sultan al@boone-family.zzz,Abu Dhabi,Asia,AE,{ +9AMtOW0BH63Xcmy432DJ,ecommerce,-,-,Men's Clothing,Men's Clothing,EUR,Boris,Boris,Boris Bradley,Boris Bradley,MALE,36,Bradley,Bradley,(empty),Wednesday,2,boris@bradley-family.zzz,-,Europe,GB,{ \\"coordinates\\": [ - 54.4, - 24.5 + -0.1, + 51.5 ], \\"type\\": \\"Point\\" -},Abu Dhabi,Angeldale, Oceanavigations, Microlutions,Angeldale, Oceanavigations, Microlutions,Jul 12, 2019 @ 00:00:00.000,716724,sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290,sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290,80, 60, 21.984, 11.992,80, 60, 21.984, 11.992,Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories,Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories,Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000,0, 0, 0, 0,0, 0, 0, 0,Angeldale, Oceanavigations, Microlutions, Oceanavigations,Angeldale, Oceanavigations, Microlutions, Oceanavigations,42.375, 33, 10.344, 6.109,80, 60, 21.984, 11.992,23,975, 6,338, 14,116, 15,290,Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor,Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor,1, 1, 1, 1,ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085,0, 0, 0, 0,80, 60, 21.984, 11.992,80, 60, 21.984, 11.992,0, 0, 0, 0,ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085,174,174,4,4,order,sultan -9gMtOW0BH63Xcmy432DJ,ecommerce,-,-,Women's Shoes, Women's Clothing,Women's Shoes, Women's Clothing,EUR,Pia,Pia,Pia Richards,Pia Richards,FEMALE,45,Richards,Richards,(empty),Saturday,5,pia@richards-family.zzz,Cannes,Europe,FR,{ +},-,Microlutions, Elitelligence,Microlutions, Elitelligence,Jun 25, 2019 @ 00:00:00.000,568397,sold_product_568397_24419, sold_product_568397_20207,sold_product_568397_24419, sold_product_568397_20207,33, 28.984,33, 28.984,Men's Clothing, Men's Clothing,Men's Clothing, Men's Clothing,Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,0, 0,0, 0,Microlutions, Elitelligence,Microlutions, Elitelligence,17.484, 13.922,33, 28.984,24,419, 20,207,Cargo trousers - oliv, Trousers - black,Cargo trousers - oliv, Trousers - black,1, 1,ZO0112101121, ZO0530405304,0, 0,33, 28.984,33, 28.984,0, 0,ZO0112101121, ZO0530405304,61.969,61.969,2,2,order,boris +9QMtOW0BH63Xcmy432DJ,ecommerce,-,-,Men's Clothing,Men's Clothing,EUR,Oliver,Oliver,Oliver Hubbard,Oliver Hubbard,MALE,7,Hubbard,Hubbard,(empty),Wednesday,2,oliver@hubbard-family.zzz,-,Europe,GB,{ \\"coordinates\\": [ - 7, - 43.6 + -0.1, + 51.5 ], \\"type\\": \\"Point\\" -},Alpes-Maritimes,Tigress Enterprises, Pyramidustries,Tigress Enterprises, Pyramidustries,Jul 12, 2019 @ 00:00:00.000,591503,sold_product_591503_14761, sold_product_591503_11632,sold_product_591503_14761, sold_product_591503_11632,20.984, 20.984,20.984, 20.984,Women's Shoes, Women's Clothing,Women's Shoes, Women's Clothing,Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000,0, 0,0, 0,Tigress Enterprises, Pyramidustries,Tigress Enterprises, Pyramidustries,10.703, 9.867,20.984, 20.984,14,761, 11,632,Classic heels - blue, Summer dress - coral/pink,Classic heels - blue, Summer dress - coral/pink,1, 1,ZO0006400064, ZO0150601506,0, 0,20.984, 20.984,20.984, 20.984,0, 0,ZO0006400064, ZO0150601506,41.969,41.969,2,2,order,pia -BgMtOW0BH63Xcmy432LJ,ecommerce,-,-,Women's Clothing,Women's Clothing,EUR,Brigitte,Brigitte,Brigitte Meyer,Brigitte Meyer,FEMALE,12,Meyer,Meyer,(empty),Saturday,5,brigitte@meyer-family.zzz,New York,North America,US,{ +},-,Spritechnologies, Microlutions,Spritechnologies, Microlutions,Jun 25, 2019 @ 00:00:00.000,568044,sold_product_568044_12799, sold_product_568044_18008,sold_product_568044_12799, sold_product_568044_18008,14.992, 16.984,14.992, 16.984,Men's Clothing, Men's Clothing,Men's Clothing, Men's Clothing,Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,0, 0,0, 0,Spritechnologies, Microlutions,Spritechnologies, Microlutions,6.898, 8.828,14.992, 16.984,12,799, 18,008,Undershirt - dark grey multicolor, Long sleeved top - purple,Undershirt - dark grey multicolor, Long sleeved top - purple,1, 1,ZO0630406304, ZO0120201202,0, 0,14.992, 16.984,14.992, 16.984,0, 0,ZO0630406304, ZO0120201202,31.984,31.984,2,2,order,oliver +OAMtOW0BH63Xcmy432HJ,ecommerce,-,-,Women's Accessories,Women's Accessories,EUR,Betty,Betty,Betty Reese,Betty Reese,FEMALE,44,Reese,Reese,(empty),Wednesday,2,betty@reese-family.zzz,New York,North America,US,{ \\"coordinates\\": [ -74, - 40.8 + 40.7 ], \\"type\\": \\"Point\\" -},New York,Spherecords, Tigress Enterprises,Spherecords, Tigress Enterprises,Jul 12, 2019 @ 00:00:00.000,591709,sold_product_591709_20734, sold_product_591709_7539,sold_product_591709_20734, sold_product_591709_7539,7.988, 33,7.988, 33,Women's Clothing, Women's Clothing,Women's Clothing, Women's Clothing,Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000,0, 0,0, 0,Spherecords, Tigress Enterprises,Spherecords, Tigress Enterprises,3.6, 17.484,7.988, 33,20,734, 7,539,Basic T-shirt - dark blue, Summer dress - scarab,Basic T-shirt - dark blue, Summer dress - scarab,1, 1,ZO0638206382, ZO0038800388,0, 0,7.988, 33,7.988, 33,0, 0,ZO0638206382, ZO0038800388,40.969,40.969,2,2,order,brigitte -KQMtOW0BH63Xcmy432LJ,ecommerce,-,-,Men's Clothing,Men's Clothing,EUR,Abd,Abd,Abd Mccarthy,Abd Mccarthy,MALE,52,Mccarthy,Mccarthy,(empty),Saturday,5,abd@mccarthy-family.zzz,Cairo,Africa,EG,{ +},New York,Pyramidustries,Pyramidustries,Jun 25, 2019 @ 00:00:00.000,568229,sold_product_568229_24991, sold_product_568229_12039,sold_product_568229_24991, sold_product_568229_12039,11.992, 10.992,11.992, 10.992,Women's Accessories, Women's Accessories,Women's Accessories, Women's Accessories,Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,0, 0,0, 0,Pyramidustries, Pyramidustries,Pyramidustries, Pyramidustries,6.352, 5.82,11.992, 10.992,24,991, 12,039,Scarf - rose/white, Scarf - nude/black/turquoise,Scarf - rose/white, Scarf - nude/black/turquoise,1, 1,ZO0192201922, ZO0192801928,0, 0,11.992, 10.992,11.992, 10.992,0, 0,ZO0192201922, ZO0192801928,22.984,22.984,2,2,order,betty +OQMtOW0BH63Xcmy432HJ,ecommerce,-,-,Men's Clothing, Men's Accessories,Men's Clothing, Men's Accessories,EUR,Recip,Recip,Recip Salazar,Recip Salazar,MALE,10,Salazar,Salazar,(empty),Wednesday,2,recip@salazar-family.zzz,Istanbul,Asia,TR,{ \\"coordinates\\": [ - 31.3, - 30.1 + 29, + 41 ], \\"type\\": \\"Point\\" -},Cairo Governorate,Oceanavigations, Elitelligence,Oceanavigations, Elitelligence,Jul 12, 2019 @ 00:00:00.000,590937,sold_product_590937_14438, sold_product_590937_23607,sold_product_590937_14438, sold_product_590937_23607,28.984, 12.992,28.984, 12.992,Men's Clothing, Men's Clothing,Men's Clothing, Men's Clothing,Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000,0, 0,0, 0,Oceanavigations, Elitelligence,Oceanavigations, Elitelligence,13.344, 6.109,28.984, 12.992,14,438, 23,607,Jumper - dark grey multicolor, Print T-shirt - black,Jumper - dark grey multicolor, Print T-shirt - black,1, 1,ZO0297602976, ZO0565605656,0, 0,28.984, 12.992,28.984, 12.992,0, 0,ZO0297602976, ZO0565605656,41.969,41.969,2,2,order,abd +},Istanbul,Elitelligence,Elitelligence,Jun 25, 2019 @ 00:00:00.000,568292,sold_product_568292_23627, sold_product_568292_11149,sold_product_568292_23627, sold_product_568292_11149,24.984, 10.992,24.984, 10.992,Men's Clothing, Men's Accessories,Men's Clothing, Men's Accessories,Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,0, 0,0, 0,Elitelligence, Elitelligence,Elitelligence, Elitelligence,12.492, 5.059,24.984, 10.992,23,627, 11,149,Slim fit jeans - grey, Sunglasses - black,Slim fit jeans - grey, Sunglasses - black,1, 1,ZO0534205342, ZO0599605996,0, 0,24.984, 10.992,24.984, 10.992,0, 0,ZO0534205342, ZO0599605996,35.969,35.969,2,2,order,recip +jwMtOW0BH63Xcmy432HJ,ecommerce,-,-,Men's Clothing,Men's Clothing,EUR,Jackson,Jackson,Jackson Harper,Jackson Harper,MALE,13,Harper,Harper,(empty),Wednesday,2,jackson@harper-family.zzz,Los Angeles,North America,US,{ + \\"coordinates\\": [ + -118.2, + 34.1 + ], + \\"type\\": \\"Point\\" +},California,Low Tide Media, Oceanavigations,Low Tide Media, Oceanavigations,Jun 25, 2019 @ 00:00:00.000,568386,sold_product_568386_11959, sold_product_568386_2774,sold_product_568386_11959, sold_product_568386_2774,24.984, 85,24.984, 85,Men's Clothing, Men's Clothing,Men's Clothing, Men's Clothing,Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,0, 0,0, 0,Low Tide Media, Oceanavigations,Low Tide Media, Oceanavigations,12.742, 45.875,24.984, 85,11,959, 2,774,SLIM FIT - Formal shirt - lila, Classic coat - black,SLIM FIT - Formal shirt - lila, Classic coat - black,1, 1,ZO0422404224, ZO0291702917,0, 0,24.984, 85,24.984, 85,0, 0,ZO0422404224, ZO0291702917,110,110,2,2,order,jackson " `; exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with almost all fields when using fieldsFromSource 1`] = ` "_id,_index,_score,_type,category,currency,customer_first_name,customer_full_name,customer_gender,customer_id,customer_last_name,customer_phone,day_of_week,day_of_week_i,email,geoip,manufacturer,order_date,order_id,products,products.created_on,sku,taxful_total_price,taxless_total_price,total_quantity,total_unique_products,type,user -3AMtOW0BH63Xcmy432DJ,ecommerce,-,-,Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories,EUR,Sultan Al,Sultan Al Boone,MALE,19,Boone,-,Saturday,5,sultan al@boone-family.zzz,{\\"city_name\\":\\"Abu Dhabi\\",\\"continent_name\\":\\"Asia\\",\\"country_iso_code\\":\\"AE\\",\\"location\\":{\\"lat\\":24.5,\\"lon\\":54.4},\\"region_name\\":\\"Abu Dhabi\\"},Angeldale, Oceanavigations, Microlutions,Jul 12, 2019 @ 00:00:00.000,716724,{\\"_id\\":\\"sold_product_716724_23975\\",\\"base_price\\":79.99,\\"base_unit_price\\":79.99,\\"category\\":\\"Men's Shoes\\",\\"created_on\\":\\"2016-12-31T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Angeldale\\",\\"min_price\\":42.39,\\"price\\":79.99,\\"product_id\\":23975,\\"product_name\\":\\"Winter boots - cognac\\",\\"quantity\\":1,\\"sku\\":\\"ZO0687606876\\",\\"tax_amount\\":0,\\"taxful_price\\":79.99,\\"taxless_price\\":79.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_716724_6338\\",\\"base_price\\":59.99,\\"base_unit_price\\":59.99,\\"category\\":\\"Men's Clothing\\",\\"created_on\\":\\"2016-12-31T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Oceanavigations\\",\\"min_price\\":32.99,\\"price\\":59.99,\\"product_id\\":6338,\\"product_name\\":\\"Trenchcoat - black\\",\\"quantity\\":1,\\"sku\\":\\"ZO0290502905\\",\\"tax_amount\\":0,\\"taxful_price\\":59.99,\\"taxless_price\\":59.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_716724_14116\\",\\"base_price\\":21.99,\\"base_unit_price\\":21.99,\\"category\\":\\"Women's Accessories\\",\\"created_on\\":\\"2016-12-31T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Microlutions\\",\\"min_price\\":10.34,\\"price\\":21.99,\\"product_id\\":14116,\\"product_name\\":\\"Watch - black\\",\\"quantity\\":1,\\"sku\\":\\"ZO0126701267\\",\\"tax_amount\\":0,\\"taxful_price\\":21.99,\\"taxless_price\\":21.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_716724_15290\\",\\"base_price\\":11.99,\\"base_unit_price\\":11.99,\\"category\\":\\"Men's Accessories\\",\\"created_on\\":\\"2016-12-31T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Oceanavigations\\",\\"min_price\\":6.11,\\"price\\":11.99,\\"product_id\\":15290,\\"product_name\\":\\"Hat - light grey multicolor\\",\\"quantity\\":1,\\"sku\\":\\"ZO0308503085\\",\\"tax_amount\\":0,\\"taxful_price\\":11.99,\\"taxless_price\\":11.99,\\"unit_discount_amount\\":0},Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000,ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085,173.96,173.96,4,4,order,sultan -9gMtOW0BH63Xcmy432DJ,ecommerce,-,-,Women's Shoes, Women's Clothing,EUR,Pia,Pia Richards,FEMALE,45,Richards,-,Saturday,5,pia@richards-family.zzz,{\\"city_name\\":\\"Cannes\\",\\"continent_name\\":\\"Europe\\",\\"country_iso_code\\":\\"FR\\",\\"location\\":{\\"lat\\":43.6,\\"lon\\":7},\\"region_name\\":\\"Alpes-Maritimes\\"},Tigress Enterprises, Pyramidustries,Jul 12, 2019 @ 00:00:00.000,591503,{\\"_id\\":\\"sold_product_591503_14761\\",\\"base_price\\":20.99,\\"base_unit_price\\":20.99,\\"category\\":\\"Women's Shoes\\",\\"created_on\\":\\"2016-12-31T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Tigress Enterprises\\",\\"min_price\\":10.7,\\"price\\":20.99,\\"product_id\\":14761,\\"product_name\\":\\"Classic heels - blue\\",\\"quantity\\":1,\\"sku\\":\\"ZO0006400064\\",\\"tax_amount\\":0,\\"taxful_price\\":20.99,\\"taxless_price\\":20.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_591503_11632\\",\\"base_price\\":20.99,\\"base_unit_price\\":20.99,\\"category\\":\\"Women's Clothing\\",\\"created_on\\":\\"2016-12-31T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Pyramidustries\\",\\"min_price\\":9.87,\\"price\\":20.99,\\"product_id\\":11632,\\"product_name\\":\\"Summer dress - coral/pink\\",\\"quantity\\":1,\\"sku\\":\\"ZO0150601506\\",\\"tax_amount\\":0,\\"taxful_price\\":20.99,\\"taxless_price\\":20.99,\\"unit_discount_amount\\":0},Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000,ZO0006400064, ZO0150601506,41.98,41.98,2,2,order,pia -BgMtOW0BH63Xcmy432LJ,ecommerce,-,-,Women's Clothing,EUR,Brigitte,Brigitte Meyer,FEMALE,12,Meyer,-,Saturday,5,brigitte@meyer-family.zzz,{\\"city_name\\":\\"New York\\",\\"continent_name\\":\\"North America\\",\\"country_iso_code\\":\\"US\\",\\"location\\":{\\"lat\\":40.8,\\"lon\\":-74},\\"region_name\\":\\"New York\\"},Spherecords, Tigress Enterprises,Jul 12, 2019 @ 00:00:00.000,591709,{\\"_id\\":\\"sold_product_591709_20734\\",\\"base_price\\":7.99,\\"base_unit_price\\":7.99,\\"category\\":\\"Women's Clothing\\",\\"created_on\\":\\"2016-12-31T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Spherecords\\",\\"min_price\\":3.6,\\"price\\":7.99,\\"product_id\\":20734,\\"product_name\\":\\"Basic T-shirt - dark blue\\",\\"quantity\\":1,\\"sku\\":\\"ZO0638206382\\",\\"tax_amount\\":0,\\"taxful_price\\":7.99,\\"taxless_price\\":7.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_591709_7539\\",\\"base_price\\":32.99,\\"base_unit_price\\":32.99,\\"category\\":\\"Women's Clothing\\",\\"created_on\\":\\"2016-12-31T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Tigress Enterprises\\",\\"min_price\\":17.48,\\"price\\":32.99,\\"product_id\\":7539,\\"product_name\\":\\"Summer dress - scarab\\",\\"quantity\\":1,\\"sku\\":\\"ZO0038800388\\",\\"tax_amount\\":0,\\"taxful_price\\":32.99,\\"taxless_price\\":32.99,\\"unit_discount_amount\\":0},Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000,ZO0638206382, ZO0038800388,40.98,40.98,2,2,order,brigitte +9AMtOW0BH63Xcmy432DJ,ecommerce,-,-,Men's Clothing,EUR,Boris,Boris Bradley,MALE,36,Bradley,-,Wednesday,2,boris@bradley-family.zzz,{\\"continent_name\\":\\"Europe\\",\\"country_iso_code\\":\\"GB\\",\\"location\\":{\\"lat\\":51.5,\\"lon\\":-0.1}},Microlutions, Elitelligence,Jun 25, 2019 @ 00:00:00.000,568397,{\\"_id\\":\\"sold_product_568397_24419\\",\\"base_price\\":32.99,\\"base_unit_price\\":32.99,\\"category\\":\\"Men's Clothing\\",\\"created_on\\":\\"2016-12-14T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Microlutions\\",\\"min_price\\":17.48,\\"price\\":32.99,\\"product_id\\":24419,\\"product_name\\":\\"Cargo trousers - oliv\\",\\"quantity\\":1,\\"sku\\":\\"ZO0112101121\\",\\"tax_amount\\":0,\\"taxful_price\\":32.99,\\"taxless_price\\":32.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_568397_20207\\",\\"base_price\\":28.99,\\"base_unit_price\\":28.99,\\"category\\":\\"Men's Clothing\\",\\"created_on\\":\\"2016-12-14T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Elitelligence\\",\\"min_price\\":13.92,\\"price\\":28.99,\\"product_id\\":20207,\\"product_name\\":\\"Trousers - black\\",\\"quantity\\":1,\\"sku\\":\\"ZO0530405304\\",\\"tax_amount\\":0,\\"taxful_price\\":28.99,\\"taxless_price\\":28.99,\\"unit_discount_amount\\":0},Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,ZO0112101121, ZO0530405304,61.98,61.98,2,2,order,boris +9QMtOW0BH63Xcmy432DJ,ecommerce,-,-,Men's Clothing,EUR,Oliver,Oliver Hubbard,MALE,7,Hubbard,-,Wednesday,2,oliver@hubbard-family.zzz,{\\"continent_name\\":\\"Europe\\",\\"country_iso_code\\":\\"GB\\",\\"location\\":{\\"lat\\":51.5,\\"lon\\":-0.1}},Spritechnologies, Microlutions,Jun 25, 2019 @ 00:00:00.000,568044,{\\"_id\\":\\"sold_product_568044_12799\\",\\"base_price\\":14.99,\\"base_unit_price\\":14.99,\\"category\\":\\"Men's Clothing\\",\\"created_on\\":\\"2016-12-14T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Spritechnologies\\",\\"min_price\\":6.9,\\"price\\":14.99,\\"product_id\\":12799,\\"product_name\\":\\"Undershirt - dark grey multicolor\\",\\"quantity\\":1,\\"sku\\":\\"ZO0630406304\\",\\"tax_amount\\":0,\\"taxful_price\\":14.99,\\"taxless_price\\":14.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_568044_18008\\",\\"base_price\\":16.99,\\"base_unit_price\\":16.99,\\"category\\":\\"Men's Clothing\\",\\"created_on\\":\\"2016-12-14T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Microlutions\\",\\"min_price\\":8.83,\\"price\\":16.99,\\"product_id\\":18008,\\"product_name\\":\\"Long sleeved top - purple\\",\\"quantity\\":1,\\"sku\\":\\"ZO0120201202\\",\\"tax_amount\\":0,\\"taxful_price\\":16.99,\\"taxless_price\\":16.99,\\"unit_discount_amount\\":0},Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,ZO0630406304, ZO0120201202,31.98,31.98,2,2,order,oliver +OAMtOW0BH63Xcmy432HJ,ecommerce,-,-,Women's Accessories,EUR,Betty,Betty Reese,FEMALE,44,Reese,-,Wednesday,2,betty@reese-family.zzz,{\\"city_name\\":\\"New York\\",\\"continent_name\\":\\"North America\\",\\"country_iso_code\\":\\"US\\",\\"location\\":{\\"lat\\":40.7,\\"lon\\":-74},\\"region_name\\":\\"New York\\"},Pyramidustries,Jun 25, 2019 @ 00:00:00.000,568229,{\\"_id\\":\\"sold_product_568229_24991\\",\\"base_price\\":11.99,\\"base_unit_price\\":11.99,\\"category\\":\\"Women's Accessories\\",\\"created_on\\":\\"2016-12-14T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Pyramidustries\\",\\"min_price\\":6.35,\\"price\\":11.99,\\"product_id\\":24991,\\"product_name\\":\\"Scarf - rose/white\\",\\"quantity\\":1,\\"sku\\":\\"ZO0192201922\\",\\"tax_amount\\":0,\\"taxful_price\\":11.99,\\"taxless_price\\":11.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_568229_12039\\",\\"base_price\\":10.99,\\"base_unit_price\\":10.99,\\"category\\":\\"Women's Accessories\\",\\"created_on\\":\\"2016-12-14T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Pyramidustries\\",\\"min_price\\":5.82,\\"price\\":10.99,\\"product_id\\":12039,\\"product_name\\":\\"Scarf - nude/black/turquoise\\",\\"quantity\\":1,\\"sku\\":\\"ZO0192801928\\",\\"tax_amount\\":0,\\"taxful_price\\":10.99,\\"taxless_price\\":10.99,\\"unit_discount_amount\\":0},Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,ZO0192201922, ZO0192801928,22.98,22.98,2,2,order,betty +OQMtOW0BH63Xcmy432HJ,ecommerce,-,-,Men's Clothing, Men's Accessories,EUR,Recip,Recip Salazar,MALE,10,Salazar,-,Wednesday,2,recip@salazar-family.zzz,{\\"city_name\\":\\"Istanbul\\",\\"continent_name\\":\\"Asia\\",\\"country_iso_code\\":\\"TR\\",\\"location\\":{\\"lat\\":41,\\"lon\\":29},\\"region_name\\":\\"Istanbul\\"},Elitelligence,Jun 25, 2019 @ 00:00:00.000,568292,{\\"_id\\":\\"sold_product_568292_23627\\",\\"base_price\\":24.99,\\"base_unit_price\\":24.99,\\"category\\":\\"Men's Clothing\\",\\"created_on\\":\\"2016-12-14T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Elitelligence\\",\\"min_price\\":12.49,\\"price\\":24.99,\\"product_id\\":23627,\\"product_name\\":\\"Slim fit jeans - grey\\",\\"quantity\\":1,\\"sku\\":\\"ZO0534205342\\",\\"tax_amount\\":0,\\"taxful_price\\":24.99,\\"taxless_price\\":24.99,\\"unit_discount_amount\\":0}, {\\"_id\\":\\"sold_product_568292_11149\\",\\"base_price\\":10.99,\\"base_unit_price\\":10.99,\\"category\\":\\"Men's Accessories\\",\\"created_on\\":\\"2016-12-14T00:00:00+00:00\\",\\"discount_amount\\":0,\\"discount_percentage\\":0,\\"manufacturer\\":\\"Elitelligence\\",\\"min_price\\":5.06,\\"price\\":10.99,\\"product_id\\":11149,\\"product_name\\":\\"Sunglasses - black\\",\\"quantity\\":1,\\"sku\\":\\"ZO0599605996\\",\\"tax_amount\\":0,\\"taxful_price\\":10.99,\\"taxless_price\\":10.99,\\"unit_discount_amount\\":0},Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000,ZO0534205342, ZO0599605996,35.98,35.98,2,2,order,recip " `; @@ -208,41 +216,34 @@ exports[`Reporting APIs CSV Generation from SearchSource non-timebased With filt `; exports[`Reporting APIs CSV Generation from SearchSource validation Searches large amount of data, stops at Max Size Reached 1`] = ` -"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,19,716724,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,591503,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0006400064, ZO0150601506\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591709,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638206382, ZO0038800388\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,590937,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0297602976, ZO0565605656\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,590976,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0561405614, ZO0281602816\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,591636,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0385003850, ZO0408604086\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,591539,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0505605056, ZO0513605136\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,591598,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0276702767, ZO0291702917\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,590927,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0050800508\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,590970,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0455604556, ZO0680806808\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,591299,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0229002290, ZO0674406744\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,591133,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0529905299, ZO0617006170\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,591175,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0299402994, ZO0433504335\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,591297,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0257502575, ZO0451704517\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,591149,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0584905849, ZO0578405784\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,591754,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0335803358, ZO0325903259\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,591803,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0645906459, ZO0324303243\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,592082,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0034400344, ZO0492904929\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,591283,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0239302393, ZO0198501985\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,591148,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0290302903, ZO0513705137\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,591417,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0464504645, ZO0621006210\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,591562,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0544305443, ZO0108001080\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,590996,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0638106381, ZO0096900969\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,591317,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0366203662, ZO0139501395\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,591362,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0541805418, ZO0594105941\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,591411,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0693506935, ZO0532405324\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,38,722629,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0424204242, ZO0403504035, ZO0506705067, ZO0395603956\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,591041,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0418704187, ZO0557105571\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,591074,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0268602686, ZO0484704847\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,591349,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0474804748, ZO0560705607\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,591374,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0206002060, ZO0268302683\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,591230,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0226902269, ZO0660106601\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,591717,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0248002480, ZO0646706467\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,591768,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0005800058, ZO0133901339\\" -\\"Jul 12, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,591810,5,\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"ZO0587405874, ZO0590305903\\" +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,\\"(empty)\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"{ + \\"\\"coordinates\\"\\": [ + 54.4, + 24.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.375, 33, 10.344, 6.109\\",\\"80, 60, 21.984, 11.992\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",174,174,4,4,order,sultan +9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Richards\\",\\"Pia Richards\\",FEMALE,45,Richards,Richards,\\"(empty)\\",Saturday,5,\\"pia@richards-family.zzz\\",Cannes,Europe,FR,\\"{ + \\"\\"coordinates\\"\\": [ + 7, + 43.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.703, 9.867\\",\\"20.984, 20.984\\",\\"14,761, 11,632\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0006400064, ZO0150601506\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0006400064, ZO0150601506\\",\\"41.969\\",\\"41.969\\",2,2,order,pia +BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{ + \\"\\"coordinates\\"\\": [ + -74, + 40.8 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"3.6, 17.484\\",\\"7.988, 33\\",\\"20,734, 7,539\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"1, 1\\",\\"ZO0638206382, ZO0038800388\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0638206382, ZO0038800388\\",\\"40.969\\",\\"40.969\\",2,2,order,brigitte +KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mccarthy\\",\\"Abd Mccarthy\\",MALE,52,Mccarthy,Mccarthy,\\"(empty)\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590937,\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"28.984, 12.992\\",\\"28.984, 12.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.344, 6.109\\",\\"28.984, 12.992\\",\\"14,438, 23,607\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0297602976, ZO0565605656\\",\\"0, 0\\",\\"28.984, 12.992\\",\\"28.984, 12.992\\",\\"0, 0\\",\\"ZO0297602976, ZO0565605656\\",\\"41.969\\",\\"41.969\\",2,2,order,abd " `; diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/generate_csv_discover.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/generate_csv_discover.snap new file mode 100644 index 0000000000000..52f53377b109d --- /dev/null +++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/generate_csv_discover.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Reporting APIs Generate CSV from SearchSource exported CSV file matches snapshot 1`] = ` +"\\"_id\\",\\"_index\\",\\"_score\\",\\"_type\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +NwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Lambert\\",\\"Mostafa Lambert\\",MALE,9,Lambert,Lambert,\\"(empty)\\",Tuesday,1,\\"mostafa@lambert-family.zzz\\",Cairo,Africa,EG,\\"{ + \\"\\"coordinates\\"\\": [ + 31.3, + 30.1 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567868,\\"sold_product_567868_15827, sold_product_567868_6221\\",\\"sold_product_567868_15827, sold_product_567868_6221\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"9.867, 15.07\\",\\"20.984, 28.984\\",\\"15,827, 6,221\\",\\"Belt - black/brown, Shirt - dark blue\\",\\"Belt - black/brown, Shirt - dark blue\\",\\"1, 1\\",\\"ZO0310403104, ZO0416604166\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0310403104, ZO0416604166\\",\\"49.969\\",\\"49.969\\",2,2,order,mostafa +SgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Selena,Selena,\\"Selena Lewis\\",\\"Selena Lewis\\",FEMALE,42,Lewis,Lewis,\\"(empty)\\",Tuesday,1,\\"selena@lewis-family.zzz\\",Marrakesh,Africa,MA,\\"{ + \\"\\"coordinates\\"\\": [ + -8, + 31.6 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567446,\\"sold_product_567446_12751, sold_product_567446_12494\\",\\"sold_product_567446_12751, sold_product_567446_12494\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"31.844, 11.25\\",\\"65, 24.984\\",\\"12,751, 12,494\\",\\"Lace-ups - black, Classic heels - cognac/beige\\",\\"Lace-ups - black, Classic heels - cognac/beige\\",\\"1, 1\\",\\"ZO0322803228, ZO0002700027\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0322803228, ZO0002700027\\",90,90,2,2,order,selena +bwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Oliver,Oliver,\\"Oliver Martin\\",\\"Oliver Martin\\",MALE,7,Martin,Martin,\\"(empty)\\",Tuesday,1,\\"oliver@martin-family.zzz\\",\\"-\\",Europe,GB,\\"{ + \\"\\"coordinates\\"\\": [ + -0.1, + 51.5 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",\\"-\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567340,\\"sold_product_567340_3840, sold_product_567340_14835\\",\\"sold_product_567340_3840, sold_product_567340_14835\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"7.82, 21.406\\",\\"16.984, 42\\",\\"3,840, 14,835\\",\\"Sports shirt - dark grey multicolor, High-top trainers - grey\\",\\"Sports shirt - dark grey multicolor, High-top trainers - grey\\",\\"1, 1\\",\\"ZO0615606156, ZO0514905149\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0615606156, ZO0514905149\\",\\"58.969\\",\\"58.969\\",2,2,order,oliver +5AMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Salazar\\",\\"Kamal Salazar\\",MALE,39,Salazar,Salazar,\\"(empty)\\",Tuesday,1,\\"kamal@salazar-family.zzz\\",Istanbul,Asia,TR,\\"{ + \\"\\"coordinates\\"\\": [ + 29, + 41 + ], + \\"\\"type\\"\\": \\"\\"Point\\"\\" +}\\",Istanbul,\\"Spherecords, Spritechnologies\\",\\"Spherecords, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567736,\\"sold_product_567736_24718, sold_product_567736_24306\\",\\"sold_product_567736_24718, sold_product_567736_24306\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spritechnologies\\",\\"Spherecords, Spritechnologies\\",\\"6.109, 36.75\\",\\"11.992, 75\\",\\"24,718, 24,306\\",\\"Pyjama bottoms - light grey multicolor, Waterproof trousers - scarlet\\",\\"Pyjama bottoms - light grey multicolor, Waterproof trousers - scarlet\\",\\"1, 1\\",\\"ZO0663706637, ZO0620906209\\",\\"0, 0\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"0, 0\\",\\"ZO0663706637, ZO0620906209\\",87,87,2,2,order,kamal +" +`; diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/bwc_existing_indexes.ts b/x-pack/test/reporting_api_integration/reporting_and_security/bwc_existing_indexes.ts index 0da51901f9086..168390bc6fc28 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/bwc_existing_indexes.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/bwc_existing_indexes.ts @@ -19,6 +19,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const reportingAPI = getService('reportingAPI'); + const kibanaServer = getService('kibanaServer'); describe('BWC report generation into existing indexes', () => { let cleanupIndexAlias: () => Promise; @@ -28,7 +29,8 @@ export default function ({ getService }: FtrProviderContext) { await reportingAPI.deleteAllReports(); // data to report on await esArchiver.load('test/functional/fixtures/es_archiver/logstash_functional'); - await esArchiver.load('test/functional/fixtures/es_archiver/discover'); // includes index pattern for logstash_functional + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + // archive with reporting index mappings v6.2 await esArchiver.load('x-pack/test/functional/es_archives/reporting/bwc/6_2'); @@ -41,8 +43,8 @@ export default function ({ getService }: FtrProviderContext) { }); after('remove index alias', async () => { - await esArchiver.load('test/functional/fixtures/es_archiver/logstash_functional'); - await esArchiver.load('test/functional/fixtures/es_archiver/discover'); + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); await cleanupIndexAlias(); await esArchiver.unload('x-pack/test/functional/es_archives/reporting/bwc/6_2'); diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts b/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts index fd194a1df1f65..03e1592df0818 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/bwc_generation_urls.ts @@ -36,7 +36,8 @@ export default function ({ getService }: FtrProviderContext) { await reportingAPI.deleteAllReports(); }); - describe('Pre 6_2', () => { + // FLAKY: https://github.com/elastic/kibana/issues/93354 + describe.skip('Pre 6_2', () => { // The URL being tested was captured from release 6.4 and then the layout section was removed to test structure before // preserve_layout was introduced. See https://github.com/elastic/kibana/issues/23414 it('job posted successfully', async () => { diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/download_csv_dashboard.ts b/x-pack/test/reporting_api_integration/reporting_and_security/download_csv_dashboard.ts index 220fe29d5a6e7..3515602342db5 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/download_csv_dashboard.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/download_csv_dashboard.ts @@ -10,10 +10,12 @@ import supertest from 'supertest'; import { JobParamsDownloadCSV } from '../../../plugins/reporting/server/export_types/csv_searchsource_immediate/types'; import { FtrProviderContext } from '../ftr_provider_context'; -const getMockJobParams = (obj: any): JobParamsDownloadCSV => ({ - title: `Mock CSV Title`, - ...obj, -}); +const getMockJobParams = (obj: object) => { + return { + title: `Mock CSV Title`, + ...obj, + } as JobParamsDownloadCSV; +}; // eslint-disable-next-line import/no-default-export export default function ({ getService }: FtrProviderContext) { @@ -31,6 +33,9 @@ export default function ({ getService }: FtrProviderContext) { }, }; + const fromTime = '2019-06-20T00:00:00.000Z'; + const toTime = '2019-06-25T00:00:00.000Z'; + describe('CSV Generation from SearchSource', () => { before(async () => { await kibanaServer.uiSettings.update({ @@ -127,8 +132,8 @@ export default function ({ getService }: FtrProviderContext) { meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, range: { order_date: { - gte: '2019-03-23T03:06:17.785Z', - lte: '2019-10-04T02:33:16.708Z', + gte: fromTime, + lte: toTime, format: 'strict_date_optional_time', }, }, @@ -151,7 +156,7 @@ export default function ({ getService }: FtrProviderContext) { status: resStatus, text: resText, type: resType, - } = (await generateAPI.getCSVFromSearchSource( + } = await generateAPI.getCSVFromSearchSource( getMockJobParams({ searchSource: { query: { query: '', language: 'kuery' }, @@ -168,8 +173,8 @@ export default function ({ getService }: FtrProviderContext) { meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, range: { order_date: { - gte: '2019-03-23T03:06:17.785Z', - lte: '2019-10-04T02:33:16.708Z', + gte: fromTime, + lte: toTime, format: 'strict_date_optional_time', }, }, @@ -181,7 +186,7 @@ export default function ({ getService }: FtrProviderContext) { browserTimezone: 'UTC', title: 'testfooyu78yt90-', }) - )) as supertest.Response; + ); expect(resStatus).to.eql(200); expect(resType).to.eql('text/csv'); expectSnapshot(resText).toMatch(); @@ -382,9 +387,6 @@ export default function ({ getService }: FtrProviderContext) { }); describe('validation', () => { - after(async () => { - await reportingAPI.deleteAllReports(); - }); it('Return a 404', async () => { const { body } = (await generateAPI.getCSVFromSearchSource( getMockJobParams({ @@ -401,6 +403,7 @@ export default function ({ getService }: FtrProviderContext) { expect(body).to.eql(expectedBody); }); + // NOTE: this test requires having the test server run with `xpack.reporting.csv.maxSizeBytes=6000` it(`Searches large amount of data, stops at Max Size Reached`, async () => { await reportingAPI.initEcommerce(); @@ -415,16 +418,7 @@ export default function ({ getService }: FtrProviderContext) { query: { query: '', language: 'kuery' }, index: '5193f870-d861-11e9-a311-0fa548c5f953', sort: [{ order_date: 'desc' }], - fields: [ - 'order_date', - 'category', - 'currency', - 'customer_id', - 'order_id', - 'day_of_week_i', - 'products.created_on', - 'sku', - ], + fields: ['*'], filter: [], parent: { query: { language: 'kuery', query: '' }, @@ -435,8 +429,8 @@ export default function ({ getService }: FtrProviderContext) { meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, range: { order_date: { - gte: '2019-03-23T03:06:17.785Z', - lte: '2019-10-04T02:33:16.708Z', + gte: '2019-03-23T00:00:00.000Z', + lte: '2019-10-04T00:00:00.000Z', format: 'strict_date_optional_time', }, }, diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover.ts b/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover.ts index c2238ccb9c0d7..e16c9063aa497 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover.ts @@ -6,73 +6,70 @@ */ import expect from '@kbn/expect'; -import supertest from 'supertest'; -import { JOB_PARAMS_RISON_CSV_DEPRECATED } from '../services/fixtures'; +import { SearchSourceFields } from 'src/plugins/data/common'; +import { ReportApiJSON } from '../../../plugins/reporting/common/types'; import { FtrProviderContext } from '../ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const supertestSvc = getService('supertest'); const reportingAPI = getService('reportingAPI'); - const generateAPI = { - getCsvFromParamsInPayload: async (jobParams: object = {}) => { - return await supertestSvc - .post(`/api/reporting/generate/csv`) - .set('kbn-xsrf', 'xxx') - .send(jobParams); - }, - getCsvFromParamsInQueryString: async (jobParams: string = '') => { - return await supertestSvc - .post(`/api/reporting/generate/csv?jobParams=${encodeURIComponent(jobParams)}`) - .set('kbn-xsrf', 'xxx'); - }, - }; + describe('Generate CSV from SearchSource', () => { + it(`exported CSV file matches snapshot`, async () => { + await reportingAPI.initEcommerce(); - describe('Generation from Job Params', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/reporting/logs'); - await esArchiver.load('x-pack/test/functional/es_archives/logstash_functional'); - }); + const fromTime = '2019-06-20T00:00:00.000Z'; + const toTime = '2019-06-24T00:00:00.000Z'; - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/reporting/logs'); - await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); - await reportingAPI.deleteAllReports(); - }); + const { text: reportApiJson, status } = await reportingAPI.generateCsv({ + title: 'CSV Report', + browserTimezone: 'UTC', + objectType: 'search', + version: '7.15.0', + searchSource: { + version: true, + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + sort: [{ order_date: 'desc' }], + fields: ['*'], + filter: [], + parent: { + query: { language: 'kuery', query: '' }, + filter: [], + parent: { + filter: [ + { + meta: { index: '5193f870-d861-11e9-a311-0fa548c5f953', params: {} }, + range: { + order_date: { + gte: fromTime, + lte: toTime, + format: 'strict_date_optional_time', + }, + }, + }, + ], + }, + }, + } as unknown as SearchSourceFields, + }); + expect(status).to.be(200); - it('Rejects bogus jobParams', async () => { - const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInPayload({ - jobParams: 0, - })) as supertest.Response; + const { job: report, path: downloadPath } = JSON.parse(reportApiJson) as { + job: ReportApiJSON; + path: string; + }; + expect(report.created_by).to.be('elastic'); + expect(report.jobtype).to.be('csv_searchsource'); - expect(resText).to.match(/expected value of type \[string\] but got \[number\]/); - expect(resStatus).to.eql(400); - }); + // wait for the the pending job to complete + await reportingAPI.waitForJobToFinish(downloadPath); - it('Rejects empty jobParams', async () => { - const { status: resStatus, text: resText } = - (await generateAPI.getCsvFromParamsInPayload()) as supertest.Response; + const csvFile = await reportingAPI.getCompletedJobOutput(downloadPath); + expectSnapshot(csvFile).toMatch(); - expect(resStatus).to.eql(400); - expect(resText).to.match(/jobParams RISON string is required/); - }); - - it('Accepts jobParams in POST payload', async () => { - const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInPayload({ - jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED, - })) as supertest.Response; - expect(resText).to.match(/"jobtype":"csv"/); - expect(resStatus).to.eql(200); - }); - - it('Accepts jobParams in query string', async () => { - const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInQueryString( - JOB_PARAMS_RISON_CSV_DEPRECATED - )) as supertest.Response; - expect(resText).to.match(/"jobtype":"csv"/); - expect(resStatus).to.eql(200); + await reportingAPI.teardownEcommerce(); + await reportingAPI.deleteAllReports(); }); }); } diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover_deprecated.ts b/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover_deprecated.ts new file mode 100644 index 0000000000000..9e3ddfaf57b39 --- /dev/null +++ b/x-pack/test/reporting_api_integration/reporting_and_security/generate_csv_discover_deprecated.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import supertest from 'supertest'; +import { FtrProviderContext } from '../ftr_provider_context'; +import { JOB_PARAMS_RISON_CSV_DEPRECATED } from '../services/fixtures'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const supertestSvc = getService('supertest'); + const reportingAPI = getService('reportingAPI'); + + const generateAPI = { + getCsvFromParamsInPayload: async (jobParams: object = {}) => { + return await supertestSvc + .post(`/api/reporting/generate/csv`) + .set('kbn-xsrf', 'xxx') + .send(jobParams); + }, + getCsvFromParamsInQueryString: async (jobParams: string = '') => { + return await supertestSvc + .post(`/api/reporting/generate/csv?jobParams=${encodeURIComponent(jobParams)}`) + .set('kbn-xsrf', 'xxx'); + }, + }; + + describe('Generation from Legacy Job Params', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/reporting/logs'); + await esArchiver.load('x-pack/test/functional/es_archives/logstash_functional'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/reporting/logs'); + await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); + await reportingAPI.deleteAllReports(); + }); + + it('Rejects bogus jobParams', async () => { + const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInPayload({ + jobParams: 0, + })) as supertest.Response; + + expect(resText).to.match(/expected value of type \[string\] but got \[number\]/); + expect(resStatus).to.eql(400); + }); + + it('Rejects empty jobParams', async () => { + const { status: resStatus, text: resText } = + (await generateAPI.getCsvFromParamsInPayload()) as supertest.Response; + + expect(resStatus).to.eql(400); + expect(resText).to.match(/jobParams RISON string is required/); + }); + + it('Accepts jobParams in POST payload', async () => { + const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInPayload({ + jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED, + })) as supertest.Response; + expect(resText).to.match(/"jobtype":"csv"/); + expect(resStatus).to.eql(200); + }); + + it('Accepts jobParams in query string', async () => { + const { status: resStatus, text: resText } = (await generateAPI.getCsvFromParamsInQueryString( + JOB_PARAMS_RISON_CSV_DEPRECATED + )) as supertest.Response; + expect(resText).to.match(/"jobtype":"csv"/); + expect(resStatus).to.eql(200); + }); + }); +} diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts index 266fee37b288d..159115e2054e1 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts @@ -25,6 +25,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./security_roles_privileges')); loadTestFile(require.resolve('./download_csv_dashboard')); loadTestFile(require.resolve('./generate_csv_discover')); + loadTestFile(require.resolve('./generate_csv_discover_deprecated')); loadTestFile(require.resolve('./network_policy')); loadTestFile(require.resolve('./spaces')); loadTestFile(require.resolve('./usage')); diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/security_roles_privileges.ts b/x-pack/test/reporting_api_integration/reporting_and_security/security_roles_privileges.ts index f260ada7fe15d..ec526ac1cd272 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/security_roles_privileges.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/security_roles_privileges.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { SearchSourceFields } from 'src/plugins/data/common'; import supertest from 'supertest'; import { FtrProviderContext } from '../ftr_provider_context'; @@ -32,11 +33,10 @@ export default function ({ getService }: FtrProviderContext) { query: { query: '', language: 'kuery' }, index: '5193f870-d861-11e9-a311-0fa548c5f953', filter: [], - }, + } as unknown as SearchSourceFields, browserTimezone: 'UTC', title: 'testfooyu78yt90-', - version: '7.13.0', - } as any + } )) as supertest.Response; expect(res.status).to.eql(403); }); @@ -50,11 +50,10 @@ export default function ({ getService }: FtrProviderContext) { query: { query: '', language: 'kuery' }, index: '5193f870-d861-11e9-a311-0fa548c5f953', filter: [], - }, + } as unknown as SearchSourceFields, browserTimezone: 'UTC', title: 'testfooyu78yt90-', - version: '7.13.0', - } as any + } )) as supertest.Response; expect(res.status).to.eql(200); }); @@ -165,23 +164,21 @@ export default function ({ getService }: FtrProviderContext) { describe('Discover: Generate CSV report', () => { it('does not allow user that does not have the role-based privilege', async () => { const res = await reportingAPI.generateCsv( - reportingAPI.DATA_ANALYST_USERNAME, - reportingAPI.DATA_ANALYST_PASSWORD, { browserTimezone: 'UTC', - searchSource: {}, + searchSource: {} as SearchSourceFields, objectType: 'search', title: 'test disallowed', version: '7.14.0', - } + }, + reportingAPI.DATA_ANALYST_USERNAME, + reportingAPI.DATA_ANALYST_PASSWORD ); expect(res.status).to.eql(403); }); it('does allow user with the role-based privilege', async () => { const res = await reportingAPI.generateCsv( - reportingAPI.REPORTING_USER_USERNAME, - reportingAPI.REPORTING_USER_PASSWORD, { browserTimezone: 'UTC', title: 'allowed search', @@ -190,10 +187,12 @@ export default function ({ getService }: FtrProviderContext) { version: true, fields: [{ field: '*', include_unmapped: 'true' }], index: '5193f870-d861-11e9-a311-0fa548c5f953', - } as any, + } as unknown as SearchSourceFields, columns: [], version: '7.13.0', - } + }, + reportingAPI.REPORTING_USER_USERNAME, + reportingAPI.REPORTING_USER_PASSWORD ); expect(res.status).to.eql(200); }); diff --git a/x-pack/test/reporting_api_integration/services/scenarios.ts b/x-pack/test/reporting_api_integration/services/scenarios.ts index 0fd18b4e85129..e39a3e2e5954b 100644 --- a/x-pack/test/reporting_api_integration/services/scenarios.ts +++ b/x-pack/test/reporting_api_integration/services/scenarios.ts @@ -132,7 +132,7 @@ export function createScenarios({ getService }: Pick { + const generateCsv = async (job: JobParamsCSV, username = 'elastic', password = 'changeme') => { const jobParams = rison.encode(job as object as RisonValue); return await supertestWithoutAuth .post(`/api/reporting/generate/csv_searchsource`) @@ -156,6 +156,11 @@ export function createScenarios({ getService }: Pick { + const response = await supertest.get(downloadReportPath); + return response.text as unknown; + }; + const deleteAllReports = async () => { log.debug('ReportingAPI.deleteAllReports'); @@ -184,7 +189,7 @@ export function createScenarios({ getService }: Pick { log.debug('ReportingAPI.makeAllReportingIndicesUnmanaged'); - const settings: any = { + const settings = { 'index.lifecycle.name': null, }; await esSupertest @@ -216,6 +221,7 @@ export function createScenarios({ getService }: Pick { + // Failing: See https://github.com/elastic/kibana/issues/112732 + describe.skip('dashboard in space', () => { describe('Storing search sessions in space', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/dashboard/session_in_space'); diff --git a/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts b/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts index 3f02e64056325..cd13f71cf1bb7 100644 --- a/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts +++ b/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts @@ -26,6 +26,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const searchSessions = getService('searchSessions'); const retry = getService('retry'); const kibanaServer = getService('kibanaServer'); + const toasts = getService('toasts'); describe('discover async search', () => { before(async () => { @@ -112,12 +113,20 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // load URL to restore a saved session await PageObjects.searchSessionsManagement.goTo(); - const searchSessionList = await PageObjects.searchSessionsManagement.getList(); + const searchSessionListBeforeRestore = await PageObjects.searchSessionsManagement.getList(); + const searchesCountBeforeRestore = searchSessionListBeforeRestore[0].searchesCount; // navigate to Discover - await searchSessionList[0].view(); + await searchSessionListBeforeRestore[0].view(); await PageObjects.header.waitUntilLoadingHasFinished(); await searchSessions.expectState('restored'); expect(await PageObjects.discover.hasNoResults()).to.be(true); + expect(await toasts.getToastCount()).to.be(0); // no session restoration related warnings + + await PageObjects.searchSessionsManagement.goTo(); + const searchSessionListAfterRestore = await PageObjects.searchSessionsManagement.getList(); + const searchesCountAfterRestore = searchSessionListAfterRestore[0].searchesCount; + + expect(searchesCountBeforeRestore).to.be(searchesCountAfterRestore); // no new searches started during restore }); }); diff --git a/x-pack/test/search_sessions_integration/tests/apps/discover/sessions_in_space.ts b/x-pack/test/search_sessions_integration/tests/apps/discover/sessions_in_space.ts index 728ad056f4e6b..064c6bdc4495e 100644 --- a/x-pack/test/search_sessions_integration/tests/apps/discover/sessions_in_space.ts +++ b/x-pack/test/search_sessions_integration/tests/apps/discover/sessions_in_space.ts @@ -23,7 +23,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const searchSessions = getService('searchSessions'); - describe('discover in space', () => { + // FLAKY https://github.com/elastic/kibana/issues/112913 + describe.skip('discover in space', () => { describe('Storing search sessions in space', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/dashboard/session_in_space'); diff --git a/x-pack/test/security_solution_cypress/config.ts b/x-pack/test/security_solution_cypress/config.ts index d22ff564beb2c..c1c22d1ea1d8f 100644 --- a/x-pack/test/security_solution_cypress/config.ts +++ b/x-pack/test/security_solution_cypress/config.ts @@ -40,6 +40,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { // retrieve rules from the filesystem but not from fleet for Cypress tests '--xpack.securitySolution.prebuiltRulesFromFileSystem=true', '--xpack.securitySolution.prebuiltRulesFromSavedObjects=false', + '--xpack.securitySolution.enableExperimental=["riskyHostsEnabled"]', `--home.disableWelcomeScreen=true`, ], }, diff --git a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json new file mode 100644 index 0000000000000..7327f0fc76897 --- /dev/null +++ b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json @@ -0,0 +1,23 @@ +{ + "type":"doc", + "value":{ + "id":"a4cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f", + "index":"ml_host_risk_score_latest", + "source":{ + "@timestamp":"2021-03-10T14:51:05.766Z", + "risk_score":21, + "host":{ + "name":"ip-10-10-10-121" + }, + "rules":{ + "Unusual Linux Username":{ + "average_risk":21, + "rule_count":2, + "rule_risk":42 + } + }, + "ingest_timestamp":"2021-03-09T18:02:08.319296053Z", + "risk":"Low" + } + } +} diff --git a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json new file mode 100644 index 0000000000000..211c50f6baee2 --- /dev/null +++ b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json @@ -0,0 +1,58 @@ +{ + "type": "index", + "value": { + "index": "ml_host_risk_score_latest", + "mappings": { + "properties": { + "@timestamp": { + "type": "date" + }, + "host": { + "properties": { + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "ingest_timestamp": { + "type": "date" + }, + "risk": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "risk_score": { + "type": "long" + } + } + }, + "settings": { + "index": { + "lifecycle": { + "name": "ml_host_risk_score_latest", + "rollover_alias": "ml_host_risk_score_latest" + }, + "mapping": { + "total_fields": { + "limit": "10000" + } + }, + "max_docvalue_fields_search": "200", + "number_of_replicas": "1", + "number_of_shards": "1", + "refresh_interval": "5s" + } + } + } +} diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts index a793582cb7295..95299d8a81f5c 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts @@ -21,7 +21,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const policyTestResources = getService('policyTestResources'); - describe('When on the Endpoint Policy Details Page', function () { + // FLAKY https://github.com/elastic/kibana/issues/100296 + describe.skip('When on the Endpoint Policy Details Page', function () { describe('with an invalid policy id', () => { it('should display an error', async () => { await pageObjects.policy.navigateToPolicyDetails('invalid-id'); @@ -879,6 +880,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ); expect(await testSubjects.isSelected('policyWindowsEvent_dns')).to.be(wasSelected); }); + + it('should show trusted apps card and link should go back to policy', async () => { + await testSubjects.existOrFail('fleetTrustedAppsCard'); + await (await testSubjects.find('linkToTrustedApps')).click(); + await testSubjects.existOrFail('policyDetailsPage'); + await (await testSubjects.find('policyDetailsBackLink')).click(); + await testSubjects.existOrFail('endpointIntegrationPolicyForm'); + }); }); }); } diff --git a/x-pack/test/security_solution_endpoint/config.ts b/x-pack/test/security_solution_endpoint/config.ts index b00df7732ea4f..2bfb231887ac2 100644 --- a/x-pack/test/security_solution_endpoint/config.ts +++ b/x-pack/test/security_solution_endpoint/config.ts @@ -44,6 +44,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { // always install Endpoint package by default when Fleet sets up `--xpack.fleet.packages.0.name=endpoint`, `--xpack.fleet.packages.0.version=latest`, + // TODO: Remove feature flags once we're good to go + '--xpack.securitySolution.enableExperimental=["trustedAppsByPolicyEnabled"]', ], }, layout: { diff --git a/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.js b/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.ts similarity index 83% rename from x-pack/test/stack_functional_integration/apps/filebeat/filebeat.js rename to x-pack/test/stack_functional_integration/apps/filebeat/filebeat.ts index 85570fc8b0158..4bcdc75d7fa50 100644 --- a/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.js +++ b/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.ts @@ -6,8 +6,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ getService, getPageObjects }) { +export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('check filebeat', function () { const retry = getService('retry'); const PageObjects = getPageObjects(['common', 'discover', 'timePicker']); @@ -17,7 +18,7 @@ export default function ({ getService, getPageObjects }) { await PageObjects.discover.selectIndexPattern('filebeat-*'); await PageObjects.timePicker.setCommonlyUsedTime('Last_30 days'); await retry.try(async () => { - const hitCount = parseInt(await PageObjects.discover.getHitCount()); + const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); expect(hitCount).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/stack_functional_integration/apps/filebeat/index.js b/x-pack/test/stack_functional_integration/apps/filebeat/index.ts similarity index 70% rename from x-pack/test/stack_functional_integration/apps/filebeat/index.js rename to x-pack/test/stack_functional_integration/apps/filebeat/index.ts index 478914d395c39..24077f40c9324 100644 --- a/x-pack/test/stack_functional_integration/apps/filebeat/index.js +++ b/x-pack/test/stack_functional_integration/apps/filebeat/index.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ loadTestFile }) { +export default function ({ loadTestFile }: FtrProviderContext) { describe('filebeat app', function () { loadTestFile(require.resolve('./filebeat')); }); diff --git a/x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.js b/x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.ts similarity index 54% rename from x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.js rename to x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.ts index 05f03a115f616..801e651d8b92e 100644 --- a/x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.js +++ b/x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.ts @@ -6,19 +6,23 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ getService, getPageObjects }) { +export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const PageObjects = getPageObjects(['common', 'uptime']); - describe('check heartbeat', function () { - it('Uptime app should show snapshot count greater than zero', async function () { + describe('check heartbeat overview page', function () { + it('Uptime app should show 1 UP monitor', async function () { await PageObjects.common.navigateToApp('uptime', { insertTimestamp: false }); await retry.try(async function () { - const upCount = parseInt((await PageObjects.uptime.getSnapshotCount()).up); - expect(upCount).to.be.greaterThan(0); + const upCount = parseInt((await PageObjects.uptime.getSnapshotCount()).up, 10); + expect(upCount).to.eql(1); }); }); + it('Uptime app should show Kibana QA Monitor present', async function () { + await PageObjects.uptime.pageHasExpectedIds(['kibana-qa-monitor']); + }); }); } diff --git a/x-pack/test/stack_functional_integration/apps/heartbeat/index.js b/x-pack/test/stack_functional_integration/apps/heartbeat/index.ts similarity index 72% rename from x-pack/test/stack_functional_integration/apps/heartbeat/index.js rename to x-pack/test/stack_functional_integration/apps/heartbeat/index.ts index 226350a74afc0..85c195a9ceff4 100644 --- a/x-pack/test/stack_functional_integration/apps/heartbeat/index.js +++ b/x-pack/test/stack_functional_integration/apps/heartbeat/index.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ loadTestFile }) { +export default function ({ loadTestFile }: FtrProviderContext) { describe('heartbeat app', function () { require('./_heartbeat'); loadTestFile(require.resolve('./_heartbeat')); diff --git a/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.js b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.ts similarity index 87% rename from x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.js rename to x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.ts index 34f7c924f5ddb..79dc213e5485a 100644 --- a/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.js +++ b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.ts @@ -6,8 +6,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ getService, getPageObjects }) { +export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); const retry = getService('retry'); const browser = getService('browser'); @@ -27,7 +28,7 @@ export default function ({ getService, getPageObjects }) { await PageObjects.discover.selectIndexPattern('metricbeat-*'); await PageObjects.timePicker.setCommonlyUsedTime('Today'); await retry.try(async function () { - const hitCount = parseInt(await PageObjects.discover.getHitCount()); + const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); expect(hitCount).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.ts similarity index 93% rename from x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js rename to x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.ts index ac911a941c146..d2e9adbfd2683 100644 --- a/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js +++ b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.ts @@ -8,11 +8,16 @@ import expect from '@kbn/expect'; import { resolve } from 'path'; import { REPO_ROOT } from '@kbn/dev-utils'; +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; const INTEGRATION_TEST_ROOT = process.env.WORKSPACE || resolve(REPO_ROOT, '../integration-test'); const ARCHIVE = resolve(INTEGRATION_TEST_ROOT, 'test/es_archives/metricbeat'); -export default function ({ getService, getPageObjects, updateBaselines }) { +export default function ({ + getService, + getPageObjects, + updateBaselines, +}: FtrProviderContext & { updateBaselines: boolean }) { const screenshot = getService('screenshots'); const browser = getService('browser'); const log = getService('log'); diff --git a/x-pack/test/stack_functional_integration/apps/metricbeat/index.js b/x-pack/test/stack_functional_integration/apps/metricbeat/index.ts similarity index 74% rename from x-pack/test/stack_functional_integration/apps/metricbeat/index.js rename to x-pack/test/stack_functional_integration/apps/metricbeat/index.ts index 9ee04df965dcc..c4e0db2797b94 100644 --- a/x-pack/test/stack_functional_integration/apps/metricbeat/index.js +++ b/x-pack/test/stack_functional_integration/apps/metricbeat/index.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ loadTestFile }) { +export default function ({ loadTestFile }: FtrProviderContext) { describe('metricbeat app', function () { loadTestFile(require.resolve('./_metricbeat')); loadTestFile(require.resolve('./_metricbeat_dashboard')); diff --git a/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.js b/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.ts similarity index 88% rename from x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.js rename to x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.ts index a5d6e6e924667..d0d7e326441a0 100644 --- a/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.js +++ b/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.ts @@ -6,8 +6,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ getService, getPageObjects }) { +export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); const retry = getService('retry'); const browser = getService('browser'); @@ -31,7 +32,7 @@ export default function ({ getService, getPageObjects }) { await PageObjects.discover.selectIndexPattern('packetbeat-*'); await PageObjects.timePicker.setCommonlyUsedTime('Today'); await retry.try(async function () { - const hitCount = parseInt(await PageObjects.discover.getHitCount()); + const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); expect(hitCount).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/stack_functional_integration/apps/packetbeat/index.js b/x-pack/test/stack_functional_integration/apps/packetbeat/index.ts similarity index 71% rename from x-pack/test/stack_functional_integration/apps/packetbeat/index.js rename to x-pack/test/stack_functional_integration/apps/packetbeat/index.ts index ba0af98d21f6b..70e38b6284fbe 100644 --- a/x-pack/test/stack_functional_integration/apps/packetbeat/index.js +++ b/x-pack/test/stack_functional_integration/apps/packetbeat/index.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ loadTestFile }) { +export default function ({ loadTestFile }: FtrProviderContext) { describe('packetbeat app', function () { loadTestFile(require.resolve('./_packetbeat')); }); diff --git a/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.js b/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.ts similarity index 87% rename from x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.js rename to x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.ts index c983a9155ae6a..9ef8b85c0ec09 100644 --- a/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.js +++ b/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.ts @@ -6,8 +6,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ getService, getPageObjects }) { +export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); const browser = getService('browser'); const PageObjects = getPageObjects(['common', 'discover', 'timePicker']); @@ -26,7 +27,7 @@ export default function ({ getService, getPageObjects }) { await PageObjects.discover.selectIndexPattern('winlogbeat-*'); await PageObjects.timePicker.setCommonlyUsedTime('Today'); await retry.try(async function () { - const hitCount = parseInt(await PageObjects.discover.getHitCount()); + const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); expect(hitCount).to.be.greaterThan(0); }); }); diff --git a/x-pack/test/stack_functional_integration/apps/winlogbeat/index.js b/x-pack/test/stack_functional_integration/apps/winlogbeat/index.ts similarity index 71% rename from x-pack/test/stack_functional_integration/apps/winlogbeat/index.js rename to x-pack/test/stack_functional_integration/apps/winlogbeat/index.ts index bb883ee498181..826a292de5659 100644 --- a/x-pack/test/stack_functional_integration/apps/winlogbeat/index.js +++ b/x-pack/test/stack_functional_integration/apps/winlogbeat/index.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; -export default function ({ loadTestFile }) { +export default function ({ loadTestFile }: FtrProviderContext) { describe('winlogbeat app', function () { loadTestFile(require.resolve('./_winlogbeat')); }); diff --git a/x-pack/test/usage_collection/plugins/application_usage_test/public/plugin.ts b/x-pack/test/usage_collection/plugins/application_usage_test/public/plugin.ts index b0c777593b021..ff1e89b58c7e8 100644 --- a/x-pack/test/usage_collection/plugins/application_usage_test/public/plugin.ts +++ b/x-pack/test/usage_collection/plugins/application_usage_test/public/plugin.ts @@ -12,8 +12,12 @@ import './types'; export class ApplicationUsageTest implements Plugin { public setup(core: CoreSetup) {} - public async start(core: CoreStart) { - const applications = await core.application.applications$.pipe(first()).toPromise(); - window.__applicationIds__ = [...applications.keys()]; + public start(core: CoreStart) { + core.application.applications$ + .pipe(first()) + .toPromise() + .then((applications) => { + window.__applicationIds__ = [...applications.keys()]; + }); } } diff --git a/yarn.lock b/yarn.lock index ef179cc8105ed..b7d21025f38d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1886,14 +1886,14 @@ dependencies: "@hapi/hoek" "9.x.x" -"@hapi/boom@9.x.x", "@hapi/boom@^9.0.0", "@hapi/boom@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.1.1.tgz#89e6f0e01637c2a4228da0d113e8157c93677b04" - integrity sha512-VNR8eDbBrOxBgbkddRYIe7+8DZ+vSbV6qlmaN2x7eWjsUjy2VmQgChkOKcVZIeupEZYj+I0dqNg430OhwzagjA== +"@hapi/boom@9.x.x", "@hapi/boom@^9.0.0", "@hapi/boom@^9.1.0", "@hapi/boom@^9.1.4": + version "9.1.4" + resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.1.4.tgz#1f9dad367c6a7da9f8def24b4a986fc5a7bd9db6" + integrity sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw== dependencies: "@hapi/hoek" "9.x.x" -"@hapi/bounce@2.x.x": +"@hapi/bounce@2.x.x", "@hapi/bounce@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@hapi/bounce/-/bounce-2.0.0.tgz#e6ef56991c366b1e2738b2cd83b01354d938cf3d" integrity sha512-JesW92uyzOOyuzJKjoLHM1ThiOvHPOLDHw01YV8yh5nCso7sDwJho1h0Ad2N+E62bZyz46TG3xhAi/78Gsct6A== @@ -1906,7 +1906,7 @@ resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-2.0.0.tgz#5bb2193eb685c0007540ca61d166d4e1edaf918d" integrity sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg== -"@hapi/call@8.x.x": +"@hapi/call@^8.0.0": version "8.0.1" resolved "https://registry.yarnpkg.com/@hapi/call/-/call-8.0.1.tgz#9e64cd8ba6128eb5be6e432caaa572b1ed8cd7c0" integrity sha512-bOff6GTdOnoe5b8oXRV3lwkQSb/LAWylvDMae6RgEWWntd0SHtkYbQukDHKlfaYtVnSAgIavJ0kqszF/AIBb6g== @@ -1914,7 +1914,7 @@ "@hapi/boom" "9.x.x" "@hapi/hoek" "9.x.x" -"@hapi/catbox-memory@5.x.x": +"@hapi/catbox-memory@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@hapi/catbox-memory/-/catbox-memory-5.0.0.tgz#6c18dad1a80737480d1c33bfbefd5d028deec86d" integrity sha512-ByuxVJPHNaXwLzbBv4GdTr6ccpe1nG+AfYt+8ftDWEJY7EWBWzD+Klhy5oPTDGzU26pNUh1e7fcYI1ILZRxAXQ== @@ -1979,29 +1979,29 @@ "@hapi/validate" "1.x.x" "@hapi/wreck" "17.x.x" -"@hapi/hapi@^20.0.3": - version "20.0.3" - resolved "https://registry.yarnpkg.com/@hapi/hapi/-/hapi-20.0.3.tgz#e72cad460394e6d2c15f9c57abb5d3332dea27e3" - integrity sha512-aqJVHVjoY3phiZsgsGjDRG15CoUNIs1azScqLZDOCZUSKYGTbzPi+K0QP+RUjUJ0m8L9dRuTZ27c8HKxG3wEhA== +"@hapi/hapi@^20.2.0": + version "20.2.0" + resolved "https://registry.yarnpkg.com/@hapi/hapi/-/hapi-20.2.0.tgz#bf0eca9cc591e83f3d72d06a998d31be35d044a1" + integrity sha512-yPH/z8KvlSLV8lI4EuId9z595fKKk5n6YA7H9UddWYWsBXMcnCyoFmHtYq0PCV4sNgKLD6QW9e27R9V9Z9aqqw== dependencies: "@hapi/accept" "^5.0.1" "@hapi/ammo" "^5.0.1" - "@hapi/boom" "9.x.x" - "@hapi/bounce" "2.x.x" - "@hapi/call" "8.x.x" + "@hapi/boom" "^9.1.0" + "@hapi/bounce" "^2.0.0" + "@hapi/call" "^8.0.0" "@hapi/catbox" "^11.1.1" - "@hapi/catbox-memory" "5.x.x" + "@hapi/catbox-memory" "^5.0.0" "@hapi/heavy" "^7.0.1" - "@hapi/hoek" "9.x.x" - "@hapi/mimos" "5.x.x" + "@hapi/hoek" "^9.0.4" + "@hapi/mimos" "^6.0.0" "@hapi/podium" "^4.1.1" - "@hapi/shot" "^5.0.1" - "@hapi/somever" "3.x.x" + "@hapi/shot" "^5.0.5" + "@hapi/somever" "^3.0.0" "@hapi/statehood" "^7.0.3" "@hapi/subtext" "^7.0.3" - "@hapi/teamwork" "5.x.x" - "@hapi/topo" "5.x.x" - "@hapi/validate" "^1.1.0" + "@hapi/teamwork" "^5.1.0" + "@hapi/topo" "^5.0.0" + "@hapi/validate" "^1.1.1" "@hapi/heavy@^7.0.1": version "7.0.1" @@ -2012,15 +2012,15 @@ "@hapi/hoek" "9.x.x" "@hapi/validate" "1.x.x" -"@hapi/hoek@9.x.x", "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.0.4", "@hapi/hoek@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.1.tgz#9daf5745156fd84b8e9889a2dc721f0c58e894aa" - integrity sha512-CAEbWH7OIur6jEOzaai83jq3FmKmv4PmX1JYfs9IrYcGEVI/lyL1EXJGCj7eFVJ0bg5QR8LMxBlEtA+xKiLpFw== +"@hapi/hoek@9.x.x", "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.0.4", "@hapi/hoek@^9.2.0": + version "9.2.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.0.tgz#f3933a44e365864f4dad5db94158106d511e8131" + integrity sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug== -"@hapi/inert@^6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@hapi/inert/-/inert-6.0.3.tgz#57af5d912893fabcb57eb4b956f84f6cd8020fe1" - integrity sha512-Z6Pi0Wsn2pJex5CmBaq+Dky9q40LGzXLUIUFrYpDtReuMkmfy9UuUeYc4064jQ1Xe9uuw7kbwE6Fq6rqKAdjAg== +"@hapi/inert@^6.0.4": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@hapi/inert/-/inert-6.0.4.tgz#0544221eabc457110a426818358d006e70ff1f41" + integrity sha512-tpmNqtCCAd+5Ts07bJmMaA79+ZUIf0zSWnQMaWtbcO4nGrO/yXB2AzoslfzFX2JEV9vGeF3FfL8mYw0pHl8VGg== dependencies: "@hapi/ammo" "5.x.x" "@hapi/boom" "9.x.x" @@ -2040,10 +2040,10 @@ "@hapi/cryptiles" "5.x.x" "@hapi/hoek" "9.x.x" -"@hapi/mimos@5.x.x": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@hapi/mimos/-/mimos-5.0.0.tgz#245c6c98b1cc2c13395755c730321b913de074eb" - integrity sha512-EVS6wJYeE73InTlPWt+2e3Izn319iIvffDreci3qDNT+t3lA5ylJ0/SoTaID8e0TPNUkHUSsgJZXEmLHvoYzrA== +"@hapi/mimos@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@hapi/mimos/-/mimos-6.0.0.tgz#daa523d9c07222c7e8860cb7c9c5501fd6506484" + integrity sha512-Op/67tr1I+JafN3R3XN5DucVSxKRT/Tc+tUszDwENoNpolxeXkhrJ2Czt6B6AAqrespHoivhgZBWYSuANN9QXg== dependencies: "@hapi/hoek" "9.x.x" mime-db "1.x.x" @@ -2074,24 +2074,24 @@ "@hapi/hoek" "9.x.x" "@hapi/nigel" "4.x.x" -"@hapi/podium@4.x.x", "@hapi/podium@^4.1.1": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@hapi/podium/-/podium-4.1.1.tgz#106e5849f2cb19b8767cc16007e0107f27c3c791" - integrity sha512-jh7a6+5Z4FUWzx8fgmxjaAa1DTBu+Qfg+NbVdo0f++rE5DgsVidUYrLDp3db65+QjDLleA2MfKQXkpT8ylBDXA== +"@hapi/podium@4.x.x", "@hapi/podium@^4.1.1", "@hapi/podium@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@hapi/podium/-/podium-4.1.3.tgz#91e20838fc2b5437f511d664aabebbb393578a26" + integrity sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g== dependencies: "@hapi/hoek" "9.x.x" "@hapi/teamwork" "5.x.x" "@hapi/validate" "1.x.x" -"@hapi/shot@^5.0.1": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@hapi/shot/-/shot-5.0.4.tgz#6c978314f21a054c041f4becc50095dd78d3d775" - integrity sha512-PcEz0WJgFDA3xNSMeONgQmothFr7jhbbRRSAKaDh7chN7zOXBlhl13bvKZW6CMb2xVfJUmt34CW3e/oExMgBhQ== +"@hapi/shot@^5.0.5": + version "5.0.5" + resolved "https://registry.yarnpkg.com/@hapi/shot/-/shot-5.0.5.tgz#a25c23d18973bec93c7969c51bf9579632a5bebd" + integrity sha512-x5AMSZ5+j+Paa8KdfCoKh+klB78otxF+vcJR/IoN91Vo2e5ulXIW6HUsFTCU+4W6P/Etaip9nmdAx2zWDimB2A== dependencies: "@hapi/hoek" "9.x.x" "@hapi/validate" "1.x.x" -"@hapi/somever@3.x.x": +"@hapi/somever@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@hapi/somever/-/somever-3.0.0.tgz#f4e9b16a948415b926b4dd898013602b0cb45758" integrity sha512-Upw/kmKotC9iEmK4y047HMYe4LDKsE5NWfjgX41XNKmFvxsQL7OiaCWVhuyyhU0ShDGBfIAnCH8jZr49z/JzZA== @@ -2125,19 +2125,19 @@ "@hapi/pez" "^5.0.1" "@hapi/wreck" "17.x.x" -"@hapi/teamwork@5.x.x": +"@hapi/teamwork@5.x.x", "@hapi/teamwork@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@hapi/teamwork/-/teamwork-5.1.0.tgz#7801a61fc727f702fd2196ef7625eb4e389f4124" integrity sha512-llqoQTrAJDTXxG3c4Kz/uzhBS1TsmSBa/XG5SPcVXgmffHE1nFtyLIK0hNJHCB3EuBKT84adzd1hZNY9GJLWtg== -"@hapi/topo@5.x.x", "@hapi/topo@^5.0.0": +"@hapi/topo@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.0.0.tgz#c19af8577fa393a06e9c77b60995af959be721e7" integrity sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw== dependencies: "@hapi/hoek" "^9.0.0" -"@hapi/validate@1.x.x", "@hapi/validate@^1.1.0": +"@hapi/validate@1.x.x", "@hapi/validate@^1.1.1": version "1.1.3" resolved "https://registry.yarnpkg.com/@hapi/validate/-/validate-1.1.3.tgz#f750a07283929e09b51aa16be34affb44e1931ad" integrity sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA== @@ -5170,41 +5170,42 @@ resolved "https://registry.yarnpkg.com/@types/hapi__catbox/-/hapi__catbox-10.2.3.tgz#c9279c16d709bf2987491c332e11d18124ae018f" integrity sha512-gs6MKMKXzWpSqeYsPaDIDAxD8jLNg7aFxgAJE6Jnc+ns072Z9fuh39/NF5gSk1KNoGCLnIpeZ0etT9gY9QDCKg== -"@types/hapi__cookie@^10.1.1": - version "10.1.1" - resolved "https://registry.yarnpkg.com/@types/hapi__cookie/-/hapi__cookie-10.1.1.tgz#4420c7f89ef466aa8c1f4d9975c62e6b5b066b1c" - integrity sha512-sWVS20wvqbYSjpjpfOwsD/gtDBba3mi+Y4Yg2qZMBs0/VAgvhOOmpBXzFf2rE8rrEuR44n7tzmEgPWRw5q7kaw== +"@types/hapi__cookie@^10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@types/hapi__cookie/-/hapi__cookie-10.1.3.tgz#b0ab2be28669e083c63253927262c43f24395c2c" + integrity sha512-v/hPXxOVfBdkTa+S4cGec88vZjvEbLaZp8xjg2MtjDhykx1/mLtY4EJHk6fI1cW5WGgFV9pgMjz5mOktjNwILw== dependencies: "@types/hapi__hapi" "*" + joi "^17.3.0" -"@types/hapi__h2o2@^8.3.2": - version "8.3.2" - resolved "https://registry.yarnpkg.com/@types/hapi__h2o2/-/hapi__h2o2-8.3.2.tgz#43cce95972c3097a2ca3efe6b7054a0c95fbf291" - integrity sha512-l36uuLHTwUQNbNUIkT14Z4WbJl1CIWpBZu7ZCBemGBypiNnbJxN3o0YyQ6QAid3YYa2C7LVDIdyY4MhpX8q9ZA== +"@types/hapi__h2o2@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@types/hapi__h2o2/-/hapi__h2o2-8.3.3.tgz#f6c5ac480a6fd421025f7d0f78dfa916703511b7" + integrity sha512-+qWZVFVGc5Y0wuNZvVe876VJjUBCJ8eQdXovg4Rg9laHpeERQejluI7aw31xXWfLojTuHz3ThZzC6Orqras05Q== dependencies: "@hapi/boom" "^9.0.0" "@hapi/wreck" "^17.0.0" "@types/hapi__hapi" "*" "@types/node" "*" -"@types/hapi__hapi@*", "@types/hapi__hapi@^20.0.2": - version "20.0.2" - resolved "https://registry.yarnpkg.com/@types/hapi__hapi/-/hapi__hapi-20.0.2.tgz#e7571451f7fb75e87ab3873ec91b92f92cd55fff" - integrity sha512-7FwFoaxSCtHXbHbDdArSeVABFOfMLgVkOvOUtWrqUBzw639B2rq9OHv3kOVDHY0bOao0f6ubMzUxio8WQ9QZfQ== +"@types/hapi__hapi@*", "@types/hapi__hapi@^20.0.9": + version "20.0.9" + resolved "https://registry.yarnpkg.com/@types/hapi__hapi/-/hapi__hapi-20.0.9.tgz#9d570846c96268266a14c970c13aeeaccfc8e172" + integrity sha512-fGpKScknCKZityRXdZgpCLGbm41R1ppFgnKHerfZlqOOlCX/jI129S6ghgBqkqCE8m9A0CIu1h7Ch04lD9KOoA== dependencies: "@hapi/boom" "^9.0.0" "@hapi/iron" "^6.0.0" + "@hapi/podium" "^4.1.3" "@types/hapi__catbox" "*" "@types/hapi__mimos" "*" - "@types/hapi__podium" "*" "@types/hapi__shot" "*" - "@types/joi" "*" "@types/node" "*" + joi "^17.3.0" -"@types/hapi__inert@^5.2.2": - version "5.2.2" - resolved "https://registry.yarnpkg.com/@types/hapi__inert/-/hapi__inert-5.2.2.tgz#6513c487d216ed9377c2c0efceb178fda0928bfa" - integrity sha512-Vp9HS2wi3Qbm1oUlcTvzA2Zd+f3Dwg+tgLqWA6KTCgKbQX4LCPKIvVssbaQAVncmcpH0aPrtkAfftJlS/sMsGg== +"@types/hapi__inert@^5.2.3": + version "5.2.3" + resolved "https://registry.yarnpkg.com/@types/hapi__inert/-/hapi__inert-5.2.3.tgz#f586eb240d5997c9968d1b4e8b37679517045ca1" + integrity sha512-I1mWQrEc7oMqGtofT0rwBgRBCBurz0wNzbq8QZsHWR+aXM0bk1j9GA6zwyGIeO53PNl2C1c2kpXlc084xCV+Tg== dependencies: "@types/hapi__hapi" "*" @@ -5215,11 +5216,6 @@ dependencies: "@types/mime-db" "*" -"@types/hapi__podium@*", "@types/hapi__podium@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@types/hapi__podium/-/hapi__podium-3.4.1.tgz#826ffed038979c844410e576b574f8237afd59bc" - integrity sha512-qgMyeXTZhGWvvUnXFavW2Pksf07IV1haBM/Fdq6cFi1lCIXhUHsaTrr2w651q+rhHZf+1dgP1vltJ0/quLxYYw== - "@types/hapi__shot@*": version "4.1.1" resolved "https://registry.yarnpkg.com/@types/hapi__shot/-/hapi__shot-4.1.1.tgz#c760322b90eb77f36a3003a442e8dc69e6ae3922" @@ -5361,11 +5357,6 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" -"@types/joi@*": - version "14.3.4" - resolved "https://registry.yarnpkg.com/@types/joi/-/joi-14.3.4.tgz#eed1e14cbb07716079c814138831a520a725a1e0" - integrity sha512-1TQNDJvIKlgYXGNIABfgFp9y0FziDpuGrd799Q5RcnsDu+krD+eeW/0Fs5PHARvWWFelOhIG2OPCo6KbadBM4A== - "@types/joi@^17.2.3": version "17.2.3" resolved "https://registry.yarnpkg.com/@types/joi/-/joi-17.2.3.tgz#b7768ed9d84f1ebd393328b9f97c1cf3d2b94798" @@ -5631,10 +5622,10 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node-forge@^0.10.4": - version "0.10.4" - resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-0.10.4.tgz#f30025cc2da0177393b9deaefbf3b9edd55b807b" - integrity sha512-RpP7JCxlPA32n8FE0kjOpCsCrsX6VjiD0fjOCo4NwIn8IdcicHi4B2e+votWuOpOmwzUjMwRLqVIF95epGd5nA== +"@types/node-forge@^0.10.5": + version "0.10.5" + resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-0.10.5.tgz#f79925c88202817a7ec0958c3a9d3a915d362b4f" + integrity sha512-P+Q+MPSDr0RgIzv5h0gJuJDCm1e4RaSu/EMJZTUS4ZzboWH2uX/T7TiqAAcEFTHzCKtgMRqCgTVTX9SD72fMTQ== dependencies: "@types/node" "*" @@ -7732,6 +7723,13 @@ axios@^0.21.1: dependencies: follow-redirects "^1.10.0" +axios@^0.21.2: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + axobject-query@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" @@ -8965,30 +8963,6 @@ cacache@^12.0.2: unique-filename "^1.1.1" y18n "^4.0.0" -cacache@^13.0.1: - version "13.0.1" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" - integrity sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w== - dependencies: - chownr "^1.1.2" - figgy-pudding "^3.5.1" - fs-minipass "^2.0.0" - glob "^7.1.4" - graceful-fs "^4.2.2" - infer-owner "^1.0.4" - lru-cache "^5.1.1" - minipass "^3.0.0" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - p-map "^3.0.0" - promise-inflight "^1.0.1" - rimraf "^2.7.1" - ssri "^7.0.0" - unique-filename "^1.1.1" - cacache@^15.0.3, cacache@^15.0.4, cacache@^15.0.5: version "15.0.5" resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0" @@ -9412,7 +9386,7 @@ chokidar@3.4.3, chokidar@^2.0.0, chokidar@^2.0.4, chokidar@^2.1.1, chokidar@^2.1 optionalDependencies: fsevents "~2.1.2" -chownr@^1.1.1, chownr@^1.1.2: +chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -9441,13 +9415,13 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@^92.0.1: - version "92.0.1" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-92.0.1.tgz#3e28b7e0c9fb94d693cf74d51af0c29d57f18dca" - integrity sha512-LptlDVCs1GgyFNVbRoHzzy948JDVzTgGiVPXjNj385qXKQP3hjAVBIgyvb/Hco0xSEW8fjwJfsm1eQRmu6t4pQ== +chromedriver@^93.0.1: + version "93.0.1" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-93.0.1.tgz#3ed1f7baa98a754fc1788c42ac8e4bb1ab27db32" + integrity sha512-KDzbW34CvQLF5aTkm3b5VdlTrvdIt4wEpCzT2p4XJIQWQZEPco5pNce7Lu9UqZQGkhQ4mpZt4Ky6NKVyIS2N8A== dependencies: "@testim/chrome-version" "^1.0.7" - axios "^0.21.1" + axios "^0.21.2" del "^6.0.0" extract-zip "^2.0.1" https-proxy-agent "^5.0.0" @@ -13927,6 +13901,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.10.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== +follow-redirects@^1.14.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e" + integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw== + font-awesome@4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" @@ -17403,15 +17382,7 @@ jest-when@^3.2.1: bunyan "^1.8.12" expect "^24.8.0" -jest-worker@^25.4.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.5.0.tgz#2611d071b79cea0f43ee57a3d118593ac1547db1" - integrity sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw== - dependencies: - merge-stream "^2.0.0" - supports-color "^7.0.0" - -jest-worker@^26.2.1, jest-worker@^26.6.2: +jest-worker@^26.2.1, jest-worker@^26.5.0, jest-worker@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== @@ -24690,7 +24661,7 @@ serialize-error@^2.1.0: resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" integrity sha1-ULZ51WNc34Rme9yOWa9OW4HV9go= -serialize-javascript@5.0.1: +serialize-javascript@5.0.1, serialize-javascript@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== @@ -25392,14 +25363,6 @@ ssri@^6.0.1: dependencies: figgy-pudding "^3.5.1" -ssri@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-7.1.0.tgz#92c241bf6de82365b5c7fb4bd76e975522e1294d" - integrity sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g== - dependencies: - figgy-pudding "^3.5.1" - minipass "^3.1.1" - ssri@^8.0.0: version "8.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" @@ -26471,21 +26434,6 @@ terser-webpack-plugin@^1.4.3: webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser-webpack-plugin@^2.1.2: - version "2.3.7" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.7.tgz#4910ff5d1a872168cc7fa6cd3749e2b0d60a8a0b" - integrity sha512-xzYyaHUNhzgaAdBsXxk2Yvo/x1NJdslUaussK3fdpBbvttm1iIwU+c26dj9UxJcwk2c5UWt5F55MUTIA8BE7Dg== - dependencies: - cacache "^13.0.1" - find-cache-dir "^3.3.1" - jest-worker "^25.4.0" - p-limit "^2.3.0" - schema-utils "^2.6.6" - serialize-javascript "^3.1.0" - source-map "^0.6.1" - terser "^4.6.12" - webpack-sources "^1.4.3" - terser-webpack-plugin@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-3.1.0.tgz#91e6d39571460ed240c0cf69d295bcf30ebf98cb" @@ -26501,6 +26449,21 @@ terser-webpack-plugin@^3.0.0: terser "^4.8.0" webpack-sources "^1.4.3" +terser-webpack-plugin@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a" + integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ== + dependencies: + cacache "^15.0.5" + find-cache-dir "^3.3.1" + jest-worker "^26.5.0" + p-limit "^3.0.2" + schema-utils "^3.0.0" + serialize-javascript "^5.0.1" + source-map "^0.6.1" + terser "^5.3.4" + webpack-sources "^1.4.3" + terser@5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/terser/-/terser-5.4.0.tgz#9815c0839072d5c894e22c6fc508fbe9f5e7d7e8" @@ -26510,7 +26473,7 @@ terser@5.4.0: source-map "~0.7.2" source-map-support "~0.5.19" -terser@^4.1.2, terser@^4.6.12, terser@^4.6.3, terser@^4.8.0: +terser@^4.1.2, terser@^4.6.3, terser@^4.8.0: version "4.8.0" resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== @@ -26519,7 +26482,7 @@ terser@^4.1.2, terser@^4.6.12, terser@^4.6.3, terser@^4.8.0: source-map "~0.6.1" source-map-support "~0.5.12" -terser@^5.7.1: +terser@^5.3.4, terser@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784" integrity sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==