fix: Session auth, sidebar toggle, and dependencies table

- Change session.cookie_samesite from Strict to Lax for Authelia compatibility
- Redesign sidebar toggle with separate collapse/expand buttons
- Add script to create missing ticket_dependencies table
- Add .env.example template
- Add check for missing .env with helpful error message

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-23 21:16:29 -05:00
parent 380b0e1adf
commit 6d03f9c89b
6 changed files with 129 additions and 51 deletions

14
.env.example Normal file
View File

@@ -0,0 +1,14 @@
# Tinker Tickets Environment Configuration
# Copy this file to .env and fill in your values
# Database Configuration
DB_HOST=10.10.10.50
DB_USER=tinkertickets
DB_PASS=your_password_here
DB_NAME=ticketing_system
# Discord Webhook (optional - for notifications)
DISCORD_WEBHOOK_URL=
# Timezone (default: America/New_York)
TIMEZONE=America/New_York

View File

@@ -1692,74 +1692,81 @@ input[type="checkbox"]:checked {
}
/* Collapsible Sidebar */
.dashboard-layout {
position: relative;
}
.sidebar-toggle {
position: absolute;
left: 250px;
top: 1rem;
width: 24px;
height: 48px;
background: var(--bg-secondary);
border: 2px solid var(--terminal-green);
color: var(--terminal-green);
cursor: pointer;
z-index: 100;
display: flex;
align-items: center;
justify-content: center;
transition: left 0.3s ease, background 0.2s ease;
padding: 0;
border-radius: 0 4px 4px 0;
}
.sidebar-toggle:hover {
background: rgba(0, 255, 65, 0.2);
color: var(--terminal-amber);
border-color: var(--terminal-amber);
}
.toggle-arrow {
transition: transform 0.3s ease;
font-size: 0.9rem;
}
.dashboard-sidebar {
position: relative;
transition: width 0.3s ease, opacity 0.3s ease;
transition: width 0.3s ease, min-width 0.3s ease;
overflow: hidden;
}
.sidebar-content {
transition: opacity 0.3s ease;
transition: opacity 0.2s ease;
width: 250px;
}
/* Collapse button inside sidebar */
.sidebar-collapse-btn {
display: block;
width: 100%;
padding: 0.5rem 1rem;
background: var(--bg-secondary);
border: none;
border-bottom: 2px solid var(--terminal-green);
color: var(--terminal-green);
font-family: var(--font-mono);
font-size: 0.85rem;
cursor: pointer;
text-align: left;
transition: background 0.2s ease;
}
.sidebar-collapse-btn:hover {
background: rgba(0, 255, 65, 0.15);
color: var(--terminal-amber);
}
/* Expand button shown when collapsed */
.sidebar-expand-btn {
display: none;
padding: 0.5rem 1rem;
background: var(--bg-secondary);
border: 2px solid var(--terminal-green);
color: var(--terminal-green);
font-family: var(--font-mono);
font-size: 0.85rem;
cursor: pointer;
white-space: nowrap;
transition: background 0.2s ease;
margin-right: 1rem;
flex-shrink: 0;
}
.sidebar-expand-btn:hover {
background: rgba(0, 255, 65, 0.15);
color: var(--terminal-amber);
border-color: var(--terminal-amber);
}
/* Collapsed state */
.dashboard-sidebar.collapsed {
width: 0;
min-width: 0;
}
.dashboard-sidebar.collapsed .sidebar-content {
.dashboard-sidebar.collapsed .sidebar-content,
.dashboard-sidebar.collapsed .sidebar-collapse-btn {
opacity: 0;
pointer-events: none;
}
.dashboard-layout.sidebar-collapsed .sidebar-toggle {
left: 0;
.dashboard-layout.sidebar-collapsed .sidebar-expand-btn {
display: block;
}
.dashboard-layout.sidebar-collapsed .toggle-arrow {
transform: rotate(180deg);
}
/* Hide toggle on mobile */
/* Hide collapse controls on mobile */
@media (max-width: 768px) {
.sidebar-toggle {
display: none;
.sidebar-collapse-btn,
.sidebar-expand-btn {
display: none !important;
}
}

View File

@@ -1,6 +1,9 @@
<?php
// Load environment variables
$envFile = __DIR__ . '/../.env';
if (!file_exists($envFile)) {
die('Configuration error: .env file not found. Copy .env.example to .env and configure your database settings.');
}
$envVars = parse_ini_file($envFile, false, INI_SCANNER_TYPED);
// Strip quotes from values if present (parse_ini_file may include them)

View File

@@ -25,8 +25,10 @@ class AuthMiddleware {
// Configure secure session settings
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1); // Requires HTTPS
ini_set('session.cookie_samesite', 'Strict');
ini_set('session.cookie_samesite', 'Lax'); // Lax allows redirects from Authelia
ini_set('session.use_strict_mode', 1);
ini_set('session.gc_maxlifetime', 18000); // 5 hours
ini_set('session.cookie_lifetime', 0); // Until browser closes
session_start();
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Create ticket_dependencies table if it doesn't exist
* Run once: php scripts/create_dependencies_table.php
*/
require_once dirname(__DIR__) . '/config/config.php';
$conn = new mysqli(
$GLOBALS['config']['DB_HOST'],
$GLOBALS['config']['DB_USER'],
$GLOBALS['config']['DB_PASS'],
$GLOBALS['config']['DB_NAME']
);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error . "\n");
}
echo "Connected to database successfully.\n";
// Check if table exists
$tableCheck = $conn->query("SHOW TABLES LIKE 'ticket_dependencies'");
if ($tableCheck->num_rows > 0) {
echo "Table 'ticket_dependencies' already exists.\n";
$conn->close();
exit(0);
}
// Create the table
$sql = "CREATE TABLE ticket_dependencies (
dependency_id INT AUTO_INCREMENT PRIMARY KEY,
ticket_id VARCHAR(9) NOT NULL,
depends_on_id VARCHAR(9) NOT NULL,
dependency_type ENUM('blocks', 'blocked_by', 'relates_to', 'duplicates') NOT NULL DEFAULT 'blocks',
created_by INT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (ticket_id) REFERENCES tickets(ticket_id) ON DELETE CASCADE,
FOREIGN KEY (depends_on_id) REFERENCES tickets(ticket_id) ON DELETE CASCADE,
FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE SET NULL,
UNIQUE KEY unique_dependency (ticket_id, depends_on_id, dependency_type),
INDEX idx_ticket_id (ticket_id),
INDEX idx_depends_on_id (depends_on_id),
INDEX idx_dependency_type (dependency_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
if ($conn->query($sql) === TRUE) {
echo "Table 'ticket_dependencies' created successfully.\n";
} else {
echo "Error creating table: " . $conn->error . "\n";
}
$conn->close();

View File

@@ -125,12 +125,9 @@
<!-- Dashboard Layout with Sidebar -->
<div class="dashboard-layout" id="dashboardLayout">
<!-- Sidebar Toggle Button (outside sidebar for always-visible) -->
<button class="sidebar-toggle" id="sidebarToggle" onclick="toggleSidebar()" title="Toggle Sidebar">
<span class="toggle-arrow" id="toggleArrow">◀</span>
</button>
<!-- Left Sidebar with Filters -->
<aside class="dashboard-sidebar" id="dashboardSidebar">
<button class="sidebar-collapse-btn" onclick="toggleSidebar()" title="Collapse Sidebar">◀ Hide</button>
<div class="sidebar-content">
<div class="ascii-frame-inner">
<div class="ascii-subsection-header">Filters</div>
@@ -192,6 +189,8 @@
</div>
</div>
</aside>
<!-- Expand button shown when sidebar is collapsed -->
<button class="sidebar-expand-btn" id="sidebarExpandBtn" onclick="toggleSidebar()" title="Show Filters">▶ Filters</button>
<!-- Main Content Area -->
<main class="dashboard-main">