feat: bootstrap dashboard templates and dashboard homepage view
ci/woodpecker/push/woodpecker Pipeline was successful
Details
ci/woodpecker/push/woodpecker Pipeline was successful
Details
parent
1a0ca0117a
commit
64b4437acd
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class DashConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'dash'
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
{% load static %}
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="stylesheet" href="{% static 'css/main.css' %}" />
|
||||||
|
<title>{{ title }}| Hostea Dashbaord</title>
|
||||||
|
{% include "common/components/meta.html" %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
{% include "dash/common/components/primary-nav.html" %}
|
||||||
|
</header>
|
||||||
|
<div class="panel__container">
|
||||||
|
{% include "dash/common/components/secondary-nav.html" %}
|
||||||
|
<main class="dash__main">
|
||||||
|
{% block dash %} {% endblock %}
|
||||||
|
{% include "common/components/footer.html" %}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,36 @@
|
||||||
|
{% load static %}
|
||||||
|
<nav class="nav__container">
|
||||||
|
<input type="checkbox" class="nav__toggle" id="nav__toggle" />
|
||||||
|
<div class="nav__header">
|
||||||
|
<a class="nav__logo-container" href="/">
|
||||||
|
<img
|
||||||
|
src="{% static 'img/android-icon-48x48.png' %}"
|
||||||
|
alt="Hostea temporary logo"
|
||||||
|
/>
|
||||||
|
<p class="nav__home-btn">ostea</p>
|
||||||
|
</a>
|
||||||
|
<label class="nav__hamburger-menu" for="nav__toggle">
|
||||||
|
<span class="nav__hamburger-inner"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav__spacer"></div>
|
||||||
|
|
||||||
|
<div class="nav__link-group">
|
||||||
|
<div class="nav__link-container">
|
||||||
|
<a class="nav__link" rel="noreferrer" href="{% url 'accounts.login' %}"
|
||||||
|
>Add Instance</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="nav__link-container">
|
||||||
|
<a class="nav__link" rel="noreferrer" href="{% url 'accounts.login' %}"
|
||||||
|
>Support</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="nav__link-container">
|
||||||
|
<a class="nav__link" rel="noreferrer" href="{% url 'accounts.logout' %}"
|
||||||
|
>Logout</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<aside class="secondary-nav__container">
|
||||||
|
<nav class="secondary-nav">
|
||||||
|
<div class="secondary-nav__options">
|
||||||
|
<p class="secondary-nav__option-link">realaravinth</p>
|
||||||
|
</div>
|
||||||
|
<div class="secondary-nav__options">
|
||||||
|
<a href="/foo" class="secondary-nav__option-link">Instances</a>
|
||||||
|
<a href="/foo" class="secondary-nav__option-link">Support</a>
|
||||||
|
<a href="/foo" class="secondary-nav__option-link">Billing</a>
|
||||||
|
</div>
|
||||||
|
<div class="secondary-nav__options">
|
||||||
|
<a href="/foo" class="secondary-nav__option-link">Manage Account</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends 'dash/common/base.html' %}
|
||||||
|
{% block dash %}
|
||||||
|
{% include "common/components/error.html" %}
|
||||||
|
<h2>{{ title }}</h2>
|
||||||
|
{% include "common/components/error.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,71 @@
|
||||||
|
# Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.utils.http import urlencode
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.test import TestCase, Client, override_settings
|
||||||
|
from django.contrib.auth import authenticate
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
class DashHome(TestCase):
|
||||||
|
"""
|
||||||
|
Tests create new app view
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.password = "password121231"
|
||||||
|
self.username = "dashboard_home_user"
|
||||||
|
self.email = f"{self.username}@example.org"
|
||||||
|
self.user = get_user_model().objects.create(
|
||||||
|
username=self.username,
|
||||||
|
email=self.email,
|
||||||
|
)
|
||||||
|
self.user.set_password(self.password)
|
||||||
|
self.user.save()
|
||||||
|
|
||||||
|
def test_dash_is_protected(self):
|
||||||
|
"""
|
||||||
|
Tests if dashboard template renders
|
||||||
|
"""
|
||||||
|
resp = self.client.get(reverse("dash.home"))
|
||||||
|
self.assertEqual(resp.status_code, 302)
|
||||||
|
|
||||||
|
# default LOGIN redirect URI that is used by @login_required decorator is
|
||||||
|
# /accounts/login. There's a redirection endpoint at /accounts/login/ that
|
||||||
|
# will redirect user to /login. Hence the /accounts prefix
|
||||||
|
redirect_login_uri = f"/accounts{reverse('accounts.login')}?next={reverse('dash.home')}"
|
||||||
|
self.assertEqual(resp.headers["location"], redirect_login_uri)
|
||||||
|
|
||||||
|
def test_dash_home_renders(self):
|
||||||
|
"""
|
||||||
|
Tests if login template renders
|
||||||
|
"""
|
||||||
|
c = Client()
|
||||||
|
|
||||||
|
# username login works
|
||||||
|
payload = {
|
||||||
|
"login": self.username,
|
||||||
|
"password": self.password,
|
||||||
|
}
|
||||||
|
resp = c.post(reverse("accounts.login"), payload)
|
||||||
|
self.assertEqual(resp.status_code, 302)
|
||||||
|
self.assertEqual(resp.headers["location"], reverse("accounts.home"))
|
||||||
|
|
||||||
|
# email login works
|
||||||
|
resp = c.get(reverse('dash.home'))
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertEqual(b"Billing" in resp.content, True)
|
||||||
|
self.assertEqual(b"Support" in resp.content, True)
|
||||||
|
self.assertEqual(b"Logout" in resp.content, True)
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
|
||||||
|
from .views import (
|
||||||
|
home
|
||||||
|
)
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("", home, name="dash.home"),
|
||||||
|
]
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
from django.utils.http import urlencode
|
||||||
|
from django.contrib.auth import authenticate, login, logout
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.views.decorators.csrf import csrf_protect
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
def default_ctx(title: str):
|
||||||
|
return {
|
||||||
|
"title": title,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def home(request):
|
||||||
|
PAGE_TITLE = "Home"
|
||||||
|
ctx = default_ctx(title=PAGE_TITLE)
|
||||||
|
|
||||||
|
return render(request, "dash/home/index.html", context=ctx)
|
|
@ -34,9 +34,11 @@ h2 {
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
/*
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
|
@ -99,6 +101,7 @@ header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
border-bottom: 1px solid rgb(211, 211, 211);
|
border-bottom: 1px solid rgb(211, 211, 211);
|
||||||
|
height: 63px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__home-btn {
|
.nav__home-btn {
|
||||||
|
@ -469,3 +472,56 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* footer ends */
|
/* footer ends */
|
||||||
|
|
||||||
|
/* dashbaord starts */
|
||||||
|
|
||||||
|
.panel__container {
|
||||||
|
/* background-color: green; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* secondary nav starts */
|
||||||
|
.secondary-nav__container {
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-x: auto;
|
||||||
|
flex: 1;
|
||||||
|
position: fixed;
|
||||||
|
top: 63px;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
width: 260px;
|
||||||
|
border-right: 1px solid rgb(217, 217, 217);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-nav {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.secondary-nav__options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-bottom: 1px solid rgb(217, 217, 217);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-nav__option-link {
|
||||||
|
padding: 20px 0 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-nav__option-link:hover {
|
||||||
|
background-color: lightslategray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* secondary nav ends */
|
||||||
|
|
||||||
|
.dash__main {
|
||||||
|
flex: 2;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
min-height: calc(-63px + 100vh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dashbaord ends */
|
||||||
|
|
Loading…
Reference in New Issue