From 283c1b160297e8f44efd854c03502603a51671bf Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 5 Dec 2019 14:21:58 +0100 Subject: [PATCH 1/2] Move url state_hashing utils to kibana_utils Get back old error handling behaviour if hashed url was shared directly add missing types improve --- .i18nrc.json | 1 + .../dashboard/dashboard_app_controller.tsx | 4 +- .../kibana/public/dashboard/legacy_imports.ts | 2 +- .../public/discover/angular/discover.js | 4 +- .../kibana/public/discover/kibana_services.ts | 2 +- .../kibana/public/visualize/editor/editor.js | 4 +- .../public/visualize/kibana_services.ts | 2 +- .../public/index.js | 4 +- .../ui/public/chrome/api/sub_url_hooks.js | 15 ++++--- .../state_management/__tests__/state.js | 20 +++++----- .../ui/public/state_management/state.js | 12 ++---- src/plugins/kibana_utils/public/index.ts | 2 + .../public/state_management}/index.ts | 6 ++- .../state_management/state_hash/index.ts | 20 ++++++++++ .../state_hash}/state_hash.test.ts | 5 +-- .../state_hash}/state_hash.ts | 2 +- .../url}/hash_unhash_url.test.ts | 5 +-- .../state_management/url}/hash_unhash_url.ts | 8 ++-- .../public/state_management/url/index.ts | 20 ++++++++++ test/typings/encode_uri_query.d.ts | 24 ++++++++++++ test/typings/rison_node.d.ts | 39 +++++++++++++++++++ .../translations/translations/ja-JP.json | 4 +- .../translations/translations/zh-CN.json | 2 + 23 files changed, 158 insertions(+), 49 deletions(-) rename src/{legacy/ui/public/state_management/state_hashing => plugins/kibana_utils/public/state_management}/index.ts (85%) create mode 100644 src/plugins/kibana_utils/public/state_management/state_hash/index.ts rename src/{legacy/ui/public/state_management/state_hashing => plugins/kibana_utils/public/state_management/state_hash}/state_hash.test.ts (91%) rename src/{legacy/ui/public/state_management/state_hashing => plugins/kibana_utils/public/state_management/state_hash}/state_hash.ts (96%) rename src/{legacy/ui/public/state_management/state_hashing => plugins/kibana_utils/public/state_management/url}/hash_unhash_url.test.ts (97%) rename src/{legacy/ui/public/state_management/state_hashing => plugins/kibana_utils/public/state_management/url}/hash_unhash_url.ts (94%) create mode 100644 src/plugins/kibana_utils/public/state_management/url/index.ts create mode 100644 test/typings/encode_uri_query.d.ts create mode 100644 test/typings/rison_node.d.ts diff --git a/.i18nrc.json b/.i18nrc.json index e5ba6762da154..fac9b9ce53184 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -19,6 +19,7 @@ "kbnVislibVisTypes": "src/legacy/core_plugins/kbn_vislib_vis_types", "kibana_react": "src/legacy/core_plugins/kibana_react", "kibana-react": "src/plugins/kibana_react", + "kibana_utils": "src/plugins/kibana_utils", "navigation": "src/legacy/core_plugins/navigation", "newsfeed": "src/plugins/newsfeed", "regionMap": "src/legacy/core_plugins/region_map", diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx index b5a6db912bdf0..c68e368fb6469 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx @@ -36,7 +36,7 @@ import { KbnUrl, SaveOptions, SavedObjectFinder, - unhashUrl, + StateManagement, } from './legacy_imports'; import { FilterStateManager, IndexPattern } from '../../../data/public'; import { Query, SavedQuery, IndexPatterns } from '../../../../../plugins/data/public'; @@ -747,7 +747,7 @@ export class DashboardAppController { anchorElement, allowEmbed: true, allowShortUrl: !dashboardConfig.getHideWriteControls(), - shareableUrl: unhashUrl(window.location.href), + shareableUrl: StateManagement.Url.unhashUrl(window.location.href), objectId: dash.id, objectType: 'dashboard', sharingData: { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts index 7c3c389330887..7a8286eef8948 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts @@ -63,6 +63,6 @@ export { confirmModalFactory } from 'ui/modals/confirm_modal'; export { configureAppAngularModule } from 'ui/legacy_compat'; export { stateMonitorFactory, StateMonitor } from 'ui/state_management/state_monitor_factory'; export { ensureDefaultIndexPattern } from 'ui/legacy_compat'; -export { unhashUrl } from 'ui/state_management/state_hashing'; +export { StateManagement } from '../../../../../plugins/kibana_utils/public'; export { IInjector } from 'ui/chrome'; export { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder'; diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js index 7abb7166aa902..eb15cff39b395 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js @@ -48,7 +48,7 @@ import { migrateLegacyQuery, RequestAdapter, showSaveModal, - unhashUrl, + StateManagement, stateMonitorFactory, subscribeWithScope, tabifyAggResponse, @@ -330,7 +330,7 @@ function discoverController( anchorElement, allowEmbed: false, allowShortUrl: uiCapabilities.discover.createShortUrl, - shareableUrl: unhashUrl(window.location.href), + shareableUrl: StateManagement.Url.unhashUrl(window.location.href), objectId: savedSearch.id, objectType: 'search', sharingData: { diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index 0d9dab96d6120..602c90d868619 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -78,7 +78,7 @@ export { tabifyAggResponse } from 'ui/agg_response/tabify'; // @ts-ignore export { vislibSeriesResponseHandlerProvider } from 'ui/vis/response_handlers/vislib'; export { ensureDefaultIndexPattern } from 'ui/legacy_compat'; -export { unhashUrl } from 'ui/state_management/state_hashing'; +export { StateManagement } from '../../../../../plugins/kibana_utils/public'; // EXPORT types export { Vis } from 'ui/vis'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js index 2cf2584810741..170565907d31b 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js @@ -45,7 +45,7 @@ import { showSaveModal, stateMonitorFactory, subscribeWithScope, - unhashUrl, + StateManagement } from '../kibana_services'; const { @@ -248,7 +248,7 @@ function VisEditor( anchorElement, allowEmbed: true, allowShortUrl: capabilities.visualize.createShortUrl, - shareableUrl: unhashUrl(window.location.href), + shareableUrl: StateManagement.Url.unhashUrl(window.location.href), objectId: savedVis.id, objectType: 'visualization', sharingData: { diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts index 6477d1941c205..2f5f25afe5d89 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts @@ -103,7 +103,7 @@ export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url'; export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal'; -export { unhashUrl } from 'ui/state_management/state_hashing'; +export { StateManagement } from '../../../../../plugins/kibana_utils/public'; export { Container, Embeddable, diff --git a/src/legacy/core_plugins/state_session_storage_redirect/public/index.js b/src/legacy/core_plugins/state_session_storage_redirect/public/index.js index 1aa7bce2af699..e5ec8e323587a 100644 --- a/src/legacy/core_plugins/state_session_storage_redirect/public/index.js +++ b/src/legacy/core_plugins/state_session_storage_redirect/public/index.js @@ -18,7 +18,7 @@ */ import chrome from 'ui/chrome'; -import { hashUrl } from 'ui/state_management/state_hashing'; +import { StateManagement } from '../../../../plugins/kibana_utils/public'; import uiRoutes from 'ui/routes'; import { fatalError } from 'ui/notify'; @@ -29,7 +29,7 @@ uiRoutes url: function (AppState, globalState, $window) { const redirectUrl = chrome.getInjected('redirectUrl'); try { - const hashedUrl = hashUrl(redirectUrl); + const hashedUrl = StateManagement.Url.hashUrl(redirectUrl); const url = chrome.addBasePath(hashedUrl); $window.location = url; diff --git a/src/legacy/ui/public/chrome/api/sub_url_hooks.js b/src/legacy/ui/public/chrome/api/sub_url_hooks.js index e38a1f4b19e56..74a510b860df1 100644 --- a/src/legacy/ui/public/chrome/api/sub_url_hooks.js +++ b/src/legacy/ui/public/chrome/api/sub_url_hooks.js @@ -19,9 +19,8 @@ import url from 'url'; -import { - unhashUrl, -} from '../../state_management/state_hashing'; +import { StateManagement } from '../../../../../plugins/kibana_utils/public'; +import { toastNotifications } from '../../notify/toasts'; export function registerSubUrlHooks(angularModule, internals) { angularModule.run(($rootScope, Private, $location) => { @@ -29,8 +28,14 @@ export function registerSubUrlHooks(angularModule, internals) { function updateSubUrls() { const urlWithHashes = window.location.href; - const urlWithStates = unhashUrl(urlWithHashes); - internals.trackPossibleSubUrl(urlWithStates); + let urlWithStates; + try { + urlWithStates = StateManagement.Url.unhashUrl(urlWithHashes); + } catch (e) { + toastNotifications.addDanger(e.message); + } + + internals.trackPossibleSubUrl(urlWithStates || urlWithHashes); } function onRouteChange($event) { diff --git a/src/legacy/ui/public/state_management/__tests__/state.js b/src/legacy/ui/public/state_management/__tests__/state.js index 6f6f74c9d2bec..cd5f8d3f0c60d 100644 --- a/src/legacy/ui/public/state_management/__tests__/state.js +++ b/src/legacy/ui/public/state_management/__tests__/state.js @@ -26,11 +26,9 @@ import { toastNotifications } from '../../notify'; import * as FatalErrorNS from '../../notify/fatal_error'; import { StateProvider } from '../state'; import { - createStateHash, - isStateHash, - unhashQuery -} from '../state_hashing'; -import { HashedItemStore } from '../../../../../plugins/kibana_utils/public'; + StateManagement, + HashedItemStore +} from '../../../../../plugins/kibana_utils/public'; import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; import { EventsProvider } from '../../events'; @@ -58,7 +56,7 @@ describe('State Management', () => { const hashedItemStore = new HashedItemStore(store); const state = new State(param, initial, hashedItemStore); - const getUnhashedSearch = () => unhashQuery($location.search()); + const getUnhashedSearch = () => StateManagement.Url.unhashQuery($location.search()); return { store, hashedItemStore, state, getUnhashedSearch }; }; @@ -248,7 +246,7 @@ describe('State Management', () => { state.save(); const urlVal = $location.search()[state.getQueryParamName()]; - expect(isStateHash(urlVal)).to.be(true); + expect(StateManagement.StateHash.isStateHash(urlVal)).to.be(true); expect(hashedItemStore.getItem(urlVal)).to.eql(JSON.stringify({ foo: 'bar' })); }); @@ -262,7 +260,7 @@ describe('State Management', () => { const urlVal = $location.search()._s; expect(urlVal).to.not.be(rison); - expect(isStateHash(urlVal)).to.be(true); + expect(StateManagement.StateHash.isStateHash(urlVal)).to.be(true); expect(hashedItemStore.getItem(urlVal)).to.eql(JSON.stringify(obj)); }); @@ -278,7 +276,7 @@ describe('State Management', () => { const { state } = setup({ storeInHash: true }); const search = $location.search(); - const badHash = createStateHash('{"a": "b"}', () => null); + const badHash = StateManagement.StateHash.createStateHash('{"a": "b"}', () => null); search[state.getQueryParamName()] = badHash; $location.search(search); @@ -315,10 +313,10 @@ describe('State Management', () => { expect(state.translateHashToRison('(a:b)')).to.be('(a:b)'); expect(state.translateHashToRison('')).to.be(''); - const existingHash = createStateHash('{"a": "b"}', () => null); + const existingHash = StateManagement.StateHash.createStateHash('{"a": "b"}', () => null); hashedItemStore.setItem(existingHash, '{"a": "b"}'); - const nonExistingHash = createStateHash('{"b": "c"}', () => null); + const nonExistingHash = StateManagement.StateHash.createStateHash('{"b": "c"}', () => null); expect(state.translateHashToRison(existingHash)).to.be('(a:b)'); expect(state.translateHashToRison(nonExistingHash)).to.be('!n'); diff --git a/src/legacy/ui/public/state_management/state.js b/src/legacy/ui/public/state_management/state.js index 359dfa5749611..1df3c45bd03ce 100644 --- a/src/legacy/ui/public/state_management/state.js +++ b/src/legacy/ui/public/state_management/state.js @@ -35,11 +35,7 @@ import { fatalError, toastNotifications } from '../notify'; import './config_provider'; import { createLegacyClass } from '../utils/legacy_class'; import { callEach } from '../utils/function'; -import { hashedItemStore } from '../../../../plugins/kibana_utils/public'; -import { - createStateHash, - isStateHash -} from './state_hashing'; +import { hashedItemStore, StateManagement } from '../../../../plugins/kibana_utils/public'; export function StateProvider(Private, $rootScope, $location, stateManagementConfig, config, kbnUrl, $injector) { const Events = Private(EventsProvider); @@ -95,7 +91,7 @@ export function StateProvider(Private, $rootScope, $location, stateManagementCon return null; } - if (isStateHash(urlVal)) { + if (StateManagement.StateHash.isStateHash(urlVal)) { return this._parseStateHash(urlVal); } @@ -269,7 +265,7 @@ export function StateProvider(Private, $rootScope, $location, stateManagementCon * @return {string} rison */ State.prototype.translateHashToRison = function (stateHashOrRison) { - if (isStateHash(stateHashOrRison)) { + if (StateManagement.StateHash.isStateHash(stateHashOrRison)) { return rison.encode(this._parseStateHash(stateHashOrRison)); } @@ -292,7 +288,7 @@ export function StateProvider(Private, $rootScope, $location, stateManagementCon // We need to strip out Angular-specific properties. const json = angular.toJson(state); - const hash = createStateHash(json); + const hash = StateManagement.StateHash.createStateHash(json); const isItemSet = this._hashedItemStore.setItem(hash, json); if (isItemSet) { diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 22ac720246d4b..60aa9c1610d40 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -28,3 +28,5 @@ export * from './errors'; export * from './field_mapping'; export * from './storage'; export * from './storage/hashed_item_store'; +import * as StateManagement from './state_management'; +export { StateManagement }; diff --git a/src/legacy/ui/public/state_management/state_hashing/index.ts b/src/plugins/kibana_utils/public/state_management/index.ts similarity index 85% rename from src/legacy/ui/public/state_management/state_hashing/index.ts rename to src/plugins/kibana_utils/public/state_management/index.ts index 6225202f90978..8f571e9e4fd75 100644 --- a/src/legacy/ui/public/state_management/state_hashing/index.ts +++ b/src/plugins/kibana_utils/public/state_management/index.ts @@ -17,5 +17,7 @@ * under the License. */ -export { hashUrl, unhashUrl, hashQuery, unhashQuery } from './hash_unhash_url'; -export { createStateHash, isStateHash } from './state_hash'; +import * as Url from './url'; +import * as StateHash from './state_hash'; + +export { Url, StateHash }; diff --git a/src/plugins/kibana_utils/public/state_management/state_hash/index.ts b/src/plugins/kibana_utils/public/state_management/state_hash/index.ts new file mode 100644 index 0000000000000..0e52c4c55872d --- /dev/null +++ b/src/plugins/kibana_utils/public/state_management/state_hash/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './state_hash'; diff --git a/src/legacy/ui/public/state_management/state_hashing/state_hash.test.ts b/src/plugins/kibana_utils/public/state_management/state_hash/state_hash.test.ts similarity index 91% rename from src/legacy/ui/public/state_management/state_hashing/state_hash.test.ts rename to src/plugins/kibana_utils/public/state_management/state_hash/state_hash.test.ts index 83a94e37785c4..cccb74acaf1e5 100644 --- a/src/legacy/ui/public/state_management/state_hashing/state_hash.test.ts +++ b/src/plugins/kibana_utils/public/state_management/state_hash/state_hash.test.ts @@ -18,9 +18,8 @@ */ import { encode as encodeRison } from 'rison-node'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { mockStorage } from '../../../../../plugins/kibana_utils/public/storage/hashed_item_store/mock'; -import { createStateHash, isStateHash } from '../state_hashing'; +import { mockStorage } from '../../storage/hashed_item_store/mock'; +import { createStateHash, isStateHash } from './state_hash'; describe('stateHash', () => { beforeEach(() => { diff --git a/src/legacy/ui/public/state_management/state_hashing/state_hash.ts b/src/plugins/kibana_utils/public/state_management/state_hash/state_hash.ts similarity index 96% rename from src/legacy/ui/public/state_management/state_hashing/state_hash.ts rename to src/plugins/kibana_utils/public/state_management/state_hash/state_hash.ts index b3574876bafae..a3eb5272b112d 100644 --- a/src/legacy/ui/public/state_management/state_hashing/state_hash.ts +++ b/src/plugins/kibana_utils/public/state_management/state_hash/state_hash.ts @@ -18,7 +18,7 @@ */ import { Sha256 } from '../../../../../core/public/utils'; -import { hashedItemStore } from '../../../../../plugins/kibana_utils/public'; +import { hashedItemStore } from '../../storage/hashed_item_store'; // This prefix is used to identify hash strings that have been encoded in the URL. const HASH_PREFIX = 'h@'; diff --git a/src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.test.ts b/src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.test.ts similarity index 97% rename from src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.test.ts rename to src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.test.ts index afbe86a4b4d12..a85158acddefd 100644 --- a/src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.test.ts +++ b/src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.test.ts @@ -17,9 +17,8 @@ * under the License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { mockStorage } from '../../../../../plugins/kibana_utils/public/storage/hashed_item_store/mock'; -import { HashedItemStore } from '../../../../../plugins/kibana_utils/public'; +import { mockStorage } from '../../storage/hashed_item_store/mock'; +import { HashedItemStore } from '../../storage/hashed_item_store'; import { hashUrl, unhashUrl } from './hash_unhash_url'; describe('hash unhash url', () => { diff --git a/src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.ts b/src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.ts similarity index 94% rename from src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.ts rename to src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.ts index 7142683c25115..872e7953f938b 100644 --- a/src/legacy/ui/public/state_management/state_hashing/hash_unhash_url.ts +++ b/src/plugins/kibana_utils/public/state_management/url/hash_unhash_url.ts @@ -22,8 +22,8 @@ import rison, { RisonObject } from 'rison-node'; import { stringify as stringifyQueryString } from 'querystring'; import encodeUriQuery from 'encode-uri-query'; import { format as formatUrl, parse as parseUrl } from 'url'; -import { hashedItemStore } from '../../../../../plugins/kibana_utils/public'; -import { createStateHash, isStateHash } from './state_hash'; +import { hashedItemStore } from '../../storage/hashed_item_store'; +import { createStateHash, isStateHash } from '../state_hash'; export type IParsedUrlQuery = Record; @@ -98,7 +98,7 @@ export function retrieveState(stateHash: string): RisonObject { const json = hashedItemStore.getItem(stateHash); const throwUnableToRestoreUrlError = () => { throw new Error( - i18n.translate('common.ui.stateManagement.unableToRestoreUrlErrorMessage', { + i18n.translate('kibana_utils.stateManagement.url.unableToRestoreUrlErrorMessage', { defaultMessage: 'Unable to completely restore the URL, be sure to use the share functionality.', }) @@ -125,7 +125,7 @@ export function persistState(state: RisonObject): string { if (isItemSet) return hash; // If we ran out of space trying to persist the state, notify the user. const message = i18n.translate( - 'common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage', + 'kibana_utils.stateManagement.url.unableToStoreHistoryInSessionErrorMessage', { defaultMessage: 'Kibana is unable to store history items in your session ' + diff --git a/src/plugins/kibana_utils/public/state_management/url/index.ts b/src/plugins/kibana_utils/public/state_management/url/index.ts new file mode 100644 index 0000000000000..30c5696233db7 --- /dev/null +++ b/src/plugins/kibana_utils/public/state_management/url/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './hash_unhash_url'; diff --git a/test/typings/encode_uri_query.d.ts b/test/typings/encode_uri_query.d.ts new file mode 100644 index 0000000000000..4bfc554624446 --- /dev/null +++ b/test/typings/encode_uri_query.d.ts @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +declare module 'encode-uri-query' { + function encodeUriQuery(query: string, usePercentageSpace?: boolean): string; + // eslint-disable-next-line import/no-default-export + export default encodeUriQuery; +} diff --git a/test/typings/rison_node.d.ts b/test/typings/rison_node.d.ts new file mode 100644 index 0000000000000..2592c36e8ae9a --- /dev/null +++ b/test/typings/rison_node.d.ts @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +declare module 'rison-node' { + export type RisonValue = null | boolean | number | string | RisonObject | RisonArray; + + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface RisonArray extends Array {} + + export interface RisonObject { + [key: string]: RisonValue; + } + + export const decode: (input: string) => RisonValue; + + // eslint-disable-next-line @typescript-eslint/camelcase + export const decode_object: (input: string) => RisonObject; + + export const encode: (input: Input) => string; + + // eslint-disable-next-line @typescript-eslint/camelcase + export const encode_object: (input: Input) => string; +} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index c24f04697e3e5..b9fc90f947e08 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -676,6 +676,8 @@ "kibana-react.savedObjects.saveModal.saveButtonLabel": "保存", "kibana-react.savedObjects.saveModal.saveTitle": "{objectType} を保存", "kibana-react.savedObjects.saveModal.titleLabel": "タイトル", + "kibana_utils.stateManagement.url.unableToRestoreUrlErrorMessage": "URL を完全に復元できません。共有機能を使用していることを確認してください。", + "kibana_utils.stateManagement.url.unableToStoreHistoryInSessionErrorMessage": "セッションがいっぱいで安全に削除できるアイテムが見つからないため、Kibana は履歴アイテムを保存できません。\n\nこれは大抵新規タブに移動することで解決されますが、より大きな問題が原因である可能性もあります。このメッセージが定期的に表示される場合は、{gitHubIssuesUrl} で問題を報告してください。", "inspector.closeButton": "インスペクターを閉じる", "inspector.reqTimestampDescription": "リクエストの開始が記録された時刻です", "inspector.reqTimestampKey": "リクエストのタイムスタンプ", @@ -12750,4 +12752,4 @@ "xpack.licensing.check.errorUnavailableMessage": "現在ライセンス情報が利用できないため {pluginName} を使用できません。", "xpack.licensing.check.errorUnsupportedMessage": "ご使用の {licenseType} ライセンスは {pluginName} をサポートしていません。ライセンスをアップグレードしてください。" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6de1bc2135351..19207007ee714 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -677,6 +677,8 @@ "kibana-react.savedObjects.saveModal.saveButtonLabel": "保存", "kibana-react.savedObjects.saveModal.saveTitle": "保存 {objectType}", "kibana-react.savedObjects.saveModal.titleLabel": "标题", + "kibana_utils.stateManagement.url.unableToRestoreUrlErrorMessage": "无法完整还原 URL,确保使用共享功能。", + "kibana_utils.stateManagement.url.unableToStoreHistoryInSessionErrorMessage": "Kibana 无法将历史记录项存储在您的会话中,因为其已满,并且似乎没有任何可安全删除的项。\n\n通常可通过移至新的标签页来解决此问题,但这会导致更大的问题。如果您有规律地看到此消息,请在 {gitHubIssuesUrl} 提交问题。", "inspector.closeButton": "关闭检查器", "inspector.reqTimestampDescription": "记录请求启动的时间", "inspector.reqTimestampKey": "请求时间戳", From 22d4135a5a4f4217f7106322640a0f56d1f96f0f Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 6 Dec 2019 12:04:03 +0100 Subject: [PATCH 2/2] Remove grouping of imports --- .../dashboard/dashboard_app_controller.tsx | 4 ++-- .../kibana/public/dashboard/legacy_imports.ts | 2 +- .../public/discover/angular/discover.js | 4 ++-- .../kibana/public/discover/kibana_services.ts | 2 +- .../kibana/public/visualize/editor/editor.js | 4 ++-- .../public/visualize/kibana_services.ts | 2 +- .../public/index.js | 4 ++-- .../ui/public/chrome/api/sub_url_hooks.js | 4 ++-- .../state_management/__tests__/state.js | 16 +++++++------ .../ui/public/state_management/state.js | 8 +++---- src/plugins/kibana_utils/public/index.ts | 4 ++-- .../public/state_management/index.ts | 23 ------------------- 12 files changed, 28 insertions(+), 49 deletions(-) delete mode 100644 src/plugins/kibana_utils/public/state_management/index.ts diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx index c68e368fb6469..b5a6db912bdf0 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx @@ -36,7 +36,7 @@ import { KbnUrl, SaveOptions, SavedObjectFinder, - StateManagement, + unhashUrl, } from './legacy_imports'; import { FilterStateManager, IndexPattern } from '../../../data/public'; import { Query, SavedQuery, IndexPatterns } from '../../../../../plugins/data/public'; @@ -747,7 +747,7 @@ export class DashboardAppController { anchorElement, allowEmbed: true, allowShortUrl: !dashboardConfig.getHideWriteControls(), - shareableUrl: StateManagement.Url.unhashUrl(window.location.href), + shareableUrl: unhashUrl(window.location.href), objectId: dash.id, objectType: 'dashboard', sharingData: { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts index 7a8286eef8948..b0f09f0cf9745 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts @@ -63,6 +63,6 @@ export { confirmModalFactory } from 'ui/modals/confirm_modal'; export { configureAppAngularModule } from 'ui/legacy_compat'; export { stateMonitorFactory, StateMonitor } from 'ui/state_management/state_monitor_factory'; export { ensureDefaultIndexPattern } from 'ui/legacy_compat'; -export { StateManagement } from '../../../../../plugins/kibana_utils/public'; +export { unhashUrl } from '../../../../../plugins/kibana_utils/public'; export { IInjector } from 'ui/chrome'; export { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder'; diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js index eb15cff39b395..7abb7166aa902 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js @@ -48,7 +48,7 @@ import { migrateLegacyQuery, RequestAdapter, showSaveModal, - StateManagement, + unhashUrl, stateMonitorFactory, subscribeWithScope, tabifyAggResponse, @@ -330,7 +330,7 @@ function discoverController( anchorElement, allowEmbed: false, allowShortUrl: uiCapabilities.discover.createShortUrl, - shareableUrl: StateManagement.Url.unhashUrl(window.location.href), + shareableUrl: unhashUrl(window.location.href), objectId: savedSearch.id, objectType: 'search', sharingData: { diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index 602c90d868619..43a0afa83dfe4 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -78,7 +78,7 @@ export { tabifyAggResponse } from 'ui/agg_response/tabify'; // @ts-ignore export { vislibSeriesResponseHandlerProvider } from 'ui/vis/response_handlers/vislib'; export { ensureDefaultIndexPattern } from 'ui/legacy_compat'; -export { StateManagement } from '../../../../../plugins/kibana_utils/public'; +export { unhashUrl } from '../../../../../plugins/kibana_utils/public'; // EXPORT types export { Vis } from 'ui/vis'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js index 170565907d31b..c985e1a00655f 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js @@ -45,7 +45,7 @@ import { showSaveModal, stateMonitorFactory, subscribeWithScope, - StateManagement + unhashUrl } from '../kibana_services'; const { @@ -248,7 +248,7 @@ function VisEditor( anchorElement, allowEmbed: true, allowShortUrl: capabilities.visualize.createShortUrl, - shareableUrl: StateManagement.Url.unhashUrl(window.location.href), + shareableUrl: unhashUrl(window.location.href), objectId: savedVis.id, objectType: 'visualization', sharingData: { diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts index 2f5f25afe5d89..40d36dab227fa 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts @@ -103,7 +103,7 @@ export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url'; export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal'; -export { StateManagement } from '../../../../../plugins/kibana_utils/public'; +export { unhashUrl } from '../../../../../plugins/kibana_utils/public'; export { Container, Embeddable, diff --git a/src/legacy/core_plugins/state_session_storage_redirect/public/index.js b/src/legacy/core_plugins/state_session_storage_redirect/public/index.js index e5ec8e323587a..7fbf715ac3616 100644 --- a/src/legacy/core_plugins/state_session_storage_redirect/public/index.js +++ b/src/legacy/core_plugins/state_session_storage_redirect/public/index.js @@ -18,7 +18,7 @@ */ import chrome from 'ui/chrome'; -import { StateManagement } from '../../../../plugins/kibana_utils/public'; +import { hashUrl } from '../../../../plugins/kibana_utils/public'; import uiRoutes from 'ui/routes'; import { fatalError } from 'ui/notify'; @@ -29,7 +29,7 @@ uiRoutes url: function (AppState, globalState, $window) { const redirectUrl = chrome.getInjected('redirectUrl'); try { - const hashedUrl = StateManagement.Url.hashUrl(redirectUrl); + const hashedUrl = hashUrl(redirectUrl); const url = chrome.addBasePath(hashedUrl); $window.location = url; diff --git a/src/legacy/ui/public/chrome/api/sub_url_hooks.js b/src/legacy/ui/public/chrome/api/sub_url_hooks.js index 74a510b860df1..3ff262f546e3c 100644 --- a/src/legacy/ui/public/chrome/api/sub_url_hooks.js +++ b/src/legacy/ui/public/chrome/api/sub_url_hooks.js @@ -19,7 +19,7 @@ import url from 'url'; -import { StateManagement } from '../../../../../plugins/kibana_utils/public'; +import { unhashUrl } from '../../../../../plugins/kibana_utils/public'; import { toastNotifications } from '../../notify/toasts'; export function registerSubUrlHooks(angularModule, internals) { @@ -30,7 +30,7 @@ export function registerSubUrlHooks(angularModule, internals) { const urlWithHashes = window.location.href; let urlWithStates; try { - urlWithStates = StateManagement.Url.unhashUrl(urlWithHashes); + urlWithStates = unhashUrl(urlWithHashes); } catch (e) { toastNotifications.addDanger(e.message); } diff --git a/src/legacy/ui/public/state_management/__tests__/state.js b/src/legacy/ui/public/state_management/__tests__/state.js index cd5f8d3f0c60d..475d7c44a5f5a 100644 --- a/src/legacy/ui/public/state_management/__tests__/state.js +++ b/src/legacy/ui/public/state_management/__tests__/state.js @@ -26,7 +26,9 @@ import { toastNotifications } from '../../notify'; import * as FatalErrorNS from '../../notify/fatal_error'; import { StateProvider } from '../state'; import { - StateManagement, + unhashQuery, + createStateHash, + isStateHash, HashedItemStore } from '../../../../../plugins/kibana_utils/public'; import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; @@ -56,7 +58,7 @@ describe('State Management', () => { const hashedItemStore = new HashedItemStore(store); const state = new State(param, initial, hashedItemStore); - const getUnhashedSearch = () => StateManagement.Url.unhashQuery($location.search()); + const getUnhashedSearch = () => unhashQuery($location.search()); return { store, hashedItemStore, state, getUnhashedSearch }; }; @@ -246,7 +248,7 @@ describe('State Management', () => { state.save(); const urlVal = $location.search()[state.getQueryParamName()]; - expect(StateManagement.StateHash.isStateHash(urlVal)).to.be(true); + expect(isStateHash(urlVal)).to.be(true); expect(hashedItemStore.getItem(urlVal)).to.eql(JSON.stringify({ foo: 'bar' })); }); @@ -260,7 +262,7 @@ describe('State Management', () => { const urlVal = $location.search()._s; expect(urlVal).to.not.be(rison); - expect(StateManagement.StateHash.isStateHash(urlVal)).to.be(true); + expect(isStateHash(urlVal)).to.be(true); expect(hashedItemStore.getItem(urlVal)).to.eql(JSON.stringify(obj)); }); @@ -276,7 +278,7 @@ describe('State Management', () => { const { state } = setup({ storeInHash: true }); const search = $location.search(); - const badHash = StateManagement.StateHash.createStateHash('{"a": "b"}', () => null); + const badHash = createStateHash('{"a": "b"}', () => null); search[state.getQueryParamName()] = badHash; $location.search(search); @@ -313,10 +315,10 @@ describe('State Management', () => { expect(state.translateHashToRison('(a:b)')).to.be('(a:b)'); expect(state.translateHashToRison('')).to.be(''); - const existingHash = StateManagement.StateHash.createStateHash('{"a": "b"}', () => null); + const existingHash = createStateHash('{"a": "b"}', () => null); hashedItemStore.setItem(existingHash, '{"a": "b"}'); - const nonExistingHash = StateManagement.StateHash.createStateHash('{"b": "c"}', () => null); + const nonExistingHash = createStateHash('{"b": "c"}', () => null); expect(state.translateHashToRison(existingHash)).to.be('(a:b)'); expect(state.translateHashToRison(nonExistingHash)).to.be('!n'); diff --git a/src/legacy/ui/public/state_management/state.js b/src/legacy/ui/public/state_management/state.js index 1df3c45bd03ce..27186b4249978 100644 --- a/src/legacy/ui/public/state_management/state.js +++ b/src/legacy/ui/public/state_management/state.js @@ -35,7 +35,7 @@ import { fatalError, toastNotifications } from '../notify'; import './config_provider'; import { createLegacyClass } from '../utils/legacy_class'; import { callEach } from '../utils/function'; -import { hashedItemStore, StateManagement } from '../../../../plugins/kibana_utils/public'; +import { hashedItemStore, isStateHash, createStateHash } from '../../../../plugins/kibana_utils/public'; export function StateProvider(Private, $rootScope, $location, stateManagementConfig, config, kbnUrl, $injector) { const Events = Private(EventsProvider); @@ -91,7 +91,7 @@ export function StateProvider(Private, $rootScope, $location, stateManagementCon return null; } - if (StateManagement.StateHash.isStateHash(urlVal)) { + if (isStateHash(urlVal)) { return this._parseStateHash(urlVal); } @@ -265,7 +265,7 @@ export function StateProvider(Private, $rootScope, $location, stateManagementCon * @return {string} rison */ State.prototype.translateHashToRison = function (stateHashOrRison) { - if (StateManagement.StateHash.isStateHash(stateHashOrRison)) { + if (isStateHash(stateHashOrRison)) { return rison.encode(this._parseStateHash(stateHashOrRison)); } @@ -288,7 +288,7 @@ export function StateProvider(Private, $rootScope, $location, stateManagementCon // We need to strip out Angular-specific properties. const json = angular.toJson(state); - const hash = StateManagement.StateHash.createStateHash(json); + const hash = createStateHash(json); const isItemSet = this._hashedItemStore.setItem(hash, json); if (isItemSet) { diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 60aa9c1610d40..c5c129eca8fd3 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -28,5 +28,5 @@ export * from './errors'; export * from './field_mapping'; export * from './storage'; export * from './storage/hashed_item_store'; -import * as StateManagement from './state_management'; -export { StateManagement }; +export * from './state_management/state_hash'; +export * from './state_management/url'; diff --git a/src/plugins/kibana_utils/public/state_management/index.ts b/src/plugins/kibana_utils/public/state_management/index.ts deleted file mode 100644 index 8f571e9e4fd75..0000000000000 --- a/src/plugins/kibana_utils/public/state_management/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import * as Url from './url'; -import * as StateHash from './state_hash'; - -export { Url, StateHash };