diff --git a/packages/app/package.json b/packages/app/package.json
index e8dfb94046..07814cdb0d 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -10,7 +10,6 @@
"@backstage/plugin-api-docs": "^0.1.1-alpha.24",
"@backstage/plugin-catalog": "^0.1.1-alpha.24",
"@backstage/plugin-circleci": "^0.1.1-alpha.24",
- "@backstage/plugin-cloudbuild": "^0.1.1-alpha.24",
"@backstage/plugin-cost-insights": "^0.1.1-alpha.24",
"@backstage/plugin-explore": "^0.1.1-alpha.24",
"@backstage/plugin-gcp-projects": "^0.1.1-alpha.24",
@@ -28,6 +27,7 @@
"@backstage/plugin-tech-radar": "^0.1.1-alpha.24",
"@backstage/plugin-techdocs": "^0.1.1-alpha.24",
"@backstage/plugin-welcome": "^0.1.1-alpha.24",
+ "@backstage/plugin-user-settings": "^0.1.1-alpha.24",
"@backstage/test-utils": "^0.1.1-alpha.24",
"@backstage/theme": "^0.1.1-alpha.24",
"@material-ui/core": "^4.11.0",
diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx
index 45ffca7801..9f5387cea8 100644
--- a/packages/app/src/components/Root/Root.tsx
+++ b/packages/app/src/components/Root/Root.tsx
@@ -35,11 +35,10 @@ import {
SidebarDivider,
SidebarSearchField,
SidebarSpace,
- SidebarUserSettings,
- DefaultProviderSettings,
} from '@backstage/core';
import { NavLink } from 'react-router-dom';
import { graphiQLRouteRef } from '@backstage/plugin-graphiql';
+import { UserSettings } from '@backstage/plugin-user-settings';
const useSidebarLogoStyles = makeStyles({
root: {
@@ -103,7 +102,7 @@ const Root: FC<{}> = ({ children }) => (
/>
- } />
+
{children}
diff --git a/packages/app/src/plugins.ts b/packages/app/src/plugins.ts
index 85c4977d67..57dc8a3443 100644
--- a/packages/app/src/plugins.ts
+++ b/packages/app/src/plugins.ts
@@ -36,3 +36,4 @@ export { plugin as GcpProjects } from '@backstage/plugin-gcp-projects';
export { plugin as Kubernetes } from '@backstage/plugin-kubernetes';
export { plugin as Cloudbuild } from '@backstage/plugin-cloudbuild';
export { plugin as CostInsights } from '@backstage/plugin-cost-insights';
+export { plugin as UserSettings } from '@backstage/plugin-user-settings';
diff --git a/packages/core/src/layout/Sidebar/index.ts b/packages/core/src/layout/Sidebar/index.ts
index a644c06e14..803306478d 100644
--- a/packages/core/src/layout/Sidebar/index.ts
+++ b/packages/core/src/layout/Sidebar/index.ts
@@ -31,5 +31,3 @@ export {
sidebarConfig,
} from './config';
export type { SidebarContextType } from './config';
-export { DefaultProviderSettings } from './DefaultProviderSettings';
-export * from './Settings';
diff --git a/plugins/user-settings/.eslintrc.js b/plugins/user-settings/.eslintrc.js
new file mode 100644
index 0000000000..13573efa9c
--- /dev/null
+++ b/plugins/user-settings/.eslintrc.js
@@ -0,0 +1,3 @@
+module.exports = {
+ extends: [require.resolve('@backstage/cli/config/eslint')],
+};
diff --git a/plugins/user-settings/README.md b/plugins/user-settings/README.md
new file mode 100644
index 0000000000..23d3e48fee
--- /dev/null
+++ b/plugins/user-settings/README.md
@@ -0,0 +1,13 @@
+# user-settings
+
+Welcome to the user-settings plugin!
+
+_This plugin was created through the Backstage CLI_
+
+## Getting started
+
+Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/user-settings](http://localhost:3000/user-settings).
+
+You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
+This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
+It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
diff --git a/plugins/user-settings/dev/index.tsx b/plugins/user-settings/dev/index.tsx
new file mode 100644
index 0000000000..264d6f801f
--- /dev/null
+++ b/plugins/user-settings/dev/index.tsx
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed 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 { createDevApp } from '@backstage/dev-utils';
+import { plugin } from '../src/plugin';
+
+createDevApp().registerPlugin(plugin).render();
diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json
new file mode 100644
index 0000000000..97fbb23301
--- /dev/null
+++ b/plugins/user-settings/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@backstage/plugin-user-settings",
+ "version": "0.1.1-alpha.21",
+ "main": "src/index.ts",
+ "types": "src/index.ts",
+ "license": "Apache-2.0",
+ "private": true,
+ "publishConfig": {
+ "access": "public",
+ "main": "dist/index.esm.js",
+ "types": "dist/index.d.ts"
+ },
+ "scripts": {
+ "build": "backstage-cli plugin:build",
+ "start": "backstage-cli plugin:serve",
+ "lint": "backstage-cli lint",
+ "test": "backstage-cli test",
+ "diff": "backstage-cli plugin:diff",
+ "prepack": "backstage-cli prepack",
+ "postpack": "backstage-cli postpack",
+ "clean": "backstage-cli clean"
+ },
+ "dependencies": {
+ "@backstage/core": "^0.1.1-alpha.21",
+ "@backstage/theme": "^0.1.1-alpha.21",
+ "@material-ui/core": "^4.11.0",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "4.0.0-alpha.45",
+ "react": "^16.13.1",
+ "react-dom": "^16.13.1",
+ "react-use": "^15.3.3"
+ },
+ "devDependencies": {
+ "@backstage/cli": "^0.1.1-alpha.21",
+ "@backstage/dev-utils": "^0.1.1-alpha.21",
+ "@testing-library/jest-dom": "^5.10.1",
+ "@testing-library/react": "^10.4.1",
+ "@testing-library/user-event": "^12.0.7",
+ "@types/jest": "^26.0.7",
+ "@types/node": "^12.0.0",
+ "jest-fetch-mock": "^3.0.3"
+ },
+ "files": [
+ "dist"
+ ]
+}
diff --git a/packages/core/src/layout/Sidebar/Settings/AppSettingsList.tsx b/plugins/user-settings/src/components/AppSettingsList.tsx
similarity index 100%
rename from packages/core/src/layout/Sidebar/Settings/AppSettingsList.tsx
rename to plugins/user-settings/src/components/AppSettingsList.tsx
diff --git a/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx b/plugins/user-settings/src/components/AuthProviderList.tsx
similarity index 89%
rename from packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx
rename to plugins/user-settings/src/components/AuthProviderList.tsx
index 34cf6fb837..659af7cf19 100644
--- a/packages/core/src/layout/Sidebar/Settings/AuthProviderList.tsx
+++ b/plugins/user-settings/src/components/AuthProviderList.tsx
@@ -15,8 +15,7 @@
*/
import React from 'react';
-import List from '@material-ui/core/List';
-import ListSubheader from '@material-ui/core/ListSubheader';
+import { List, ListSubheader } from '@material-ui/core';
type Props = {
providerSettings: React.ReactNode;
diff --git a/packages/core/src/layout/Sidebar/DefaultProviderSettings.tsx b/plugins/user-settings/src/components/DefaultProviderSettings.tsx
similarity index 93%
rename from packages/core/src/layout/Sidebar/DefaultProviderSettings.tsx
rename to plugins/user-settings/src/components/DefaultProviderSettings.tsx
index 99c5225c83..646bbb0603 100644
--- a/packages/core/src/layout/Sidebar/DefaultProviderSettings.tsx
+++ b/plugins/user-settings/src/components/DefaultProviderSettings.tsx
@@ -23,10 +23,11 @@ import {
microsoftAuthApiRef,
samlAuthApiRef,
useApi,
-} from '@backstage/core-api';
+} from '@backstage/core';
import Star from '@material-ui/icons/Star';
import React from 'react';
-import { ProviderSettingsItem } from './Settings';
+import { OAuthProviderSettings } from './OAuthProviderSettings';
+import { OIDCProviderSettings } from './OIDCProviderSettings';
export const DefaultProviderSettings = () => {
const configApi = useApi(configApiRef);
diff --git a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx b/plugins/user-settings/src/components/FeatureFlagsItem.tsx
similarity index 95%
rename from packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx
rename to plugins/user-settings/src/components/FeatureFlagsItem.tsx
index 3e40ce69cc..bc327061ef 100644
--- a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsItem.tsx
+++ b/plugins/user-settings/src/components/FeatureFlagsItem.tsx
@@ -15,11 +15,7 @@
*/
import React from 'react';
-import {
- FeatureFlagName,
- useApi,
- featureFlagsApiRef,
-} from '@backstage/core-api';
+import { FeatureFlagName, useApi, featureFlagsApiRef } from '@backstage/core';
import {
ListItem,
ListItemSecondaryAction,
diff --git a/packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx b/plugins/user-settings/src/components/FeatureFlagsList.tsx
similarity index 100%
rename from packages/core/src/layout/Sidebar/Settings/FeatureFlagsList.tsx
rename to plugins/user-settings/src/components/FeatureFlagsList.tsx
diff --git a/plugins/user-settings/src/components/OAuthProviderSettings.tsx b/plugins/user-settings/src/components/OAuthProviderSettings.tsx
new file mode 100644
index 0000000000..2ecc5536ea
--- /dev/null
+++ b/plugins/user-settings/src/components/OAuthProviderSettings.tsx
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed 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 {
+ ApiRef,
+ OAuthApi,
+ SessionStateApi,
+ useApi,
+ Subscription,
+ IconComponent,
+ SessionState,
+} from '@backstage/core';
+import React, { FC, useState, useEffect } from 'react';
+import { ProviderSettingsItem } from './ProviderSettingsItem';
+
+type OAuthProviderSidebarProps = {
+ title: string;
+ icon: IconComponent;
+ apiRef: ApiRef;
+};
+
+export const OAuthProviderSettings: FC = ({
+ title,
+ icon,
+ apiRef,
+}) => {
+ const api = useApi(apiRef);
+ const [signedIn, setSignedIn] = useState(false);
+
+ useEffect(() => {
+ let didCancel = false;
+
+ const checkSession = async () => {
+ const session = await api.getAccessToken('', { optional: true });
+ if (!didCancel) {
+ setSignedIn(!!session);
+ }
+ };
+ let subscription: Subscription;
+ const observeSession = () => {
+ subscription = api
+ .sessionState$()
+ .subscribe((sessionState: SessionState) => {
+ if (!didCancel) {
+ setSignedIn(sessionState === SessionState.SignedIn);
+ }
+ });
+ };
+
+ checkSession();
+ observeSession();
+ return () => {
+ didCancel = true;
+ subscription.unsubscribe();
+ };
+ }, [api]);
+
+ return (
+ api.getAccessToken()}
+ />
+ );
+};
diff --git a/plugins/user-settings/src/components/OIDCProviderSettings.tsx b/plugins/user-settings/src/components/OIDCProviderSettings.tsx
new file mode 100644
index 0000000000..1516b3514d
--- /dev/null
+++ b/plugins/user-settings/src/components/OIDCProviderSettings.tsx
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed 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 {
+ ApiRef,
+ OpenIdConnectApi,
+ SessionStateApi,
+ useApi,
+ Subscription,
+ IconComponent,
+ SessionState,
+} from '@backstage/core';
+import React, { FC, useState, useEffect } from 'react';
+import { ProviderSettingsItem } from './ProviderSettingsItem';
+
+export type OIDCProviderSidebarProps = {
+ title: string;
+ icon: IconComponent;
+ apiRef: ApiRef;
+};
+
+export const OIDCProviderSettings: FC = ({
+ title,
+ icon,
+ apiRef,
+}) => {
+ const api = useApi(apiRef);
+ const [signedIn, setSignedIn] = useState(false);
+
+ useEffect(() => {
+ let didCancel = false;
+
+ const checkSession = async () => {
+ const session = await api.getIdToken({ optional: true });
+ if (!didCancel) {
+ setSignedIn(!!session);
+ }
+ };
+
+ let subscription: Subscription;
+ const observeSession = () => {
+ subscription = api
+ .sessionState$()
+ .subscribe((sessionState: SessionState) => {
+ if (!didCancel) {
+ setSignedIn(sessionState === SessionState.SignedIn);
+ }
+ });
+ };
+
+ checkSession();
+ observeSession();
+ return () => {
+ didCancel = true;
+ subscription.unsubscribe();
+ };
+ }, [api]);
+
+ return (
+ api.getIdToken()}
+ />
+ );
+};
diff --git a/packages/core/src/layout/Sidebar/Settings/PinButton.tsx b/plugins/user-settings/src/components/PinButton.tsx
similarity index 96%
rename from packages/core/src/layout/Sidebar/Settings/PinButton.tsx
rename to plugins/user-settings/src/components/PinButton.tsx
index 2727313ede..0858e9d4fb 100644
--- a/packages/core/src/layout/Sidebar/Settings/PinButton.tsx
+++ b/plugins/user-settings/src/components/PinButton.tsx
@@ -24,7 +24,7 @@ import {
import LockIcon from '@material-ui/icons/Lock';
import LockOpenIcon from '@material-ui/icons/LockOpen';
import { ToggleButton } from '@material-ui/lab';
-import { SidebarPinStateContext } from '../Page';
+import { SidebarPinStateContext } from '@backstage/core';
export const SidebarPinButton = () => {
const { isPinned, toggleSidebarPinState } = useContext(
diff --git a/packages/core/src/layout/Sidebar/Settings/ProviderSettingsItem.tsx b/plugins/user-settings/src/components/ProviderSettingsItem.tsx
similarity index 95%
rename from packages/core/src/layout/Sidebar/Settings/ProviderSettingsItem.tsx
rename to plugins/user-settings/src/components/ProviderSettingsItem.tsx
index 4db7ea0823..e4a3900919 100644
--- a/packages/core/src/layout/Sidebar/Settings/ProviderSettingsItem.tsx
+++ b/plugins/user-settings/src/components/ProviderSettingsItem.tsx
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-import React, { FC, useState, useEffect } from 'react';
+import React from 'react';
+import { IconComponent, OAuthApi, OpenIdConnectApi } from '@backstage/core';
import {
ListItem,
ListItemIcon,
diff --git a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx b/plugins/user-settings/src/components/SettingsDialog.tsx
similarity index 96%
rename from packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx
rename to plugins/user-settings/src/components/SettingsDialog.tsx
index 71c4899862..c121a0b9cb 100644
--- a/packages/core/src/layout/Sidebar/Settings/SettingsDialog.tsx
+++ b/plugins/user-settings/src/components/SettingsDialog.tsx
@@ -28,7 +28,7 @@ import { FeatureFlagsList } from './FeatureFlagsList';
import { SignInAvatar } from './SignInAvatar';
import { UserSettingsMenu } from './UserSettingsMenu';
import { useUserProfile } from './useUserProfileInfo';
-import { useApi, featureFlagsApiRef } from '@backstage/core-api';
+import { useApi, featureFlagsApiRef } from '@backstage/core';
const useStyles = makeStyles({
root: {
diff --git a/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx b/plugins/user-settings/src/components/SignInAvatar.tsx
similarity index 96%
rename from packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx
rename to plugins/user-settings/src/components/SignInAvatar.tsx
index f0430edfcf..11a5e6ed99 100644
--- a/packages/core/src/layout/Sidebar/Settings/SignInAvatar.tsx
+++ b/plugins/user-settings/src/components/SignInAvatar.tsx
@@ -18,7 +18,7 @@ import React from 'react';
import { BackstageTheme } from '@backstage/theme';
import { makeStyles, Avatar } from '@material-ui/core';
import { useUserProfile } from './useUserProfileInfo';
-import { sidebarConfig } from '../config';
+import { sidebarConfig } from '@backstage/core';
const useStyles = makeStyles({
avatar: {
diff --git a/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx b/plugins/user-settings/src/components/ThemeToggle.tsx
similarity index 97%
rename from packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx
rename to plugins/user-settings/src/components/ThemeToggle.tsx
index a5e703089c..400a918d32 100644
--- a/packages/core/src/layout/Sidebar/Settings/ThemeToggle.tsx
+++ b/plugins/user-settings/src/components/ThemeToggle.tsx
@@ -19,7 +19,7 @@ import { useObservable } from 'react-use';
import LightIcon from '@material-ui/icons/WbSunny';
import DarkIcon from '@material-ui/icons/Brightness2';
import AutoIcon from '@material-ui/icons/BrightnessAuto';
-import { appThemeApiRef, useApi } from '@backstage/core-api';
+import { appThemeApiRef, useApi } from '@backstage/core';
import ToggleButton from '@material-ui/lab/ToggleButton';
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
import {
diff --git a/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx b/plugins/user-settings/src/components/UserSettings.tsx
similarity index 93%
rename from packages/core/src/layout/Sidebar/Settings/UserSettings.tsx
rename to plugins/user-settings/src/components/UserSettings.tsx
index 85dbefff9b..a5d9bd7778 100644
--- a/packages/core/src/layout/Sidebar/Settings/UserSettings.tsx
+++ b/plugins/user-settings/src/components/UserSettings.tsx
@@ -18,15 +18,14 @@ import React, { useEffect, useContext } from 'react';
import { Popover } from '@material-ui/core';
import { SignInAvatar } from './SignInAvatar';
import { SettingsDialog } from './SettingsDialog';
-import { SidebarItem } from '../Items';
+import { SidebarItem, SidebarContext } from '@backstage/core';
import { useUserProfile } from './useUserProfileInfo';
-import { SidebarContext } from '../config';
type Props = {
providerSettings?: React.ReactNode;
};
-export const SidebarUserSettings = ({ providerSettings }: Props) => {
+export const UserSettings = ({ providerSettings }: Props) => {
const { isOpen: sidebarOpen } = useContext(SidebarContext);
const { displayName } = useUserProfile();
const [open, setOpen] = React.useState(false);
diff --git a/packages/core/src/layout/Sidebar/Settings/UserSettingsMenu.tsx b/plugins/user-settings/src/components/UserSettingsMenu.tsx
similarity index 96%
rename from packages/core/src/layout/Sidebar/Settings/UserSettingsMenu.tsx
rename to plugins/user-settings/src/components/UserSettingsMenu.tsx
index 151ddb6e75..40b101fe4d 100644
--- a/packages/core/src/layout/Sidebar/Settings/UserSettingsMenu.tsx
+++ b/plugins/user-settings/src/components/UserSettingsMenu.tsx
@@ -15,7 +15,7 @@
*/
import React from 'react';
-import { identityApiRef, useApi } from '@backstage/core-api';
+import { identityApiRef, useApi } from '@backstage/core';
import { IconButton, ListItemIcon, Menu, MenuItem } from '@material-ui/core';
import SignOutIcon from '@material-ui/icons/MeetingRoom';
import MoreVertIcon from '@material-ui/icons/MoreVert';
diff --git a/packages/core/src/layout/Sidebar/Settings/index.ts b/plugins/user-settings/src/components/index.ts
similarity index 83%
rename from packages/core/src/layout/Sidebar/Settings/index.ts
rename to plugins/user-settings/src/components/index.ts
index 15042dc85d..59a8b425e4 100644
--- a/packages/core/src/layout/Sidebar/Settings/index.ts
+++ b/plugins/user-settings/src/components/index.ts
@@ -14,5 +14,4 @@
* limitations under the License.
*/
-export { ProviderSettingsItem } from './ProviderSettingsItem';
-export { SidebarUserSettings } from './UserSettings';
+export { UserSettings } from './UserSettings';
diff --git a/packages/core/src/layout/Sidebar/Settings/useUserProfileInfo.ts b/plugins/user-settings/src/components/useUserProfileInfo.ts
similarity index 93%
rename from packages/core/src/layout/Sidebar/Settings/useUserProfileInfo.ts
rename to plugins/user-settings/src/components/useUserProfileInfo.ts
index 60dae294a5..428719160d 100644
--- a/packages/core/src/layout/Sidebar/Settings/useUserProfileInfo.ts
+++ b/plugins/user-settings/src/components/useUserProfileInfo.ts
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import { useApi, identityApiRef } from '@backstage/core-api';
+import { useApi, identityApiRef } from '@backstage/core';
export const useUserProfile = () => {
const identityApi = useApi(identityApiRef);
diff --git a/plugins/user-settings/src/index.ts b/plugins/user-settings/src/index.ts
new file mode 100644
index 0000000000..311ae69a51
--- /dev/null
+++ b/plugins/user-settings/src/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed 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 { plugin } from './plugin';
+export { UserSettings } from './components/UserSettings';
diff --git a/plugins/user-settings/src/plugin.test.ts b/plugins/user-settings/src/plugin.test.ts
new file mode 100644
index 0000000000..810a2cda12
--- /dev/null
+++ b/plugins/user-settings/src/plugin.test.ts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed 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 { plugin } from './plugin';
+
+describe('user-settings', () => {
+ it('should export plugin', () => {
+ expect(plugin).toBeDefined();
+ });
+});
diff --git a/plugins/user-settings/src/plugin.ts b/plugins/user-settings/src/plugin.ts
new file mode 100644
index 0000000000..5e5461f3b1
--- /dev/null
+++ b/plugins/user-settings/src/plugin.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed 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 { createPlugin } from '@backstage/core';
+// import ExampleComponent from './components/ExampleComponent';
+
+// export const rootRouteRef = createRouteRef({
+// path: '/user-settings',
+// title: 'user-settings',
+// });
+
+export const plugin = createPlugin({
+ id: 'user-settings',
+ // apis: [createApiFactory(GCPApiRef, new GCPClient())],
+ // register({ router }) {
+ // router.addRoute(rootRouteRef, ExampleComponent);
+ // },
+});
diff --git a/plugins/user-settings/src/setupTests.ts b/plugins/user-settings/src/setupTests.ts
new file mode 100644
index 0000000000..4b4cdbdaaf
--- /dev/null
+++ b/plugins/user-settings/src/setupTests.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed 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 '@testing-library/jest-dom';
+
+require('jest-fetch-mock').enableMocks();