diff --git a/frontend/app/block/blockframe.tsx b/frontend/app/block/blockframe.tsx
index 949108f0c..843ae7fe9 100644
--- a/frontend/app/block/blockframe.tsx
+++ b/frontend/app/block/blockframe.tsx
@@ -15,6 +15,8 @@ import { TypeAheadModal } from "@/app/modals/typeaheadmodal";
import { ContextMenuModel } from "@/app/store/contextmenu";
import {
atoms,
+ createBlock,
+ getApi,
getBlockComponentModel,
getConnStatusAtom,
getHostName,
@@ -182,6 +184,9 @@ const BlockFrame_Header = ({
const prevMagifiedState = React.useRef(magnified);
const manageConnection = util.useAtomValueSafe(viewModel?.manageConnection);
const dragHandleRef = preview ? null : nodeModel.dragHandleRef;
+ const connName = blockData?.meta?.connection;
+ const allSettings = jotai.useAtomValue(atoms.fullConfigAtom);
+ const wshEnabled = allSettings?.connections?.[connName]?.["conn:wshenabled"] ?? true;
React.useEffect(() => {
if (!magnified || preview || prevMagifiedState.current) {
@@ -239,6 +244,11 @@ const BlockFrame_Header = ({
);
}
+ const wshInstallButton: IconButtonDecl = {
+ elemtype: "iconbutton",
+ icon: "link-slash",
+ title: "wsh is not installed for this connection",
+ };
return (
@@ -256,6 +266,9 @@ const BlockFrame_Header = ({
changeConnModalAtom={changeConnModalAtom}
/>
)}
+ {manageConnection && !wshEnabled && (
+
+ )}
{headerTextElems}
{endIconsElem}
@@ -568,6 +581,10 @@ const ChangeConnectionBlockModal = React.memo(
const allConnStatus = jotai.useAtomValue(atoms.allConnStatus);
const [rowIndex, setRowIndex] = React.useState(0);
const connStatusMap = new Map();
+ const fullConfig = jotai.useAtomValue(atoms.fullConfigAtom);
+ const connectionsConfig = fullConfig.connections;
+ let filterOutNowsh = util.useAtomValueSafe(viewModel.filterOutNowsh) || true;
+
let maxActiveConnNum = 1;
for (const conn of allConnStatus) {
if (conn.activeconnnum > maxActiveConnNum) {
@@ -638,7 +655,12 @@ const ChangeConnectionBlockModal = React.memo(
if (conn === connSelected) {
createNew = false;
}
- if (conn.includes(connSelected)) {
+ if (
+ conn.includes(connSelected) &&
+ connectionsConfig[conn]?.["display:hidden"] != true &&
+ (connectionsConfig[conn]?.["conn:wshenabled"] != false || !filterOutNowsh)
+ // != false is necessary because of defaults
+ ) {
filteredList.push(conn);
}
}
@@ -647,7 +669,12 @@ const ChangeConnectionBlockModal = React.memo(
if (conn === connSelected) {
createNew = false;
}
- if (conn.includes(connSelected)) {
+ if (
+ conn.includes(connSelected) &&
+ connectionsConfig[conn]?.["display:hidden"] != true &&
+ (connectionsConfig[conn]?.["conn:wshenabled"] != false || !filterOutNowsh)
+ // != false is necessary because of defaults
+ ) {
filteredWslList.push(conn);
}
}
@@ -734,9 +761,38 @@ const ChangeConnectionBlockModal = React.memo(
};
return item;
});
+ const connectionsEditItem: SuggestionConnectionItem = {
+ status: "disconnected",
+ icon: "gear",
+ iconColor: "var(--grey-text-color",
+ value: "Edit Connections",
+ label: "Edit Connections",
+ onSelect: () => {
+ util.fireAndForget(async () => {
+ globalStore.set(changeConnModalAtom, false);
+ const path = `${getApi().getConfigDir()}/connections.json`;
+ const blockDef: BlockDef = {
+ meta: {
+ view: "preview",
+ file: path,
+ },
+ };
+ await createBlock(blockDef, false, true);
+ });
+ },
+ };
+ const sortedRemoteItems = remoteItems.sort(
+ (itemA: SuggestionConnectionItem, itemB: SuggestionConnectionItem) => {
+ const connNameA = itemA.value;
+ const connNameB = itemB.value;
+ const valueA = connectionsConfig[connNameA]?.["display:order"] ?? 0;
+ const valueB = connectionsConfig[connNameB]?.["display:order"] ?? 0;
+ return valueA - valueB;
+ }
+ );
const remoteSuggestions: SuggestionConnectionScope = {
headerText: "Remote",
- items: remoteItems,
+ items: [...sortedRemoteItems, connectionsEditItem],
};
let suggestions: Array = [];
diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts
index 74ee256e4..21791b391 100644
--- a/frontend/app/store/global.ts
+++ b/frontend/app/store/global.ts
@@ -246,6 +246,21 @@ function useBlockMetaKeyAtom(blockId: string, key: T):
return useAtomValue(getBlockMetaKeyAtom(blockId, key));
}
+function getConnConfigKeyAtom(connName: string, key: T): Atom {
+ let connCache = getSingleConnAtomCache(connName);
+ const keyAtomName = "#conn-" + key;
+ let keyAtom = connCache.get(keyAtomName);
+ if (keyAtom != null) {
+ return keyAtom;
+ }
+ keyAtom = atom((get) => {
+ let fullConfig = get(atoms.fullConfigAtom);
+ return fullConfig.connections[connName]?.[key];
+ });
+ connCache.set(keyAtomName, keyAtom);
+ return keyAtom;
+}
+
const settingsAtomCache = new Map>();
function getOverrideConfigAtom(blockId: string, key: T): Atom {
@@ -261,6 +276,13 @@ function getOverrideConfigAtom(blockId: string, ke
if (metaKeyVal != null) {
return metaKeyVal;
}
+ const connNameAtom = getBlockMetaKeyAtom(blockId, "connection");
+ const connName = get(connNameAtom);
+ const connConfigKeyAtom = getConnConfigKeyAtom(connName, key as any);
+ const connConfigKeyVal = get(connConfigKeyAtom);
+ if (connConfigKeyVal != null) {
+ return connConfigKeyVal;
+ }
const settingsKeyAtom = getSettingsKeyAtom(key);
const settingsVal = get(settingsKeyAtom);
if (settingsVal != null) {
@@ -322,6 +344,15 @@ function getSingleBlockAtomCache(blockId: string): Map> {
return blockCache;
}
+function getSingleConnAtomCache(connName: string): Map> {
+ let blockCache = blockAtomCache.get(connName);
+ if (blockCache == null) {
+ blockCache = new Map>();
+ blockAtomCache.set(connName, blockCache);
+ }
+ return blockCache;
+}
+
function useBlockAtom(blockId: string, name: string, makeFn: () => Atom): Atom {
const blockCache = getSingleBlockAtomCache(blockId);
let atom = blockCache.get(name);
diff --git a/frontend/app/view/preview/preview.tsx b/frontend/app/view/preview/preview.tsx
index 3cb55316c..77ebd5898 100644
--- a/frontend/app/view/preview/preview.tsx
+++ b/frontend/app/view/preview/preview.tsx
@@ -121,6 +121,7 @@ export class PreviewModel implements ViewModel {
loadableSpecializedView: Atom>;
manageConnection: Atom;
connStatus: Atom;
+ filterOutNowsh?: Atom;
metaFilePath: Atom;
statFilePath: Atom>;
@@ -164,6 +165,7 @@ export class PreviewModel implements ViewModel {
this.manageConnection = atom(true);
this.blockAtom = WOS.getWaveObjectAtom(`block:${blockId}`);
this.markdownShowToc = atom(false);
+ this.filterOutNowsh = atom(true);
this.monacoRef = createRef();
this.viewIcon = atom((get) => {
const blockData = get(this.blockAtom);
diff --git a/frontend/app/view/sysinfo/sysinfo.tsx b/frontend/app/view/sysinfo/sysinfo.tsx
index 787be2ff0..ec2ba93be 100644
--- a/frontend/app/view/sysinfo/sysinfo.tsx
+++ b/frontend/app/view/sysinfo/sysinfo.tsx
@@ -91,7 +91,7 @@ function convertWaveEventToDataItem(event: WaveEvent): DataItem {
return dataItem;
}
-class SysinfoViewModel {
+class SysinfoViewModel implements ViewModel {
viewType: string;
blockAtom: jotai.Atom;
termMode: jotai.Atom;
@@ -109,6 +109,7 @@ class SysinfoViewModel {
metrics: jotai.Atom;
connection: jotai.Atom;
manageConnection: jotai.Atom;
+ filterOutNowsh: jotai.Atom;
connStatus: jotai.Atom;
plotMetaAtom: jotai.PrimitiveAtom