Skip to content

Commit

Permalink
[Spaces] - Support "Recently viewed" widget (#22492)
Browse files Browse the repository at this point in the history
[skip ci]
This PR makes the "Recently viewed" widget on the Kibana home page space-aware. The widget will only show saved objects that were viewed within the user's current space.

This is accomplished by changing the way the `RecentlyAccessed` module creates its `PersistedLog`. Previously, the `PersistedLog` was using a hard-coded key, but now it is deriving its key based off of the current `basePath`, which contains the space identifier.

I chose this approach because this code lies completely within OSS Kibana, and I did not want to make this module aware of the Spaces plugin. Spaces augments the `basePath` in order to function and construct space-aware links within the UI, so this ends up being transparent to consumers of `chrome.getBasePath`


You'll notice that the `PersistedLog` key is partially hashed. We do this because we don't want the browser to store information about which spaces a particular user may or may not have access to (see this [earlier conversation](#19417 (comment)))


### Important
Installations that have a configured `basePath` other than the default `''` will have their "Recently viewed" list cleared after upgrading to 6.5, because the basePath will become part of the `localStorage` key, when it previously wasn't. While this may _technically_ be a breaking change, I'm hoping this will be acceptable.

Fixes #21961
  • Loading branch information
legrego authored Aug 29, 2018
1 parent d5288dd commit 29c7b8a
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 2 deletions.
31 changes: 31 additions & 0 deletions src/ui/public/persisted_log/create_log_key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { Sha256 } from '../crypto';

export function createLogKey(type, optionalIdentifier) {
const baseKey = `kibana.history.${type}`;

if (!optionalIdentifier) {
return baseKey;
}

const protectedIdentifier = new Sha256().update(optionalIdentifier, 'utf8').digest('base64');
return `${baseKey}-${protectedIdentifier}`;
}
35 changes: 35 additions & 0 deletions src/ui/public/persisted_log/create_log_key.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 { createLogKey } from './create_log_key';

describe('createLogKey', () => {
it('should create a key starting with "kibana.history"', () => {
expect(createLogKey('foo', 'bar')).toMatch(/^kibana\.history/);
});

it('should include a hashed suffix of the identifier when present', () => {
const expectedSuffix = `/N4rLtula/QIYB+3If6bXDONEO5CnqBPrlURto+/j7k=`;
expect(createLogKey('foo', 'bar')).toMatch(`kibana.history.foo-${expectedSuffix}`);
});

it('should not include a hashed suffix if the identifier is not present', () => {
expect(createLogKey('foo')).toEqual('kibana.history.foo');
});
});
6 changes: 6 additions & 0 deletions src/ui/public/persisted_log/persisted_log.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import sinon from 'sinon';
import expect from 'expect.js';
import { PersistedLog } from './';

jest.mock('../chrome', () => {
return {
getBasePath: () => `/some/base/path`
};
});

const historyName = 'testHistory';
const historyLimit = 10;
const payload = [
Expand Down
6 changes: 4 additions & 2 deletions src/ui/public/persisted_log/recently_accessed.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/

import chrome from '../chrome';
import { PersistedLog } from './';
import { createLogKey } from './create_log_key';

class RecentlyAccessed {
constructor() {
Expand All @@ -28,7 +29,8 @@ class RecentlyAccessed {
return oldItem.id === newItem.id;
}
};
this.history = new PersistedLog('kibana.history.recentlyAccessed', historyOptions);
const logKey = createLogKey('recentlyAccessed', chrome.getBasePath());
this.history = new PersistedLog(logKey, historyOptions);
}

add(link, label, id) {
Expand Down

0 comments on commit 29c7b8a

Please sign in to comment.