Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b451b13
feat: comprehensive mobile responsiveness improvements
michelroegl-brunner Oct 8, 2025
f4fded4
fix: improve mobile terminal input handling for SSH processes
michelroegl-brunner Oct 8, 2025
82638b2
debug: add comprehensive debugging for mobile terminal input
michelroegl-brunner Oct 8, 2025
abb000a
debug: add comprehensive server-side debugging for mobile input
michelroegl-brunner Oct 8, 2025
cefdb30
debug: add WebSocket message routing debugging
michelroegl-brunner Oct 8, 2025
f75f763
debug: add comprehensive client-side debugging for mobile input
michelroegl-brunner Oct 8, 2025
e08c652
debug: add WebSocket connection tracking and message debugging
michelroegl-brunner Oct 8, 2025
f685f46
fix: correct WebSocket message format for keyboard input
michelroegl-brunner Oct 8, 2025
592687e
debug: add WebSocket connection details for mobile vs keyboard input
michelroegl-brunner Oct 8, 2025
9ed298a
fix: correct WebSocket message format to use 'input' field
michelroegl-brunner Oct 8, 2025
762f262
feat: add left/right arrow buttons to mobile terminal input
michelroegl-brunner Oct 8, 2025
d1884ff
feat: add spacebar button and clean up mobile terminal controls
michelroegl-brunner Oct 8, 2025
77b6724
feat: add backspace button to mobile terminal controls
michelroegl-brunner Oct 8, 2025
9a378e5
feat: improve mobile terminal scaling and responsiveness
michelroegl-brunner Oct 8, 2025
5e7168a
fix: improve ANSI escape sequence handling for whiptail dialogs
michelroegl-brunner Oct 8, 2025
04b73b2
debug: add whiptail/dialog detection and logging
michelroegl-brunner Oct 8, 2025
27d569e
fix: force screen clear on cursor positioning to prevent whiptail dup…
michelroegl-brunner Oct 8, 2025
12af436
debug: add comprehensive output debugging and try terminal.clear()
michelroegl-brunner Oct 8, 2025
986c5ec
debug: add whiptail session detection and enhanced debugging
michelroegl-brunner Oct 8, 2025
09436ea
feat: improve whiptail centering on mobile devices
michelroegl-brunner Oct 8, 2025
811fc4e
feat: improve whiptail horizontal centering on mobile
michelroegl-brunner Oct 8, 2025
1db1c0f
fix: resolve text wrapping and overflow issues in mobile terminal
michelroegl-brunner Oct 8, 2025
32dc1b1
fix: try auto-fit approach to resolve mobile terminal text wrapping
michelroegl-brunner Oct 8, 2025
b5691d2
fix: improve mobile terminal centering with specific dimensions
michelroegl-brunner Oct 8, 2025
df7c0ed
feat: implement virtual terminal overflow approach for mobile whiptail
michelroegl-brunner Oct 8, 2025
ba7e8c7
revert: simplify mobile terminal approach and reduce font size
michelroegl-brunner Oct 8, 2025
d390f4f
feat: reduce mobile terminal font size and dimensions for better fit
michelroegl-brunner Oct 8, 2025
ac8fcc7
feat: increase mobile font size and fix whiptail duplication
michelroegl-brunner Oct 8, 2025
2915867
fix: implement more aggressive terminal clearing for whiptail
michelroegl-brunner Oct 8, 2025
bf67df5
fix: implement terminal reset approach for whiptail duplication
michelroegl-brunner Oct 8, 2025
6830b3a
cleanup: remove all debug logging from terminal component
michelroegl-brunner Oct 8, 2025
606ef4c
feat: make InstalledScriptsTab mobile-friendly with responsive layout
michelroegl-brunner Oct 8, 2025
ba8c912
fix: resolve React hooks dependency warnings in Terminal component
michelroegl-brunner Oct 8, 2025
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
8 changes: 4 additions & 4 deletions src/app/_components/CategorySidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export function CategorySidebar({

return (
<div className={`bg-card rounded-lg shadow-md border border-border transition-all duration-300 ${
isCollapsed ? 'w-16' : 'w-80'
isCollapsed ? 'w-16' : 'w-full lg:w-80'
}`}>
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-border">
Expand Down Expand Up @@ -292,7 +292,7 @@ export function CategorySidebar({

{/* Collapsed state - show only icons with counters and tooltips */}
{isCollapsed && (
<div className="p-2 flex flex-col space-y-2">
<div className="p-2 flex flex-row lg:flex-col space-x-2 lg:space-x-0 lg:space-y-2 overflow-x-auto lg:overflow-x-visible">
{/* "All Categories" option */}
<div className="group relative">
<button
Expand All @@ -317,7 +317,7 @@ export function CategorySidebar({
</button>

{/* Tooltip */}
<div className="absolute left-full ml-2 top-1/2 transform -translate-y-1/2 bg-gray-900 text-white text-sm px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-50">
<div className="absolute left-full ml-2 top-1/2 transform -translate-y-1/2 bg-gray-900 text-white text-sm px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-50 hidden lg:block">
All Categories ({totalScripts})
</div>
</div>
Expand Down Expand Up @@ -350,7 +350,7 @@ export function CategorySidebar({
</button>

{/* Tooltip */}
<div className="absolute left-full ml-2 top-1/2 transform -translate-y-1/2 bg-gray-900 text-white text-sm px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-50">
<div className="absolute left-full ml-2 top-1/2 transform -translate-y-1/2 bg-gray-900 text-white text-sm px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-50 hidden lg:block">
{category} ({count})
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/DiffViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function DiffViewer({ scriptSlug, filePath, isOpen, onClose }: DiffViewer
className="fixed inset-0 backdrop-blur-sm bg-black/50 flex items-center justify-center p-4 z-50"
onClick={handleBackdropClick}
>
<div className="bg-card rounded-lg shadow-xl max-w-6xl w-full max-h-[90vh] overflow-hidden border border-border">
<div className="bg-card rounded-lg shadow-xl max-w-6xl w-full max-h-[90vh] overflow-hidden border border-border mx-4 sm:mx-0">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-border">
<div>
Expand Down
6 changes: 3 additions & 3 deletions src/app/_components/DownloadedScriptsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,9 @@ export function DownloadedScriptsTab() {
</div>
</div>

<div className="flex gap-6">
<div className="flex flex-col lg:flex-row gap-4 lg:gap-6">
{/* Category Sidebar */}
<div className="flex-shrink-0">
<div className="flex-shrink-0 order-2 lg:order-1">
<CategorySidebar
categories={categories}
categoryCounts={categoryCounts}
Expand All @@ -333,7 +333,7 @@ export function DownloadedScriptsTab() {
</div>

{/* Main Content */}
<div className="flex-1 min-w-0" ref={gridRef}>
<div className="flex-1 min-w-0 order-1 lg:order-2" ref={gridRef}>
{/* Enhanced Filter Bar */}
<FilterBar
filters={filters}
Expand Down
4 changes: 2 additions & 2 deletions src/app/_components/ExecutionModeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ export function ExecutionModeModal({ isOpen, onClose, onExecute, scriptName }: E
if (!isOpen) return null;

return (
<div className="fixed inset-0 backdrop-blur-sm bg-black/50 flex items-center justify-center z-50">
<div className="bg-card rounded-lg shadow-xl max-w-md w-full mx-4 border border-border">
<div className="fixed inset-0 backdrop-blur-sm bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-card rounded-lg shadow-xl max-w-md w-full border border-border">
{/* Header */}
<div className="flex items-center justify-between p-6 border-b border-border">
<h2 className="text-xl font-bold text-foreground">Execution Mode</h2>
Expand Down
217 changes: 130 additions & 87 deletions src/app/_components/FilterBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import React, { useState } from "react";
import { Button } from "./ui/button";
import { Package, Monitor, Wrench, Server, FileText, Calendar } from "lucide-react";
import { Package, Monitor, Wrench, Server, FileText, Calendar, RefreshCw, Filter } from "lucide-react";

export interface FilterState {
searchQuery: string;
Expand Down Expand Up @@ -35,6 +35,7 @@ export function FilterBar({
updatableCount = 0,
}: FilterBarProps) {
const [isTypeDropdownOpen, setIsTypeDropdownOpen] = useState(false);
const [isSortDropdownOpen, setIsSortDropdownOpen] = useState(false);

const updateFilters = (updates: Partial<FilterState>) => {
onFiltersChange({ ...filters, ...updates });
Expand Down Expand Up @@ -76,10 +77,10 @@ export function FilterBar({
};

return (
<div className="mb-6 rounded-lg border border-border bg-card p-6 shadow-sm">
<div className="mb-6 rounded-lg border border-border bg-card p-4 sm:p-6 shadow-sm">
{/* Search Bar */}
<div className="mb-4">
<div className="relative max-w-md">
<div className="relative max-w-md w-full">
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
<svg
className="h-5 w-5 text-muted-foreground"
Expand Down Expand Up @@ -128,7 +129,7 @@ export function FilterBar({
</div>

{/* Filter Buttons */}
<div className="mb-4 flex flex-wrap gap-3">
<div className="mb-4 flex flex-col sm:flex-row flex-wrap gap-2 sm:gap-3">
{/* Updateable Filter */}
<Button
onClick={() => {
Expand All @@ -142,29 +143,31 @@ export function FilterBar({
}}
variant="outline"
size="default"
className={`${
filters.showUpdatable === null
? "bg-muted text-muted-foreground hover:bg-accent"
: filters.showUpdatable === true
? "border border-green-500/20 bg-green-500/10 text-green-400"
: "border border-destructive/20 bg-destructive/10 text-destructive"
}`}
className={`w-full sm:w-auto flex items-center justify-center space-x-2 ${
filters.showUpdatable === null
? "bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground"
: filters.showUpdatable === true
? "border border-green-500/20 bg-green-500/10 text-green-400"
: "border border-destructive/20 bg-destructive/10 text-destructive"
}`}
>
{getUpdatableButtonText()}
<RefreshCw className="h-4 w-4" />
<span>{getUpdatableButtonText()}</span>
</Button>

{/* Type Dropdown */}
<div className="relative">
<div className="relative w-full sm:w-auto">
<Button
onClick={() => setIsTypeDropdownOpen(!isTypeDropdownOpen)}
variant="outline"
size="default"
className={`flex items-center space-x-2 ${
className={`w-full flex items-center justify-center space-x-2 ${
filters.selectedTypes.length === 0
? "bg-muted text-muted-foreground hover:bg-accent"
? "bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground"
: "border border-primary/20 bg-primary/10 text-primary"
}`}
>
<Filter className="h-4 w-4" />
<span>{getTypeButtonText()}</span>
<svg
className={`h-4 w-4 transition-transform ${isTypeDropdownOpen ? "rotate-180" : ""}`}
Expand Down Expand Up @@ -237,85 +240,122 @@ export function FilterBar({
)}
</div>

{/* Sort Options */}
<div className="flex items-center space-x-2">
{/* Sort By Dropdown */}
<div className="relative inline-flex items-center">
<select
value={filters.sortBy}
onChange={(e) =>
updateFilters({ sortBy: e.target.value as "name" | "created" })
}
className="rounded-lg border border-input bg-background pl-9 pr-3 py-2 text-sm text-foreground focus:ring-2 focus:ring-primary focus:outline-none appearance-none"
>
<option value="name">By Name</option>
<option value="created">By Created Date</option>
</select>
<div className="absolute left-2 pointer-events-none">
{filters.sortBy === "name" ? (
<FileText className="h-4 w-4 text-muted-foreground" />
) : (
<Calendar className="h-4 w-4 text-muted-foreground" />
)}
</div>
</div>

{/* Sort Order Button */}
{/* Sort By Dropdown */}
<div className="relative w-full sm:w-auto">
<Button
onClick={() =>
updateFilters({
sortOrder: filters.sortOrder === "asc" ? "desc" : "asc",
})
}
onClick={() => setIsSortDropdownOpen(!isSortDropdownOpen)}
variant="outline"
size="default"
className="flex items-center space-x-1 bg-muted text-muted-foreground hover:bg-accent"
className="w-full sm:w-auto flex items-center justify-center space-x-2 bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground"
>
{filters.sortOrder === "asc" ? (
<>
<svg
className="h-4 w-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M7 11l5-5m0 0l5 5m-5-5v12"
/>
</svg>
<span>
{filters.sortBy === "created" ? "Oldest First" : "A-Z"}
</span>
</>
{filters.sortBy === "name" ? (
<FileText className="h-4 w-4" />
) : (
<>
<svg
className="h-4 w-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M17 13l-5 5m0 0l-5-5m5 5V6"
/>
</svg>
<span>
{filters.sortBy === "created" ? "Newest First" : "Z-A"}
</span>
</>
<Calendar className="h-4 w-4" />
)}
<span>{filters.sortBy === "name" ? "By Name" : "By Created Date"}</span>
<svg
className={`h-4 w-4 transition-transform ${isSortDropdownOpen ? "rotate-180" : ""}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 9l-7 7-7-7"
/>
</svg>
</Button>

{isSortDropdownOpen && (
<div className="absolute top-full left-0 z-10 mt-1 w-full sm:w-48 rounded-lg border border-border bg-card shadow-lg">
<div className="p-2">
<button
onClick={() => {
updateFilters({ sortBy: "name" });
setIsSortDropdownOpen(false);
}}
className={`w-full flex items-center space-x-3 rounded-md px-3 py-2 text-left hover:bg-accent ${
filters.sortBy === "name" ? "bg-primary/10 text-primary" : "text-muted-foreground"
}`}
>
<FileText className="h-4 w-4" />
<span className="text-sm">By Name</span>
</button>
<button
onClick={() => {
updateFilters({ sortBy: "created" });
setIsSortDropdownOpen(false);
}}
className={`w-full flex items-center space-x-3 rounded-md px-3 py-2 text-left hover:bg-accent ${
filters.sortBy === "created" ? "bg-primary/10 text-primary" : "text-muted-foreground"
}`}
>
<Calendar className="h-4 w-4" />
<span className="text-sm">By Created Date</span>
</button>
</div>
</div>
)}
</div>

{/* Sort Order Button */}
<Button
onClick={() =>
updateFilters({
sortOrder: filters.sortOrder === "asc" ? "desc" : "asc",
})
}
variant="outline"
size="default"
className="w-full sm:w-auto flex items-center justify-center space-x-1 bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground"
>
{filters.sortOrder === "asc" ? (
<>
<svg
className="h-4 w-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M7 11l5-5m0 0l5 5m-5-5v12"
/>
</svg>
<span>
{filters.sortBy === "created" ? "Oldest First" : "A-Z"}
</span>
</>
) : (
<>
<svg
className="h-4 w-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M17 13l-5 5m0 0l-5-5m5 5V6"
/>
</svg>
<span>
{filters.sortBy === "created" ? "Newest First" : "Z-A"}
</span>
</>
)}
</Button>
</div>

{/* Filter Summary and Clear All */}
<div className="flex items-center justify-between">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2">
<div className="text-sm text-muted-foreground">
{filteredCount === totalScripts ? (
<span>Showing all {totalScripts} scripts</span>
Expand All @@ -336,7 +376,7 @@ export function FilterBar({
onClick={clearAllFilters}
variant="ghost"
size="sm"
className="flex items-center space-x-1 text-red-600 hover:bg-red-50 hover:text-red-800"
className="flex items-center space-x-1 text-red-600 hover:bg-red-50 hover:text-red-800 w-full sm:w-auto justify-center sm:justify-start"
>
<svg
className="h-4 w-4"
Expand All @@ -356,11 +396,14 @@ export function FilterBar({
)}
</div>

{/* Click outside to close dropdown */}
{isTypeDropdownOpen && (
{/* Click outside to close dropdowns */}
{(isTypeDropdownOpen || isSortDropdownOpen) && (
<div
className="fixed inset-0 z-0"
onClick={() => setIsTypeDropdownOpen(false)}
onClick={() => {
setIsTypeDropdownOpen(false);
setIsSortDropdownOpen(false);
}}
/>
)}
</div>
Expand Down
Loading