Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
fee3b2f
[User Storage Service] browser-side client and React hooks
tsullivan May 7, 2026
d99db24
rendering integration: add initial values to HTML to prime the client
tsullivan May 7, 2026
3705dfd
optimize objectsToFetch in server client
tsullivan May 7, 2026
b2fb0bd
comment simplification
tsullivan May 7, 2026
052c487
type check fix
tsullivan May 7, 2026
ed7ddd3
Changes from node scripts/lint.js --fix
kibanamachine May 7, 2026
7c49125
update CODEOWNERS
tsullivan May 7, 2026
1308d1c
roll back unrelated optimization
tsullivan May 7, 2026
de77277
Changes from node scripts/lint_ts_projects --fix
kibanamachine May 7, 2026
22e8d13
Changes from node scripts/regenerate_moon_projects.js --update
kibanamachine May 7, 2026
463d71c
rename provider prop
tsullivan May 8, 2026
90b1ff7
[User Storage] Add documentation
tsullivan May 8, 2026
a9ecfb0
cleanup
tsullivan May 8, 2026
c424548
Merge branch 'main' into user-storage/browser-client
tsullivan May 8, 2026
c3798a8
Merge branch 'main' into user-storage/browser-client
tsullivan May 8, 2026
e1b7da5
scout - plugin test
tsullivan May 9, 2026
97de6a9
scout cleanup
tsullivan May 9, 2026
71a036c
fix rootDir issue (add minor duplications)
tsullivan May 9, 2026
78c8e35
add test plugin to limits
tsullivan May 9, 2026
508feb9
Merge branch 'main' into user-storage/browser-client
Dosant May 11, 2026
dfe0e9a
Merge branch 'main' into user-storage/browser-client
tsullivan May 18, 2026
7303ff7
relocate test plugin
tsullivan May 18, 2026
e4853f7
Changes from node scripts/lint.js --fix
kibanamachine May 18, 2026
dea9a24
refactor fetch user storage values in server render
tsullivan May 18, 2026
cccfd08
Merge branch 'user-storage/browser-client' of github.com:tsullivan/ki…
tsullivan May 18, 2026
2307f46
Changes from node scripts/lint_ts_projects --fix
kibanamachine May 18, 2026
c0b620d
clean up
tsullivan May 18, 2026
55f07f4
Changes from node scripts/generate codeowners
kibanamachine May 18, 2026
74d5535
Changes from node scripts/regenerate_moon_projects.js --update
kibanamachine May 18, 2026
6a47424
add type overloads to meet documentation of client.get()
tsullivan May 18, 2026
0470905
Merge branch 'user-storage/browser-client' of github.com:tsullivan/ki…
tsullivan May 18, 2026
06fe6b9
add `type: set | remove` to the update observable interface
tsullivan May 18, 2026
973c116
fix tests asserting the old timeout+catchError behavior
tsullivan May 18, 2026
69371cb
remove getAll method from browser client
tsullivan May 18, 2026
cac10e1
browser client mock: delete createMock/create
tsullivan May 18, 2026
bc92fc1
add serverInject option in UserStorageDefinition
tsullivan May 19, 2026
aa5bad2
Merge branch 'main' into user-storage/browser-client
tsullivan May 19, 2026
5fda572
Merge branch 'main' into user-storage/browser-client
tsullivan May 20, 2026
967884f
Merge branch 'main' into user-storage/browser-client
tsullivan May 21, 2026
c215f23
rename: `serverInject` -> `preload`
tsullivan May 21, 2026
fcba20b
use lazy value in scout functional test
tsullivan May 21, 2026
5d6fa66
schema not allow null
tsullivan May 21, 2026
5ce9212
add peek to the API to return cached value without lazy fetch
tsullivan May 21, 2026
bfe43d7
fix api tests for per-key fetch
tsullivan May 21, 2026
e49e3f9
fix types for jest test
tsullivan May 21, 2026
910eada
fix scout ui test
tsullivan May 21, 2026
bf5946b
Merge branch 'main' into user-storage/browser-client
tsullivan May 22, 2026
0e65c22
return parsed value from PUT and use it for browser cache
tsullivan May 22, 2026
bc289b4
disallow undefined as allowed value in registration
tsullivan May 22, 2026
0a19ba2
fix type: `set` doesn't return Promise<void>
tsullivan May 22, 2026
c46bbf9
update limits
tsullivan May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -350,11 +350,13 @@ src/core/packages/user-profile/server-mocks @elastic/kibana-core
src/core/packages/user-settings/server @elastic/kibana-security
src/core/packages/user-settings/server-internal @elastic/kibana-security
src/core/packages/user-settings/server-mocks @elastic/kibana-security
src/core/packages/user-storage/browser @elastic/appex-sharedux
src/core/packages/user-storage/browser-internal @elastic/appex-sharedux
src/core/packages/user-storage/browser-mocks @elastic/appex-sharedux
Comment thread
Dosant marked this conversation as resolved.
src/core/packages/user-storage/common @elastic/appex-sharedux
src/core/packages/user-storage/server @elastic/appex-sharedux
src/core/packages/user-storage/server-internal @elastic/appex-sharedux
src/core/packages/user-storage/server-mocks @elastic/appex-sharedux
src/core/packages/user-storage/test/plugins/user_storage_test @elastic/appex-sharedux
src/core/test-helpers/kbn-server @elastic/kibana-core
src/core/test-helpers/model-versions @elastic/kibana-core
src/platform/kbn-ui/side-navigation @elastic/appex-sharedux
Expand Down Expand Up @@ -925,6 +927,7 @@ src/platform/test/plugin_functional/plugins/ui_settings_plugin @elastic/kibana-c
src/platform/test/plugin_functional/plugins/usage_collection @elastic/kibana-core
src/platform/test/server_integration/plugins/status_plugin_a @elastic/kibana-core
src/platform/test/server_integration/plugins/status_plugin_b @elastic/kibana-core
src/platform/test/user_storage/plugins/user_storage_test @elastic/appex-sharedux
src/setup_node_env @elastic/kibana-operations
x-pack/examples/alerting_example @elastic/response-ops
x-pack/examples/embedded_lens_example @elastic/kibana-visualizations
Expand Down
1 change: 0 additions & 1 deletion api_docs/plugin_directory.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana']
| <DocLink id="kibUrlForwardingPluginApi" text="urlForwarding"/> | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 12 | 0 | 12 | 0 |
| <DocLink id="kibUsageApiPluginApi" text="usageApi"/> | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 30 | 0 | 10 | 1 |
| <DocLink id="kibUsageCollectionPluginApi" text="usageCollection"/> | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 52 | 0 | 11 | 5 |
| userStorageTest | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 |
| <DocLink id="kibUxPluginApi" text="ux"/> | [@elastic/actionable-obs-team](https://github.com/orgs/elastic/teams/actionable-obs-team) | - | 2 | 0 | 2 | 0 |
| <DocLink id="kibVisDefaultEditorPluginApi" text="visDefaultEditor"/> | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | The default editor used in most aggregation-based visualizations. | 79 | 0 | 70 | 4 |
| <DocLink id="kibVisTypeGaugePluginApi" text="visTypeGauge"/> | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the gauge chart implementation using the elastic-charts library. The goal is to eventually deprecate the old implementation and keep only this. Until then, the library used is defined by the Legacy charts library advanced setting. | 7 | 0 | 7 | 2 |
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,8 @@
"@kbn/core-user-settings-server": "link:src/core/packages/user-settings/server",
"@kbn/core-user-settings-server-internal": "link:src/core/packages/user-settings/server-internal",
"@kbn/core-user-settings-server-mocks": "link:src/core/packages/user-settings/server-mocks",
"@kbn/core-user-storage-browser": "link:src/core/packages/user-storage/browser",
"@kbn/core-user-storage-browser-internal": "link:src/core/packages/user-storage/browser-internal",
"@kbn/core-user-storage-common": "link:src/core/packages/user-storage/common",
"@kbn/core-user-storage-server": "link:src/core/packages/user-storage/server",
"@kbn/core-user-storage-server-internal": "link:src/core/packages/user-storage/server-internal",
Expand Down Expand Up @@ -1242,7 +1244,7 @@
"@kbn/user-profile-components": "link:src/platform/packages/shared/kbn-user-profile-components",
"@kbn/user-profile-examples-plugin": "link:examples/user_profile_examples",
"@kbn/user-profiles-consumer-plugin": "link:x-pack/platform/test/security_api_integration/plugins/user_profiles_consumer",
"@kbn/user-storage-test-plugin": "link:src/core/packages/user-storage/test/plugins/user_storage_test",
"@kbn/user-storage-test-plugin": "link:src/platform/test/user_storage/plugins/user_storage_test",
"@kbn/utility-types": "link:src/platform/packages/shared/kbn-utility-types",
"@kbn/utility-types-jest": "link:src/platform/packages/shared/kbn-utility-types-jest",
"@kbn/utils": "link:src/platform/packages/shared/kbn-utils",
Expand Down Expand Up @@ -1709,6 +1711,7 @@
"@kbn/core-ui-settings-server-mocks": "link:src/core/packages/ui-settings/server-mocks",
"@kbn/core-usage-data-server-mocks": "link:src/core/packages/usage-data/server-mocks",
"@kbn/core-user-activity-server-mocks": "link:src/core/packages/user-activity/server-mocks",
"@kbn/core-user-storage-browser-mocks": "link:src/core/packages/user-storage/browser-mocks",
"@kbn/cypress-config": "link:src/platform/packages/shared/kbn-cypress-config",
"@kbn/cypress-test-helper": "link:src/platform/packages/shared/kbn-cypress-test-helper",
"@kbn/dependency-ownership": "link:packages/kbn-dependency-ownership",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,17 @@ describe('setup.getFeatureFlags()', () => {
expect(contract.getFeatureFlags()).toBeUndefined();
});
});

describe('setup.getUserStorage()', () => {
it('returns injectedMetadata.userStorage', () => {
const injectedMetadata = new InjectedMetadataService({
injectedMetadata: {
userStorage: { values: { 'navigation:layout': { hidden: ['discover'] } } },
},
} as unknown as InjectedMetadataParams);

expect(injectedMetadata.setup().getUserStorage()).toEqual({
values: { 'navigation:layout': { hidden: ['discover'] } },
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ export class InjectedMetadataService {
getFeatureFlags: () => {
return this.state.featureFlags;
},

getUserStorage: () => {
return this.state.userStorage;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be gated and consumers that need injection of their storage can opt into it. Somewhere in the storage integration, there should be a configuration to opt into injection when the consumer registers their storage type.

This should be the case because there could be consumers that have a large payload, where we want to just request the storage item async always.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should even inject the user storage information into the HTML that gets served to the user, I think doing so makes it such we can almost never cache the index HTML for an authenticated user on a CDN given it's content is dynamic, without adding this the dimensions for caching heuristics are well known.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get what you're saying but the pattern of injecting metadata in server-side rendering has been in use for a long time. We already do this with feature flags and UI settings, theme info, etc. It's a useful technique when we need to apply stored values into the hot paths of rendering

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did an experiment to inspect the HTML that is delivered to see what is getting injected. It is the big chunk of data in this screenshot:

Image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm aware we send along couple of these kind of configurations, however those configurations typically could be scoped to a set of users, but with the user storage addition the eventual generated entry point is now completely unique. This is not a blocker from my side, it's just something I want to confirm that we are sure we'd like to do especially that you mentioned consideration for an async approach.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'd like to table this for now. The primary consumer of User Storage will be the project side navigation, using this to store a customized nav for each user / space. I see a risk that would hurt UX if we're not showing the nav to the user asap, because we have to fetch the data in nav plugin setup.

I'll call out your point in the epic issue: https://github.com/elastic/kibana-team/issues/2874

},
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ export interface InternalInjectedMetadataSetup {
initialFeatureFlags: Record<string, unknown>;
}
| undefined;
getUserStorage: () => {
values: Record<string, unknown>;
};
}

/** @internal */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const createSetupContractMock = () => {
getKibanaBuildNumber: jest.fn(),
getCustomBranding: jest.fn(),
getFeatureFlags: jest.fn(),
getUserStorage: jest.fn().mockReturnValue({ values: {} }),
});

return setupContract;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,7 @@ export interface InjectedMetadata {
};
};
customBranding: Pick<CustomBranding, 'logo' | 'customizedLogo' | 'pageTitle'>;
userStorage: {
values: Record<string, unknown>;
};
}
1 change: 1 addition & 0 deletions src/core/packages/lifecycle/browser-mocks/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependsOn:
- '@kbn/core-rendering-browser-mocks'
- '@kbn/core-pricing-browser-mocks'
- '@kbn/core-di-mocks'
- '@kbn/core-user-storage-browser-mocks'
- '@kbn/lazy-object'
tags:
- shared-browser
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { userProfileServiceMock } from '@kbn/core-user-profile-browser-mocks';
import { createCoreStartMock } from './core_start.mock';
import { coreFeatureFlagsMock } from '@kbn/core-feature-flags-browser-mocks';
import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks';
import { userStorageServiceMock } from '@kbn/core-user-storage-browser-mocks';
import { lazyObject } from '@kbn/lazy-object';

export function createCoreSetupMock({
Expand Down Expand Up @@ -56,6 +57,7 @@ export function createCoreSetupMock({
theme: themeServiceMock.createSetupContract(),
security: securityServiceMock.createSetup(),
userProfile: userProfileServiceMock.createSetup(),
userStorage: userStorageServiceMock.createSetupContract(),
plugins: lazyObject({
onSetup: jest.fn(),
onStart: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { userProfileServiceMock } from '@kbn/core-user-profile-browser-mocks';
import { renderingServiceMock } from '@kbn/core-rendering-browser-mocks';
import { coreFeatureFlagsMock } from '@kbn/core-feature-flags-browser-mocks';
import { pricingServiceMock } from '@kbn/core-pricing-browser-mocks';
import { userStorageServiceMock } from '@kbn/core-user-storage-browser-mocks';
import { lazyObject } from '@kbn/lazy-object';

export function createCoreStartMock({ basePath = '' } = {}) {
Expand All @@ -52,6 +53,7 @@ export function createCoreStartMock({ basePath = '' } = {}) {
userProfile: userProfileServiceMock.createStart(),
rendering: renderingServiceMock.create(),
pricing: pricingServiceMock.createStartContract(),
userStorage: userStorageServiceMock.createStartContract(),
plugins: lazyObject({
onStart: jest.fn(),
}),
Expand Down
1 change: 1 addition & 0 deletions src/core/packages/lifecycle/browser-mocks/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@kbn/core-rendering-browser-mocks",
"@kbn/core-pricing-browser-mocks",
"@kbn/core-di-mocks",
"@kbn/core-user-storage-browser-mocks",
"@kbn/lazy-object",
],
"exclude": [
Expand Down
1 change: 1 addition & 0 deletions src/core/packages/lifecycle/browser/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependsOn:
- '@kbn/core-feature-flags-browser'
- '@kbn/core-rendering-browser'
- '@kbn/core-pricing-browser'
- '@kbn/core-user-storage-browser'
- '@kbn/core-di'
tags:
- shared-browser
Expand Down
3 changes: 3 additions & 0 deletions src/core/packages/lifecycle/browser/src/core_setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { CustomBrandingSetup } from '@kbn/core-custom-branding-browser';
import type { PluginsServiceSetup } from '@kbn/core-plugins-contracts-browser';
import type { SecurityServiceSetup } from '@kbn/core-security-browser';
import type { UserProfileServiceSetup } from '@kbn/core-user-profile-browser';
import type { IUserStorageClient } from '@kbn/core-user-storage-browser';
import type { CoreStart } from './core_start';

/**
Expand Down Expand Up @@ -72,6 +73,8 @@ export interface CoreSetup<TPluginsStart extends Record<string, any> = {}, TStar
security: SecurityServiceSetup;
/** {@link UserProfileServiceSetup} */
userProfile: UserProfileServiceSetup;
/** {@link IUserStorageClient} */
userStorage: IUserStorageClient;
/** {@link StartServicesAccessor} */
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
}
Expand Down
3 changes: 3 additions & 0 deletions src/core/packages/lifecycle/browser/src/core_start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type { SecurityServiceStart } from '@kbn/core-security-browser';
import type { RenderingService } from '@kbn/core-rendering-browser';
import type { UserProfileServiceStart } from '@kbn/core-user-profile-browser';
import type { FeatureFlagsStart } from '@kbn/core-feature-flags-browser';
import type { IUserStorageClient } from '@kbn/core-user-storage-browser';

/**
* Core services exposed to the `Plugin` start lifecycle
Expand Down Expand Up @@ -82,6 +83,8 @@ export interface CoreStart {
security: SecurityServiceStart;
/** {@link UserProfileServiceStart} */
userProfile: UserProfileServiceStart;
/** {@link IUserStorageClient} */
userStorage: IUserStorageClient;
/** {@link RenderingService} */
rendering: RenderingService;
}
1 change: 1 addition & 0 deletions src/core/packages/lifecycle/browser/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@kbn/core-feature-flags-browser",
"@kbn/core-rendering-browser",
"@kbn/core-pricing-browser",
"@kbn/core-user-storage-browser",
"@kbn/core-di",
],
"exclude": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export function createPluginSetupContext<
registerUserProfileDelegate: (delegate) =>
deps.userProfile.registerUserProfileDelegate(delegate),
},
userStorage: deps.userStorage,
plugins: {
onSetup: (...dependencyNames) => runtimeResolver.onSetup(plugin.name, dependencyNames),
onStart: (...dependencyNames) => runtimeResolver.onStart(plugin.name, dependencyNames),
Expand Down Expand Up @@ -178,6 +179,7 @@ export function createPluginStartContext<
authc: deps.security.authc,
},
userProfile: deps.userProfile,
userStorage: deps.userStorage,
plugins: {
onStart: (...dependencyNames) => runtimeResolver.onStart(plugin.name, dependencyNames),
},
Expand Down
2 changes: 2 additions & 0 deletions src/core/packages/rendering/server-internal/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ dependsOn:
- '@kbn/core-feature-flags-server-internal'
- '@kbn/core-feature-flags-server-mocks'
- '@kbn/core-feature-flags-server'
- '@kbn/core-user-storage-server'
- '@kbn/core-user-storage-server-mocks'
- '@kbn/repo-info'
tags:
- shared-server
Expand Down
Loading
Loading