mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-29 10:21:34 +00:00
fix: overlapping hosts when using click to expand
This commit is contained in:
@@ -1016,16 +1016,6 @@ jobs:
|
|||||||
|
|
||||||
security find-identity -v -p codesigning $KEYCHAIN_PATH
|
security find-identity -v -p codesigning $KEYCHAIN_PATH
|
||||||
|
|
||||||
- name: Build macOS App Store Package
|
|
||||||
if: steps.check_certs.outputs.has_certs == 'true'
|
|
||||||
env:
|
|
||||||
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
NODE_OPTIONS: --max-old-space-size=4096
|
|
||||||
run: |
|
|
||||||
BUILD_VERSION="${{ github.run_number }}"
|
|
||||||
npm run build && npx electron-builder --mac mas --universal --config.buildVersion="$BUILD_VERSION"
|
|
||||||
|
|
||||||
- name: Check for App Store Connect API credentials
|
- name: Check for App Store Connect API credentials
|
||||||
id: check_asc_creds
|
id: check_asc_creds
|
||||||
run: |
|
run: |
|
||||||
@@ -1044,24 +1034,16 @@ jobs:
|
|||||||
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||||
run: gem install fastlane -N
|
run: gem install fastlane -N
|
||||||
|
|
||||||
- name: Upload and submit to Mac App Store
|
- name: Write App Store Connect API key
|
||||||
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||||
env:
|
env:
|
||||||
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
||||||
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
|
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
|
||||||
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
|
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
|
||||||
run: |
|
run: |
|
||||||
PKG_FILE=$(find release -name "termix_macos_universal_mas.pkg" -type f | head -n 1)
|
# Write API key JSON that Fastlane expects; the PEM's newlines
|
||||||
if [ -z "$PKG_FILE" ]; then
|
# must be preserved as literal \n escapes, not stripped, or
|
||||||
echo "PKG file not found in release/; aborting."
|
# spaceship fails to parse the key (invalid curve name).
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
VERSION=$(node -p "require('./package.json').version")
|
|
||||||
|
|
||||||
# Write API key JSON that Fastlane deliver expects; the PEM's
|
|
||||||
# newlines must be preserved as literal \n escapes, not stripped,
|
|
||||||
# or spaceship fails to parse the key (invalid curve name).
|
|
||||||
mkdir -p /tmp/asc_keys
|
mkdir -p /tmp/asc_keys
|
||||||
KEY_P8_PATH="/tmp/asc_keys/AuthKey_${APPLE_KEY_ID}.p8"
|
KEY_P8_PATH="/tmp/asc_keys/AuthKey_${APPLE_KEY_ID}.p8"
|
||||||
API_KEY_JSON="/tmp/asc_keys/api_key.json"
|
API_KEY_JSON="/tmp/asc_keys/api_key.json"
|
||||||
@@ -1080,6 +1062,65 @@ jobs:
|
|||||||
}, null, 2) + "\n");
|
}, null, 2) + "\n");
|
||||||
' > "$API_KEY_JSON"
|
' > "$API_KEY_JSON"
|
||||||
|
|
||||||
|
- name: Resolve next build number from App Store Connect
|
||||||
|
id: build_number
|
||||||
|
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||||
|
run: |
|
||||||
|
APP_VERSION=$(node -p "require('./package.json').version")
|
||||||
|
OUT_FILE="$RUNNER_TEMP/latest_build_number.txt"
|
||||||
|
LANE_DIR="$RUNNER_TEMP/asc_lane/fastlane"
|
||||||
|
mkdir -p "$LANE_DIR"
|
||||||
|
|
||||||
|
cat > "$LANE_DIR/Fastfile" <<EOF
|
||||||
|
default_platform(:mac)
|
||||||
|
|
||||||
|
lane :fetch_build_number do
|
||||||
|
number = app_store_build_number(
|
||||||
|
live: false,
|
||||||
|
api_key_path: "/tmp/asc_keys/api_key.json",
|
||||||
|
app_identifier: "com.karmaa.termix",
|
||||||
|
version: "$APP_VERSION",
|
||||||
|
initial_build_number: 0,
|
||||||
|
)
|
||||||
|
File.write("$OUT_FILE", number.to_s)
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
|
||||||
|
(cd "$RUNNER_TEMP/asc_lane" && fastlane fetch_build_number) 2>&1 || true
|
||||||
|
|
||||||
|
LATEST=""
|
||||||
|
if [ -f "$OUT_FILE" ]; then
|
||||||
|
LATEST=$(cat "$OUT_FILE" | tr -d '[:space:]')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ "$LATEST" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "Could not resolve latest build number from App Store Connect; falling back to run number."
|
||||||
|
LATEST="${{ github.run_number }}"
|
||||||
|
fi
|
||||||
|
echo "build_version=$((LATEST + 1))" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Build macOS App Store Package
|
||||||
|
if: steps.check_certs.outputs.has_certs == 'true'
|
||||||
|
env:
|
||||||
|
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
NODE_OPTIONS: --max-old-space-size=4096
|
||||||
|
run: |
|
||||||
|
BUILD_VERSION="${{ steps.build_number.outputs.build_version || github.run_number }}"
|
||||||
|
npm run build && npx electron-builder --mac mas --universal --config.buildVersion="$BUILD_VERSION"
|
||||||
|
|
||||||
|
- name: Upload and submit to Mac App Store
|
||||||
|
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||||
|
run: |
|
||||||
|
PKG_FILE=$(find release -name "termix_macos_universal_mas.pkg" -type f | head -n 1)
|
||||||
|
if [ -z "$PKG_FILE" ]; then
|
||||||
|
echo "PKG file not found in release/; aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION=$(node -p "require('./package.json').version")
|
||||||
|
API_KEY_JSON="/tmp/asc_keys/api_key.json"
|
||||||
|
|
||||||
fastlane deliver \
|
fastlane deliver \
|
||||||
--pkg "$PKG_FILE" \
|
--pkg "$PKG_FILE" \
|
||||||
--api_key_path "$API_KEY_JSON" \
|
--api_key_path "$API_KEY_JSON" \
|
||||||
|
|||||||
@@ -1813,6 +1813,34 @@ export function SidebarTree({
|
|||||||
mode: "create" | "edit";
|
mode: "create" | "edit";
|
||||||
folder?: HostFolder;
|
folder?: HostFolder;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
const [compactHostView, setCompactHostView] = useState(
|
||||||
|
() => localStorage.getItem("compactHostView") === "true",
|
||||||
|
);
|
||||||
|
const [trayOnClick, setTrayOnClick] = useState(
|
||||||
|
() => localStorage.getItem("hostTrayOnClick") === "true",
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = () =>
|
||||||
|
setCompactHostView(localStorage.getItem("compactHostView") === "true");
|
||||||
|
window.addEventListener("storage", handler);
|
||||||
|
window.addEventListener("compactHostViewChanged", handler);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("storage", handler);
|
||||||
|
window.removeEventListener("compactHostViewChanged", handler);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = () =>
|
||||||
|
setTrayOnClick(localStorage.getItem("hostTrayOnClick") === "true");
|
||||||
|
window.addEventListener("storage", handler);
|
||||||
|
window.addEventListener("hostTrayOnClickChanged", handler);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("storage", handler);
|
||||||
|
window.removeEventListener("hostTrayOnClickChanged", handler);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
function handleDragHostStart(hostId: string) {
|
function handleDragHostStart(hostId: string) {
|
||||||
// When the dragged host is part of an active selection, move the whole set.
|
// When the dragged host is part of an active selection, move the whole set.
|
||||||
@@ -2051,6 +2079,10 @@ export function SidebarTree({
|
|||||||
const visibleRows = collectVisibleRows(children, query, openFolders);
|
const visibleRows = collectVisibleRows(children, query, openFolders);
|
||||||
const parentRef = useRef<HTMLDivElement>(null);
|
const parentRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const isTouchOnly =
|
||||||
|
typeof window !== "undefined" && window.matchMedia("(hover: none)").matches;
|
||||||
|
const clickTrayActive = trayOnClick || isTouchOnly;
|
||||||
|
|
||||||
const virtualizer = useVirtualizer({
|
const virtualizer = useVirtualizer({
|
||||||
count: visibleRows.length,
|
count: visibleRows.length,
|
||||||
getScrollElement: () => parentRef.current,
|
getScrollElement: () => parentRef.current,
|
||||||
@@ -2058,9 +2090,15 @@ export function SidebarTree({
|
|||||||
const row = visibleRows[index];
|
const row = visibleRows[index];
|
||||||
if (!row) return 36;
|
if (!row) return 36;
|
||||||
if (isFolder(row.item)) return 36;
|
if (isFolder(row.item)) return 36;
|
||||||
// Expanded action tray is taller than a single host row.
|
const isOpen = openTrayHostId === row.item.id;
|
||||||
if (openTrayHostId === row.item.id) return 88;
|
if (compactHostView) {
|
||||||
return 40;
|
// Compact rows are a single line; the tray adds a second wrapped row.
|
||||||
|
return isOpen ? 88 : 32;
|
||||||
|
}
|
||||||
|
// Default rows show name + address (+ optional tags), taller to start with.
|
||||||
|
// Click-tray mode also keeps the connection buttons visible even when closed.
|
||||||
|
const base = clickTrayActive ? 76 : 56;
|
||||||
|
return isOpen ? base + 96 : base;
|
||||||
},
|
},
|
||||||
overscan: 12,
|
overscan: 12,
|
||||||
getItemKey: (index) => {
|
getItemKey: (index) => {
|
||||||
@@ -2072,10 +2110,22 @@ export function SidebarTree({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remeasure when tray open state or tree shape changes (variable row heights).
|
// Remeasure when the tree shape changes (rows added/removed/reordered), so
|
||||||
|
// stale cached sizes from before don't leak onto different rows. Tray
|
||||||
|
// open/close is intentionally excluded — `measureElement`'s ResizeObserver
|
||||||
|
// already tracks that live via the CSS transition, and force-resetting the
|
||||||
|
// cache here would snap rows back to the rough estimate mid-animation and
|
||||||
|
// cause visible jitter.
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
virtualizer.measure();
|
virtualizer.measure();
|
||||||
}, [virtualizer, openTrayHostId, openFolders, query, visibleRows.length]);
|
}, [
|
||||||
|
virtualizer,
|
||||||
|
openFolders,
|
||||||
|
query,
|
||||||
|
visibleRows.length,
|
||||||
|
compactHostView,
|
||||||
|
trayOnClick,
|
||||||
|
]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user