Added site index file and created_at

This commit is contained in:
2026-04-06 18:01:37 +02:00
parent 3f1deae70e
commit 38fcdbf391
9 changed files with 59 additions and 14 deletions
+3
View File
@@ -110,6 +110,9 @@ func validateIncomingSite(site *models.Site) error {
if site.NotFoundFile == "" { if site.NotFoundFile == "" {
site.NotFoundFile = "404.html" site.NotFoundFile = "404.html"
} }
if site.IndexFile == "" {
site.IndexFile = "index.html"
}
if site.ForwardRules == nil { if site.ForwardRules == nil {
site.ForwardRules = []models.ForwardRule{} site.ForwardRules = []models.ForwardRule{}
} }
+3 -3
View File
@@ -62,7 +62,7 @@ func NewStaticHandler(storagePath string, siteRepo repository.SiteRepository) fi
} }
if urlPath == "/" || urlPath == "." { if urlPath == "/" || urlPath == "." {
urlPath = "/index.html" urlPath = "/" + site.IndexFile
} }
basePath := filepath.Join(storagePath, site.ID) basePath := filepath.Join(storagePath, site.ID)
@@ -71,7 +71,7 @@ func NewStaticHandler(storagePath string, siteRepo repository.SiteRepository) fi
info, err := os.Stat(filePath) info, err := os.Stat(filePath)
if err == nil { if err == nil {
if info.IsDir() { if info.IsDir() {
indexPath := filepath.Join(filePath, "index.html") indexPath := filepath.Join(filePath, site.IndexFile)
if _, err := os.Stat(indexPath); err == nil { if _, err := os.Stat(indexPath); err == nil {
return c.SendFile(indexPath) return c.SendFile(indexPath)
} }
@@ -81,7 +81,7 @@ func NewStaticHandler(storagePath string, siteRepo repository.SiteRepository) fi
} }
if site.Spa { if site.Spa {
indexPath := filepath.Join(basePath, "index.html") indexPath := filepath.Join(basePath, site.IndexFile)
if _, err := os.Stat(indexPath); err == nil { if _, err := os.Stat(indexPath); err == nil {
return c.SendFile(indexPath) return c.SendFile(indexPath)
} }
+3
View File
@@ -33,6 +33,9 @@ type Site struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Spa bool `json:"spa"` Spa bool `json:"spa"`
NotFoundFile string `json:"not_found_file"` NotFoundFile string `json:"not_found_file"`
IndexFile string `json:"index_file"`
TrailingSlash *bool `json:"trailing_slash"`
CreatedAt string `json:"created_at"`
ForwardRules []ForwardRule `json:"forward_rules"` ForwardRules []ForwardRule `json:"forward_rules"`
CustomHeaders []CustomHeaders `json:"custom_headers"` CustomHeaders []CustomHeaders `json:"custom_headers"`
} }
+4 -1
View File
@@ -18,7 +18,10 @@ CREATE TABLE IF NOT EXISTS sites (
deploy_token TEXT NOT NULL, deploy_token TEXT NOT NULL,
enabled INTEGER NOT NULL DEFAULT 1, enabled INTEGER NOT NULL DEFAULT 1,
spa INTEGER NOT NULL DEFAULT 0, spa INTEGER NOT NULL DEFAULT 0,
not_found_file TEXT NOT NULL DEFAULT '404.html' not_found_file TEXT NOT NULL DEFAULT '404.html',
index_file TEXT NOT NULL DEFAULT 'index.html',
trailing_slash INTEGER DEFAULT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
); );
CREATE TABLE IF NOT EXISTS forward_rules ( CREATE TABLE IF NOT EXISTS forward_rules (
+10 -8
View File
@@ -25,7 +25,7 @@ var _ repository.SiteRepository = (*SQLiteSiteRepository)(nil)
func (r *SQLiteSiteRepository) GetSite(id string) (*models.Site, error) { func (r *SQLiteSiteRepository) GetSite(id string) (*models.Site, error) {
row := r.db.QueryRow(` row := r.db.QueryRow(`
SELECT id, name, git_server, owner, repository, branch, domain, deploy_token, spa, enabled, not_found_file SELECT id, name, git_server, owner, repository, branch, domain, deploy_token, spa, enabled, not_found_file, index_file, trailing_slash, created_at
FROM sites WHERE id = ?`, id) FROM sites WHERE id = ?`, id)
s, err := scanSite(row) s, err := scanSite(row)
@@ -41,7 +41,7 @@ func (r *SQLiteSiteRepository) GetSite(id string) (*models.Site, error) {
func (r *SQLiteSiteRepository) GetSiteByDomain(domain string) (*models.Site, error) { func (r *SQLiteSiteRepository) GetSiteByDomain(domain string) (*models.Site, error) {
row := r.db.QueryRow(` row := r.db.QueryRow(`
SELECT id, name, git_server, owner, repository, branch, domain, deploy_token, spa, enabled, not_found_file SELECT id, name, git_server, owner, repository, branch, domain, deploy_token, spa, enabled, not_found_file, index_file, trailing_slash, created_at
FROM sites WHERE domain = ?`, domain) FROM sites WHERE domain = ?`, domain)
s, err := scanSite(row) s, err := scanSite(row)
@@ -60,7 +60,7 @@ func (r *SQLiteSiteRepository) GetSiteByDomain(domain string) (*models.Site, err
func (r *SQLiteSiteRepository) ListSites() ([]models.Site, error) { func (r *SQLiteSiteRepository) ListSites() ([]models.Site, error) {
rows, err := r.db.Query(` rows, err := r.db.Query(`
SELECT id, name, git_server, owner, repository, branch, domain, deploy_token, spa, enabled, not_found_file SELECT id, name, git_server, owner, repository, branch, domain, deploy_token, spa, enabled, not_found_file, index_file, trailing_slash, created_at
FROM sites`) FROM sites`)
if err != nil { if err != nil {
return nil, fmt.Errorf("list sites: %w", err) return nil, fmt.Errorf("list sites: %w", err)
@@ -98,10 +98,10 @@ func (r *SQLiteSiteRepository) CreateSite(s *models.Site) error {
s.ID = uuid.NewString() s.ID = uuid.NewString()
_, err = tx.Exec(` _, err = tx.Exec(`
INSERT INTO sites (id, name, git_server, owner, repository, branch, domain, deploy_token, spa, enabled, not_found_file) INSERT INTO sites (id, name, git_server, owner, repository, branch, domain, deploy_token, spa, enabled, not_found_file, index_file, trailing_slash)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
s.ID, s.Name, s.GitServer, s.Owner, s.Repository, s.Branch, s.ID, s.Name, s.GitServer, s.Owner, s.Repository, s.Branch,
s.Domain, s.DeployToken, s.Spa, s.Enabled, s.NotFoundFile, s.Domain, s.DeployToken, s.Spa, s.Enabled, s.NotFoundFile, s.IndexFile, s.TrailingSlash,
) )
if err != nil { if err != nil {
return fmt.Errorf("create site insert: %w", err) return fmt.Errorf("create site insert: %w", err)
@@ -131,9 +131,10 @@ func (r *SQLiteSiteRepository) UpdateSite(s *models.Site) error {
_, err = tx.Exec(` _, err = tx.Exec(`
UPDATE sites SET name=?, git_server=?, owner=?, repository=?, branch=?, domain=?, UPDATE sites SET name=?, git_server=?, owner=?, repository=?, branch=?, domain=?,
deploy_token=?, spa=?, enabled=?, not_found_file=? WHERE id=?`, deploy_token=?, spa=?, enabled=?, not_found_file=?, index_file=?, trailing_slash=? WHERE id=?`,
s.Name, s.GitServer, s.Owner, s.Repository, s.Branch, s.Domain, s.Name, s.GitServer, s.Owner, s.Repository, s.Branch, s.Domain,
s.DeployToken, s.Spa, s.Enabled, s.NotFoundFile, s.ID, s.DeployToken, s.Spa, s.Enabled, s.NotFoundFile, s.IndexFile, s.TrailingSlash,
s.ID,
) )
if err != nil { if err != nil {
return fmt.Errorf("update site: %w", err) return fmt.Errorf("update site: %w", err)
@@ -364,6 +365,7 @@ func scanSite(s scanner) (*models.Site, error) {
err := s.Scan( err := s.Scan(
&site.ID, &site.Name, &site.GitServer, &site.Owner, &site.Repository, &site.ID, &site.Name, &site.GitServer, &site.Owner, &site.Repository,
&site.Branch, &site.Domain, &site.DeployToken, &site.Spa, &enabled, &site.NotFoundFile, &site.Branch, &site.Domain, &site.DeployToken, &site.Spa, &enabled, &site.NotFoundFile,
&site.IndexFile, &site.TrailingSlash, &site.CreatedAt,
) )
if err != nil { if err != nil {
return nil, err return nil, err
+5 -1
View File
@@ -31,7 +31,9 @@ export interface Site {
enabled: boolean; enabled: boolean;
spa: boolean; spa: boolean;
not_found_file: string; not_found_file: string;
last_deployed: string; index_file: string;
trailing_slash: boolean | null;
created_at: string;
forward_rules: ForwardRule[]; forward_rules: ForwardRule[];
custom_headers: CustomHeaders[]; custom_headers: CustomHeaders[];
} }
@@ -45,6 +47,8 @@ export interface CreateSiteRequest {
domain: string; domain: string;
enabled: boolean; enabled: boolean;
spa: boolean; spa: boolean;
not_found_file: string;
index_file: string;
} }
export interface GetAllSitesResponse { export interface GetAllSitesResponse {
+2
View File
@@ -100,6 +100,8 @@ const NewSite = () => {
domain, domain,
spa, spa,
enabled: true, enabled: true,
not_found_file: '',
index_file: '',
}); });
console.log('Created site:', data); console.log('Created site:', data);
}; };
@@ -79,7 +79,7 @@ const OverviewTab = ({ site }: { site: Site }) => (
<Separator /> <Separator />
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-muted-foreground">Last Deployed</span> <span className="text-muted-foreground">Last Deployed</span>
<span>{formatDate(site.last_deployed)}</span> <span>{formatDate('2024-01-01T12:00:00Z')}</span>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
@@ -35,6 +35,9 @@ const SettingsTab = ({ site }: { site: Site }) => {
const [domain, setDomain] = useState(site.domain); const [domain, setDomain] = useState(site.domain);
const [branch, setBranch] = useState(site.branch); const [branch, setBranch] = useState(site.branch);
const [spa, setSpa] = useState(site.spa); const [spa, setSpa] = useState(site.spa);
const [notFoundFile, setNotFoundFile] = useState(site.not_found_file);
const [indexFile, setIndexFile] = useState(site.index_file);
const [confirmName, setConfirmName] = useState(''); const [confirmName, setConfirmName] = useState('');
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
@@ -44,6 +47,8 @@ const SettingsTab = ({ site }: { site: Site }) => {
domain, domain,
branch, branch,
spa, spa,
not_found_file: notFoundFile,
index_file: indexFile,
enabled: site.enabled, enabled: site.enabled,
git_server: site.git_server, git_server: site.git_server,
owner: site.owner, owner: site.owner,
@@ -74,6 +79,7 @@ const SettingsTab = ({ site }: { site: Site }) => {
<Input <Input
id="settings-name" id="settings-name"
value={name} value={name}
placeholder="e.g. My Awesome Site"
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
/> />
</div> </div>
@@ -82,6 +88,7 @@ const SettingsTab = ({ site }: { site: Site }) => {
<Input <Input
id="settings-domain" id="settings-domain"
value={domain} value={domain}
placeholder="e.g. www.example.com"
onChange={(e) => setDomain(e.target.value)} onChange={(e) => setDomain(e.target.value)}
/> />
</div> </div>
@@ -90,9 +97,30 @@ const SettingsTab = ({ site }: { site: Site }) => {
<Input <Input
id="settings-branch" id="settings-branch"
value={branch} value={branch}
placeholder="e.g. gh-pages"
onChange={(e) => setBranch(e.target.value)} onChange={(e) => setBranch(e.target.value)}
/> />
</div> </div>
<div className="flex items-center gap-4">
<div className="space-y-2 grow">
<Label htmlFor="settings-index-file">Custom Index File</Label>
<Input
id="settings-index-file"
value={indexFile}
placeholder="e.g. index.html"
onChange={(e) => setIndexFile(e.target.value)}
/>
</div>
<div className="space-y-2 grow">
<Label htmlFor="settings-not-found">Custom 404 Page</Label>
<Input
id="settings-not-found"
value={notFoundFile}
placeholder="e.g. 404.html"
onChange={(e) => setNotFoundFile(e.target.value)}
/>
</div>
</div>
<div className="flex items-center justify-between rounded-lg border p-4"> <div className="flex items-center justify-between rounded-lg border p-4">
<div className="space-y-0.5"> <div className="space-y-0.5">
<Label htmlFor="settings-spa">Single Page Application</Label> <Label htmlFor="settings-spa">Single Page Application</Label>