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:
14
.env.example
Normal file
14
.env.example
Normal 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
|
||||||
@@ -1692,74 +1692,81 @@ input[type="checkbox"]:checked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Collapsible Sidebar */
|
/* 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 {
|
.dashboard-sidebar {
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: width 0.3s ease, opacity 0.3s ease;
|
transition: width 0.3s ease, min-width 0.3s ease;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-content {
|
.sidebar-content {
|
||||||
transition: opacity 0.3s ease;
|
transition: opacity 0.2s ease;
|
||||||
width: 250px;
|
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 */
|
/* Collapsed state */
|
||||||
.dashboard-sidebar.collapsed {
|
.dashboard-sidebar.collapsed {
|
||||||
width: 0;
|
width: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-sidebar.collapsed .sidebar-content {
|
.dashboard-sidebar.collapsed .sidebar-content,
|
||||||
|
.dashboard-sidebar.collapsed .sidebar-collapse-btn {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-layout.sidebar-collapsed .sidebar-toggle {
|
.dashboard-layout.sidebar-collapsed .sidebar-expand-btn {
|
||||||
left: 0;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-layout.sidebar-collapsed .toggle-arrow {
|
/* Hide collapse controls on mobile */
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide toggle on mobile */
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.sidebar-toggle {
|
.sidebar-collapse-btn,
|
||||||
display: none;
|
.sidebar-expand-btn {
|
||||||
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
// Load environment variables
|
// Load environment variables
|
||||||
$envFile = __DIR__ . '/../.env';
|
$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);
|
$envVars = parse_ini_file($envFile, false, INI_SCANNER_TYPED);
|
||||||
|
|
||||||
// Strip quotes from values if present (parse_ini_file may include them)
|
// Strip quotes from values if present (parse_ini_file may include them)
|
||||||
|
|||||||
@@ -25,8 +25,10 @@ class AuthMiddleware {
|
|||||||
// Configure secure session settings
|
// Configure secure session settings
|
||||||
ini_set('session.cookie_httponly', 1);
|
ini_set('session.cookie_httponly', 1);
|
||||||
ini_set('session.cookie_secure', 1); // Requires HTTPS
|
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.use_strict_mode', 1);
|
||||||
|
ini_set('session.gc_maxlifetime', 18000); // 5 hours
|
||||||
|
ini_set('session.cookie_lifetime', 0); // Until browser closes
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
}
|
}
|
||||||
|
|||||||
53
scripts/create_dependencies_table.php
Normal file
53
scripts/create_dependencies_table.php
Normal 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();
|
||||||
@@ -125,12 +125,9 @@
|
|||||||
|
|
||||||
<!-- Dashboard Layout with Sidebar -->
|
<!-- Dashboard Layout with Sidebar -->
|
||||||
<div class="dashboard-layout" id="dashboardLayout">
|
<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 -->
|
<!-- Left Sidebar with Filters -->
|
||||||
<aside class="dashboard-sidebar" id="dashboardSidebar">
|
<aside class="dashboard-sidebar" id="dashboardSidebar">
|
||||||
|
<button class="sidebar-collapse-btn" onclick="toggleSidebar()" title="Collapse Sidebar">◀ Hide</button>
|
||||||
<div class="sidebar-content">
|
<div class="sidebar-content">
|
||||||
<div class="ascii-frame-inner">
|
<div class="ascii-frame-inner">
|
||||||
<div class="ascii-subsection-header">Filters</div>
|
<div class="ascii-subsection-header">Filters</div>
|
||||||
@@ -192,6 +189,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</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 Content Area -->
|
||||||
<main class="dashboard-main">
|
<main class="dashboard-main">
|
||||||
|
|||||||
Reference in New Issue
Block a user