forked from Hostea/dashboard
feat: bootstrap dashboard templates and dashboard homepage view
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 {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
/*
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
*/
|
||||
}
|
||||
|
||||
a:hover {
|
||||
|
@ -99,6 +101,7 @@ header {
|
|||
width: 100%;
|
||||
padding-top: 5px;
|
||||
border-bottom: 1px solid rgb(211, 211, 211);
|
||||
height: 63px;
|
||||
}
|
||||
|
||||
.nav__home-btn {
|
||||
|
@ -469,3 +472,56 @@ footer {
|
|||
}
|
||||
|
||||
/* 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