mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Extensions loading (#795)
Signed-off-by: Roman <ixrock@gmail.com> Co-authored-by: Alex Andreev <alex.andreev.email@gmail.com> Co-authored-by: Lauri Nevala <lauri.nevala@gmail.com>
This commit is contained in:
31 files changed
+564
-66
No files matched your search
@@ -4,6 +4,7 @@ import { render } from "react-dom";
|
||||
import { isMac } from "../common/vars";
|
||||
import { userStore } from "../common/user-store";
|
||||
import { workspaceStore } from "../common/workspace-store";
|
||||
import { extensionStore } from "../extensions/extension-store";
|
||||
import { clusterStore, getHostedClusterId } from "../common/cluster-store";
|
||||
import { i18nStore } from "./i18n";
|
||||
import { themeStore } from "./theme.store";
|
||||
@@ -23,6 +24,7 @@ export async function bootstrap(App: AppComponent) {
|
||||
userStore.load(),
|
||||
workspaceStore.load(),
|
||||
clusterStore.load(),
|
||||
extensionStore.load(),
|
||||
i18nStore.init(),
|
||||
themeStore.init(),
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { RouteProps } from "react-router";
|
||||
import { buildURL } from "../../navigation";
|
||||
|
||||
export const extensionsRoute: RouteProps = {
|
||||
path: "/extensions"
|
||||
}
|
||||
|
||||
export interface IExtensionsRouteParams {
|
||||
}
|
||||
|
||||
export const extensionsURL = buildURL<IExtensionsRouteParams>(extensionsRoute.path);
|
||||
@@ -0,0 +1,4 @@
|
||||
.Extensions {
|
||||
$spacing: $padding * 2;
|
||||
padding: $spacing;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import "./extensions.scss"
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { extensionStore } from "../../../extensions/extension-store";
|
||||
import { WizardLayout } from "../layout/wizard-layout";
|
||||
import { Icon } from "../icon";
|
||||
|
||||
@observer
|
||||
export class Extensions extends React.Component {
|
||||
// todo: add input-select to customize extensions loading folder(s)
|
||||
renderInfoPanel() {
|
||||
return (
|
||||
<div className="info-panel flex gaps align-center">
|
||||
<Icon material="info"/>
|
||||
<p>Extensions available to install</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { installed: installedExtensions } = extensionStore;
|
||||
return (
|
||||
<WizardLayout className="Extensions" infoPanel={this.renderInfoPanel()}>
|
||||
<h2>Extensions</h2>
|
||||
<pre>
|
||||
{JSON.stringify(installedExtensions.toJSON(), null, 2)}
|
||||
</pre>
|
||||
</WizardLayout>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./extensions.route"
|
||||
export * from "./extensions"
|
||||
@@ -4,7 +4,6 @@
|
||||
position: relative;
|
||||
border-radius: $radius;
|
||||
padding: $radius;
|
||||
margin-bottom: $padding * 2;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Workspaces, workspacesRoute } from "../+workspaces";
|
||||
import { AddCluster, addClusterRoute } from "../+add-cluster";
|
||||
import { ClusterView } from "./cluster-view";
|
||||
import { ClusterSettings, clusterSettingsRoute } from "../+cluster-settings";
|
||||
import { Extensions, extensionsRoute } from "../+extensions";
|
||||
import { clusterViewRoute, clusterViewURL, getMatchedCluster, getMatchedClusterId } from "./cluster-view.route";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { hasLoadedView, initView, lensViews, refreshViews } from "./lens-views";
|
||||
@@ -60,6 +61,7 @@ export class ClusterManager extends React.Component {
|
||||
<Route component={AddCluster} {...addClusterRoute}/>
|
||||
<Route component={ClusterView} {...clusterViewRoute}/>
|
||||
<Route component={ClusterSettings} {...clusterSettingsRoute}/>
|
||||
<Route component={Extensions} {...extensionsRoute}/>
|
||||
<Redirect exact to={this.startUrl}/>
|
||||
</Switch>
|
||||
</main>
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
.clusters {
|
||||
@include hidden-scrollbar;
|
||||
padding: 0 $spacing; // extra spacing for cluster-icon's badge
|
||||
margin-bottom: $spacing;
|
||||
margin-bottom: $margin;
|
||||
|
||||
> :last-child {
|
||||
margin-bottom: $margin;
|
||||
.ClusterIcon {
|
||||
margin-bottom: $margin * 1.5;
|
||||
}
|
||||
|
||||
&:empty {
|
||||
@@ -67,4 +67,14 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
> .dynamic-pages {
|
||||
&:not(:empty) {
|
||||
padding-top: $spacing;
|
||||
}
|
||||
|
||||
.Icon {
|
||||
--size: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,7 @@ import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { clusterIpc } from "../../../common/cluster-ipc";
|
||||
import { clusterViewURL, getMatchedClusterId } from "./cluster-view.route";
|
||||
import { DragDropContext, Droppable, Draggable, DropResult, DroppableProvided, DraggableProvided } from "react-beautiful-dnd";
|
||||
|
||||
// fixme: allow to rearrange clusters with drag&drop
|
||||
import { dynamicPages } from "./register-page";
|
||||
|
||||
interface Props {
|
||||
className?: IClassName;
|
||||
@@ -149,6 +148,12 @@ export class ClustersMenu extends React.Component<Props> {
|
||||
<Badge className="counter" label={newContexts.size} tooltip={<Trans>new</Trans>} />
|
||||
)}
|
||||
</div>
|
||||
<div className="dynamic-pages">
|
||||
{Array.from(dynamicPages.all).map(([path, { MenuIcon }]) => {
|
||||
if (!MenuIcon) return;
|
||||
return <MenuIcon onClick={() => navigate(path)}/>
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Dynamic pages
|
||||
|
||||
import React from "react";
|
||||
import { observable } from "mobx";
|
||||
import type { IconProps } from "../icon";
|
||||
|
||||
export interface PageComponents {
|
||||
Main: React.ComponentType<any>;
|
||||
MenuIcon: React.ComponentType<IconProps>;
|
||||
}
|
||||
|
||||
export class PagesStore {
|
||||
all = observable.map<string, PageComponents>();
|
||||
|
||||
getComponents(path: string): PageComponents | null {
|
||||
return this.all.get(path);
|
||||
}
|
||||
|
||||
register(path: string, components: PageComponents) {
|
||||
this.all.set(path, components);
|
||||
}
|
||||
|
||||
unregister(path: string) {
|
||||
this.all.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
export const dynamicPages = new PagesStore();
|
||||
@@ -11,9 +11,15 @@ import { ErrorBoundary } from "./components/error-boundary";
|
||||
import { WhatsNew, whatsNewRoute } from "./components/+whats-new";
|
||||
import { Notifications } from "./components/notifications";
|
||||
import { ConfirmDialog } from "./components/confirm-dialog";
|
||||
import { extensionStore } from "../extensions/extension-store";
|
||||
import { getLensRuntime } from "../extensions/lens-runtime";
|
||||
|
||||
@observer
|
||||
export class LensApp extends React.Component {
|
||||
componentDidMount() {
|
||||
extensionStore.autoEnableOnLoad(getLensRuntime);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<I18nProvider i18n={_i18n}>
|
||||
|
||||
Reference in new issue
Block a user