working on tickets implementation
34
.gitignore
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
# byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# env vars
|
||||
.env
|
||||
|
||||
# tests and coverage
|
||||
*.pytest_cache
|
||||
.coverage
|
||||
|
||||
# database & logs
|
||||
*.db
|
||||
*.sqlite3
|
||||
*.log
|
||||
|
||||
# venv
|
||||
env
|
||||
venv
|
||||
|
||||
# other
|
||||
.DS_Store
|
||||
|
||||
# javascript
|
||||
package-lock.json
|
||||
|
||||
staticfiles/*
|
||||
!staticfiles/.gitkeep
|
||||
.vscode/symbols.json
|
||||
|
||||
apps/static/assets/node_modules
|
||||
apps/static/assets/yarn.lock
|
||||
apps/static/assets/.temp
|
||||
|
206
README.md
@ -1,204 +1,20 @@
|
||||
# [Adminator Django](https://appseed.us/product/adminator/django/)
|
||||
# Contributing
|
||||
|
||||
Open-source **[Django Dashboard](https://appseed.us/admin-dashboards/django/)** generated by `AppSeed` op top of an iconic design. For newcomers, **Adminator** is one of the best open-source admin dashboard & control panel theme. Built on top of Bootstrap, `Adminator` provides a range of responsive, reusable, and commonly used components.
|
||||
## Migrations
|
||||
|
||||
- 👉 [Adminator Django](https://appseed.us/product/adminator/django/) - `Product page`
|
||||
- 👉 [Adminator Django](https://django-adminator.appseed-srv1.com) - `LIVE deployment`
|
||||
If facing migration errors, delete folders in all apps called `migrations` and delete the `db.sqlite3` database file. Note you will lose all data.
|
||||
|
||||
<br />
|
||||
To get started:
|
||||
|
||||
> 🚀 Built with [App Generator](https://appseed.us/generator/), Timestamp: `2022-05-31 07:49`
|
||||
1. `python manage.py makemigrations authentication`
|
||||
2. `python manage.py makemigrations home`
|
||||
3. `python manage.py migrate`
|
||||
|
||||
- ✅ Database: `sqlite`
|
||||
- ✅ UI-Ready app, Django Native ORM
|
||||
- ✅ `Session-Based authentication`, Forms validation
|
||||
- ✅ Design: [Adminator](https://github.com/app-generator/adminator) **v2.0.3**
|
||||
- Gulp-generated version
|
||||
## Run the server
|
||||
|
||||
<br />
|
||||
`python manage.py runserver 0.0.0.0:8000`
|
||||
|
||||

|
||||
## Access the website
|
||||
|
||||
<br />
|
||||
`http://localhost:8000`
|
||||
|
||||
## ✨ Start the app in Docker
|
||||
|
||||
> **Step 1** - Download the code from the GH repository (using `GIT`)
|
||||
|
||||
```bash
|
||||
$ # Get the code
|
||||
$ git clone https://github.com/app-generator/django-adminator.git
|
||||
$ cd django-adminator
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
> **Step 2** - Start the APP in `Docker`
|
||||
|
||||
```bash
|
||||
$ docker-compose up --build
|
||||
```
|
||||
|
||||
Visit `http://localhost:5085` in your browser. The app should be up & running.
|
||||
|
||||
<br />
|
||||
|
||||
## ✨ How to use it
|
||||
|
||||
> Download the code
|
||||
|
||||
```bash
|
||||
$ # Get the code
|
||||
$ git clone https://github.com/app-generator/django-adminator.git
|
||||
$ cd django-adminator
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
### 👉 Set Up for `Unix`, `MacOS`
|
||||
|
||||
> Install modules via `VENV`
|
||||
|
||||
```bash
|
||||
$ virtualenv env
|
||||
$ source env/bin/activate
|
||||
$ pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
> Set Up Database
|
||||
|
||||
```bash
|
||||
$ python manage.py makemigrations
|
||||
$ python manage.py migrate
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
> Start the app
|
||||
|
||||
```bash
|
||||
$ python manage.py runserver
|
||||
```
|
||||
|
||||
At this point, the app runs at `http://127.0.0.1:8000/`.
|
||||
|
||||
<br />
|
||||
|
||||
### 👉 Set Up for `Windows`
|
||||
|
||||
> Install modules via `VENV` (windows)
|
||||
|
||||
```
|
||||
$ virtualenv env
|
||||
$ .\env\Scripts\activate
|
||||
$ pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
> Set Up Database
|
||||
|
||||
```bash
|
||||
$ python manage.py makemigrations
|
||||
$ python manage.py migrate
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
> Start the app
|
||||
|
||||
```bash
|
||||
$ python manage.py runserver
|
||||
```
|
||||
|
||||
At this point, the app runs at `http://127.0.0.1:8000/`.
|
||||
|
||||
<br />
|
||||
|
||||
### 👉 Create Users
|
||||
|
||||
By default, the app redirects guest users to authenticate. In order to access the private pages, follow this set up:
|
||||
|
||||
- Start the app via `flask run`
|
||||
- Access the `registration` page and create a new user:
|
||||
- `http://127.0.0.1:8000/register/`
|
||||
- Access the `sign in` page and authenticate
|
||||
- `http://127.0.0.1:8000/login/`
|
||||
|
||||
<br />
|
||||
|
||||
## ✨ Code-base structure
|
||||
|
||||
The project is coded using a simple and intuitive structure presented below:
|
||||
|
||||
```bash
|
||||
< PROJECT ROOT >
|
||||
|
|
||||
|-- core/ # Implements app configuration
|
||||
| |-- settings.py # Defines Global Settings
|
||||
| |-- wsgi.py # Start the app in production
|
||||
| |-- urls.py # Define URLs served by all apps/nodes
|
||||
|
|
||||
|-- apps/
|
||||
| |
|
||||
| |-- home/ # A simple app that serve HTML files
|
||||
| | |-- views.py # Serve HTML pages for authenticated users
|
||||
| | |-- urls.py # Define some super simple routes
|
||||
| |
|
||||
| |-- authentication/ # Handles auth routes (login and register)
|
||||
| | |-- urls.py # Define authentication routes
|
||||
| | |-- views.py # Handles login and registration
|
||||
| | |-- forms.py # Define auth forms (login and register)
|
||||
| |
|
||||
| |-- static/
|
||||
| | |-- <css, JS, images> # CSS files, Javascripts files
|
||||
| |
|
||||
| |-- templates/ # Templates used to render pages
|
||||
| |-- includes/ # HTML chunks and components
|
||||
| | |-- navigation.html # Top menu component
|
||||
| | |-- sidebar.html # Sidebar component
|
||||
| | |-- footer.html # App Footer
|
||||
| | |-- scripts.html # Scripts common to all pages
|
||||
| |
|
||||
| |-- layouts/ # Master pages
|
||||
| | |-- base-fullscreen.html # Used by Authentication pages
|
||||
| | |-- base.html # Used by common pages
|
||||
| |
|
||||
| |-- accounts/ # Authentication pages
|
||||
| | |-- login.html # Login page
|
||||
| | |-- register.html # Register page
|
||||
| |
|
||||
| |-- home/ # UI Kit Pages
|
||||
| |-- index.html # Index page
|
||||
| |-- 404-page.html # 404 page
|
||||
| |-- *.html # All other pages
|
||||
|
|
||||
|-- requirements.txt # Development modules - SQLite storage
|
||||
|
|
||||
|-- .env # Inject Configuration via Environment
|
||||
|-- manage.py # Start the app - Django default start script
|
||||
|
|
||||
|-- ************************************************************************
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
## ✨ PRO Version
|
||||
|
||||
> For more components, pages and priority on support, feel free to take a look at this amazing starter:
|
||||
|
||||
Soft UI Dashboard is a premium Bootstrap 5 Design now available for download in Django. Made of hundred of elements, designed blocks, and fully coded pages, Soft UI Dashboard PRO is ready to help you create stunning websites and web apps.
|
||||
|
||||
- 👉 [Soft UI Dashboard PRO Django](https://appseed.us/product/soft-ui-dashboard-pro/django/) - Product Page
|
||||
- 👉 [Soft UI Dashboard PRO Django](https://django-soft-ui-dashboard-pro.appseed-srv1.com/) - LIVE Demo
|
||||
|
||||
<br >
|
||||
|
||||

|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
[Adminator Django](https://appseed.us/product/adminator/django/) - Open-source starter generated by **[AppSeed Generator](https://appseed.us/generator/)**.
|
||||
|
@ -1,8 +1,8 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
|
||||
# Register your models here.
|
||||
from .models import User
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
45
apps/authentication/migrations/0001_initial.py
Normal file
@ -0,0 +1,45 @@
|
||||
# Generated by Django 3.2.16 on 2024-01-04 14:05
|
||||
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
]
|
18
apps/authentication/migrations/0002_user_icon.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.16 on 2024-01-04 14:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authentication', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='icon',
|
||||
field=models.ImageField(default='users/default.webp', upload_to='users'),
|
||||
),
|
||||
]
|
24
apps/authentication/migrations/0003_auto_20240104_1447.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Generated by Django 3.2.16 on 2024-01-04 14:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authentication', '0002_user_icon'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='name',
|
||||
field=models.CharField(default='Corban-Lee Jones', max_length=150),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='email',
|
||||
field=models.EmailField(max_length=254, unique=True),
|
||||
),
|
||||
]
|
@ -1,4 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
@ -1,8 +1,23 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
|
||||
# Create your models here.
|
||||
|
||||
# default user profile image
|
||||
# https://st3.depositphotos.com/9998432/13335/v/450/depositphotos_133352156-stock-illustration-default-placeholder-profile-icon.jpg
|
||||
|
||||
|
||||
class User(AbstractUser):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
icon = models.ImageField(upload_to="users", default="users/default.webp")
|
||||
name = models.CharField(max_length=150)
|
||||
email = models.EmailField(unique=True)
|
||||
|
||||
USERNAME_FIELD = "email"
|
||||
REQUIRED_FIELDS = ["id", "icon", "name"]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -4,11 +4,12 @@ Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
from django.urls import path
|
||||
from .views import login_view, register_user
|
||||
from .views import login_view, register_user, profile_view
|
||||
from django.contrib.auth.views import LogoutView
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', login_view, name="login"),
|
||||
path('register/', register_user, name="register"),
|
||||
path("logout/", LogoutView.as_view(), name="logout")
|
||||
path("logout/", LogoutView.as_view(), name="logout"),
|
||||
path("profile/", profile_view, name="profile"),
|
||||
]
|
||||
|
@ -1,11 +1,9 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
# Create your views here.
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib.auth import authenticate, login
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from .forms import LoginForm, SignUpForm
|
||||
|
||||
|
||||
@ -54,3 +52,7 @@ def register_user(request):
|
||||
form = SignUpForm()
|
||||
|
||||
return render(request, "accounts/register.html", {"form": form, "msg": msg, "success": success})
|
||||
|
||||
@login_required()
|
||||
def profile_view(request):
|
||||
return render(request, "accounts/profile.html")
|
||||
|
@ -1,8 +1,7 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from .models import Ticket
|
||||
|
||||
admin.site.register(Ticket)
|
||||
|
45
apps/home/migrations/0001_initial.py
Normal file
@ -0,0 +1,45 @@
|
||||
# Generated by Django 3.2.16 on 2024-01-04 14:05
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='TicketPriority',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=32)),
|
||||
('colour', models.CharField(max_length=7)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TicketTag',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=32)),
|
||||
('colour', models.CharField(max_length=7)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Ticket',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=60)),
|
||||
('description', models.TextField(max_length=650)),
|
||||
('create_timestamp', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('edit_timestamp', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
@ -1,4 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
@ -1,10 +1,67 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
# Create your models here.
|
||||
|
||||
class TicketPriority(models.Model):
|
||||
title = models.CharField(max_length=32)
|
||||
colour = models.CharField(max_length=7)
|
||||
|
||||
|
||||
class TicketTag(models.Model):
|
||||
title = models.CharField(max_length=32)
|
||||
colour = models.CharField(max_length=7)
|
||||
|
||||
|
||||
class Ticket(models.Model):
|
||||
title = models.CharField(max_length=60)
|
||||
description = models.TextField(max_length=650)
|
||||
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
create_timestamp = models.DateTimeField(editable=True, default=timezone.now)
|
||||
edit_timestamp = models.DateTimeField(editable=True, default=timezone.now)
|
||||
|
||||
def __str__(self):
|
||||
return f"#{self.id} • {self.title} • {self.author}"
|
||||
|
||||
@property
|
||||
def is_edited(self) -> bool:
|
||||
"""Returns boolean if the ticket is believed to have been edited.
|
||||
We assume a ticket is edited if the edit_timestamp doesn't match the create_timestamp.
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
True if `self.edit_timestamp` doesn't match `self.create_timestamp`, False otherwise.
|
||||
"""
|
||||
|
||||
return self.create_timestamp != self.edit_timestamp
|
||||
|
||||
@property
|
||||
def is_older_than_day(self) -> bool:
|
||||
"""Returns boolean dependent on if `self.timestamp` is older than 24 hours.
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
True if `self.timestamp` is older than 24 hours, False otherwise.
|
||||
"""
|
||||
|
||||
dayago = timezone.now() - timedelta(hours=24)
|
||||
return self.timestamp <= dayago
|
||||
|
||||
@property
|
||||
def timestamp(self) -> datetime:
|
||||
"""Returns `self.edit_timestamp` if `self.is_edited` is True, otherwise
|
||||
returns `self.create_timestamp`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
datetime
|
||||
Either `self.edit_timestamp` or `self.create_timestamp`.
|
||||
"""
|
||||
|
||||
return self.edit_timestamp if self.is_edited else self.create_timestamp
|
||||
|
@ -3,7 +3,7 @@
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
from django.urls import path, re_path
|
||||
from django.urls import path, re_path, include
|
||||
from apps.home import views
|
||||
|
||||
urlpatterns = [
|
||||
@ -11,6 +11,13 @@ urlpatterns = [
|
||||
# The home page
|
||||
path('', views.index, name='home'),
|
||||
|
||||
# Custom Dashboard
|
||||
path('dashboard/', views.dashboard, name="dashboard"),
|
||||
path('tickets/', include([
|
||||
path('', views.tickets, name="tickets"),
|
||||
path('new/', views.new_ticket, name="ticket-new"),
|
||||
])),
|
||||
|
||||
# Matches any html file
|
||||
re_path(r'^.*\.*', views.pages, name='pages'),
|
||||
|
||||
|
@ -1,16 +1,44 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
|
||||
from django import template
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.template import loader
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
|
||||
from .models import Ticket
|
||||
|
||||
@login_required(login_url="/login/")
|
||||
|
||||
@login_required()
|
||||
def dashboard(request):
|
||||
return render(request, "home/dashboard.html")
|
||||
|
||||
|
||||
@login_required()
|
||||
def tickets(request):
|
||||
tickets = Ticket.objects.all().order_by("-create_timestamp")
|
||||
context = {
|
||||
"tickets": tickets,
|
||||
"dayago": datetime.now() - timedelta(hours=24)
|
||||
}
|
||||
|
||||
return render(request, "home/tickets.html", context)
|
||||
|
||||
|
||||
def get_ticket(request, ticket_id: int):
|
||||
ticket = Ticket.objects.get(id=ticket_id)
|
||||
|
||||
|
||||
|
||||
@login_required()
|
||||
def new_ticket(request):
|
||||
return render(request, "home/newticket.html")
|
||||
|
||||
|
||||
@login_required()
|
||||
def index(request):
|
||||
context = {'segment': 'index'}
|
||||
|
||||
@ -18,7 +46,7 @@ def index(request):
|
||||
return HttpResponse(html_template.render(context, request))
|
||||
|
||||
|
||||
@login_required(login_url="/login/")
|
||||
@login_required()
|
||||
def pages(request):
|
||||
context = {}
|
||||
# All resource paths end in .html.
|
||||
|
@ -69077,3 +69077,4 @@ table.dataTable.no-footer {
|
||||
ADD Custom code bellow this block
|
||||
*/
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
|
||||
|
49
apps/templates/accounts/profile.html
Normal file
@ -0,0 +1,49 @@
|
||||
{% extends "layouts/base.html" %}
|
||||
|
||||
{% block title %} Profile {% endblock title %}
|
||||
|
||||
<!-- Specific CSS goes HERE -->
|
||||
{% block stylesheets %}{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- ### $App Screen Content ### -->
|
||||
<main class='main-content bgc-grey-100'>
|
||||
<div id='mainContent'>
|
||||
<div class="row gap-20 masonry pos-r">
|
||||
<div class="masonry-sizer col-md-6"></div>
|
||||
<div class="masonry-item col-md-6">
|
||||
<div class="bgc-white p-20 bd">
|
||||
<h6 class="c-grey-900">Basic Form</h6>
|
||||
<div class="mT-30">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="exampleInputEmail1">Email address</label>
|
||||
<input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
|
||||
<small id="emailHelp" class="text-muted">We'll never share your email with anyone else.</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-color">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="masonry-item col-md-6">
|
||||
<div class="bgc-white p-20 bd">
|
||||
<div class="row pos-r justify-content-center justify-content-md-start">
|
||||
<div class="col-md-4 col-8">
|
||||
<img src="{{ request.user.icon.url }}" alt="" class="bdrs-50p w-100">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h3>{{ request.user.name }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
<!-- Specific Page JS goes HERE -->
|
||||
{% block javascripts %}{% endblock javascripts %}
|
287
apps/templates/home/dashboard.html
Normal file
@ -0,0 +1,287 @@
|
||||
{% extends "layouts/base.html" %}
|
||||
|
||||
{% block title %} Dashboard {% endblock title %}
|
||||
|
||||
<!-- Specific CSS goes HERE -->
|
||||
{% block stylesheets %}{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- ### $App Screen Content ### -->
|
||||
<main class='main-content bgc-grey-100'>
|
||||
<div id='mainContent'>
|
||||
<div class="row gap-20 masonry pos-r">
|
||||
<div class="masonry-sizer col-md-6"></div>
|
||||
<div class="masonry-item w-100">
|
||||
<div class="row gap-20">
|
||||
<!-- #Toatl Tickets ==================== -->
|
||||
<div class='col-md-3'>
|
||||
<div class="layers bd bgc-white p-20">
|
||||
<div class="layer w-100 mB-10">
|
||||
<h6 class="lh-1">Total Tickets</h6>
|
||||
</div>
|
||||
<div class="layer w-100">
|
||||
<div class="peers ai-sb fxw-nw">
|
||||
<div class="peer peer-greed">
|
||||
<span id="sparklinedash"></span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="d-ib lh-0 va-m fw-600 bdrs-10em pX-15 pY-15 bgc-green-50 c-green-500">+10%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- #Open Tickets ==================== -->
|
||||
<div class='col-md-3'>
|
||||
<div class="layers bd bgc-white p-20">
|
||||
<div class="layer w-100 mB-10">
|
||||
<h6 class="lh-1">Open Tickets</h6>
|
||||
</div>
|
||||
<div class="layer w-100">
|
||||
<div class="peers ai-sb fxw-nw">
|
||||
<div class="peer peer-greed">
|
||||
<span id="sparklinedash2"></span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="d-ib lh-0 va-m fw-600 bdrs-10em pX-15 pY-15 bgc-red-50 c-red-500">-7%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- #Pending Tickets ==================== -->
|
||||
<div class='col-md-3'>
|
||||
<div class="layers bd bgc-white p-20">
|
||||
<div class="layer w-100 mB-10">
|
||||
<h6 class="lh-1">Pending Tickets</h6>
|
||||
</div>
|
||||
<div class="layer w-100">
|
||||
<div class="peers ai-sb fxw-nw">
|
||||
<div class="peer peer-greed">
|
||||
<span id="sparklinedash3"></span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="d-ib lh-0 va-m fw-600 bdrs-10em pX-15 pY-15 bgc-purple-50 c-purple-500">~12%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- #Closed Tickets ==================== -->
|
||||
<div class='col-md-3'>
|
||||
<div class="layers bd bgc-white p-20">
|
||||
<div class="layer w-100 mB-10">
|
||||
<h6 class="lh-1">Closed Tickets</h6>
|
||||
</div>
|
||||
<div class="layer w-100">
|
||||
<div class="peers ai-sb fxw-nw">
|
||||
<div class="peer peer-greed">
|
||||
<span id="sparklinedash4"></span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="d-ib lh-0 va-m fw-600 bdrs-10em pX-15 pY-15 bgc-blue-50 c-blue-500">33%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="masonry-item col-12">
|
||||
<div class="bd bgc-white">
|
||||
<div class="peers fxw-nw@lg+ ai-s">
|
||||
<div class="peer peer-greed w-70p@lg- p-20">
|
||||
<div class="layers">
|
||||
<div class="layer w-100 pX-20 pT-20">
|
||||
<h6 class="lh-1">Monthly Stats</h6>
|
||||
</div>
|
||||
<div class="layer w-100 p-20 pos-r">
|
||||
<canvas id="line-chart" class="mw-100p" height="220"></canvas>
|
||||
</div>
|
||||
<div class="layer bdT p-20 w-100">
|
||||
<div class="peers ai-c jc-c gapX-20">
|
||||
<div class="peer fw-600">
|
||||
<span class="fsz-def fw-600 mR-10 c-grey-800">2% <i class="fa fa-level-down c-red-500"></i></span>
|
||||
<small class="c-grey-500 fw-600">Open Tickets</small>
|
||||
</div>
|
||||
<div class="peer fw-600">
|
||||
<span class="fsz-def fw-600 mR-10 c-grey-800">15% <i class="fa fa-level-up c-green-500"></i></span>
|
||||
<small class="c-grey-500 fw-600">Pending Tickets</small>
|
||||
</div>
|
||||
<div class="peer fw-600">
|
||||
<span class="fsz-def fw-600 mR-10 c-grey-800">8% <i class="fa fa-level-down c-red-500"></i></span>
|
||||
<small class="c-grey-500 fw-600">Closed Tickets</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="peer bdL p-20 w-30p@lg+ w-100p@lg-">
|
||||
<div class="layers">
|
||||
<div class="layer w-100">
|
||||
<!-- Progress Bars -->
|
||||
<div class="layers">
|
||||
<div class="layer w-100">
|
||||
<h5 class="mB-5">14</h5>
|
||||
<small class="fw-600 c-grey-700">Open Tickets</small>
|
||||
<span class="pull-right c-grey-600 fsz-sm">35%</span>
|
||||
<div class="progress mT-10">
|
||||
<div class="progress-bar bgc-deep-purple-500" role="progressbar" aria-valuenow="35" aria-valuemin="0" aria-valuemax="100" style="width:35%;">
|
||||
<span class="visually-hidden">35% Complete</span>
|
||||
</div>
|
||||
<div class="progress-bar bgc-grey-300" role="progressbar" style="width: 65%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layer w-100 mT-15">
|
||||
<h5 class="mB-5">10</h5>
|
||||
<small class="fw-600 c-grey-700">Pending Tickets</small>
|
||||
<span class="pull-right c-grey-600 fsz-sm">25%</span>
|
||||
<div class="progress mT-10">
|
||||
<div class="progress-bar bgc-grey-300" role="progressbar" style="width: 35%;"></div>
|
||||
<div class="progress-bar bgc-blue-500" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="width:25%;">
|
||||
<span class="visually-hidden">25% Complete</span>
|
||||
</div>
|
||||
<div class="progress-bar bgc-grey-300" role="progressbar" style="width: 40%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layer w-100 mT-15">
|
||||
<h5 class="mB-5">16</h5>
|
||||
<small class="fw-600 c-grey-700">Closed Tickets</small>
|
||||
<span class="pull-right c-grey-600 fsz-sm">40%</span>
|
||||
<div class="progress mT-10">
|
||||
<div class="progress-bar bgc-grey-300" role="progressbar" style="width: 60%;"></div>
|
||||
<div class="progress-bar bgc-red-500" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width:40%;">
|
||||
<span class="visually-hidden">40% Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Pie Charts -->
|
||||
<div class="peers pT-20 mT-20 bdT fxw-nw@lg+ jc-sb ta-c gap-10">
|
||||
<div class="peer">
|
||||
<div class="easy-pie-chart" data-size='80' data-percent="75" data-bar-color='#f44336'>
|
||||
<span></span>
|
||||
</div>
|
||||
<h6 class="fsz-sm">Low Priority</h6>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<div class="easy-pie-chart" data-size='80' data-percent="50" data-bar-color='#2196f3'>
|
||||
<span></span>
|
||||
</div>
|
||||
<h6 class="fsz-sm">Medium Priority</h6>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<div class="easy-pie-chart" data-size='80' data-percent="90" data-bar-color='#ff9800'>
|
||||
<span></span>
|
||||
</div>
|
||||
<h6 class="fsz-sm">High Priority</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="masonry-item col-md-6">
|
||||
<!-- #Sales Report ==================== -->
|
||||
<div class="bd bgc-white">
|
||||
<div class="layers">
|
||||
<div class="layer w-100 p-20">
|
||||
<h6 class="lh-1">Tickets Report</h6>
|
||||
</div>
|
||||
<div class="layer w-100">
|
||||
<div class="bgc-light-blue-500 c-white p-20">
|
||||
<div class="peers ai-c jc-sb gap-40">
|
||||
<div class="peer peer-greed">
|
||||
<h5>January 2024</h5>
|
||||
<p class="mB-0">Tickets Report</p>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<h3 class="text-end">17 Solved</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive p-20">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class=" bdwT-0">Name</th>
|
||||
<th class=" bdwT-0">Status</th>
|
||||
<th class=" bdwT-0">Date</th>
|
||||
<th class=" bdwT-0">Department</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="fw-600">Ticket #01</td>
|
||||
<td><span class="badge bgc-red-50 c-red-700 p-10 lh-0 tt-c rounded-pill">Closed</span> </td>
|
||||
<td>Jan 18</td>
|
||||
<td><span class="">Sales</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-600">Ticket #02</td>
|
||||
<td><span class="badge bgc-deep-purple-50 c-deep-purple-700 p-10 lh-0 tt-c rounded-pill">Open</span></td>
|
||||
<td>Jan 19</td>
|
||||
<td><span class="">Sales</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-600">Ticket #03</td>
|
||||
<td><span class="badge bgc-red-50 c-red-700 p-10 lh-0 tt-c rounded-pill">Closed</span></td>
|
||||
<td>Jan 20</td>
|
||||
<td><span class="">Sales</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-600">Ticket #04</td>
|
||||
<td><span class="badge bgc-blue-50 c-blue-700 p-10 lh-0 tt-c rounded-pill">Pending</span></td>
|
||||
<td>Jan 21</td>
|
||||
<td><span class="">Sales</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-600">Ticket #05</td>
|
||||
<td><span class="badge bgc-deep-purple-50 c-deep-purple-700 p-10 lh-0 tt-c rounded-pill">Open</span></td>
|
||||
<td>Jan 22</td>
|
||||
<td><span class="">Sales</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-600">Ticket #06</td>
|
||||
<td><span class="badge bgc-deep-purple-50 c-deep-purple-700 p-10 lh-0 tt-c rounded-pill">Open</span> </td>
|
||||
<td>Jan 23</td>
|
||||
<td><span class="">Sales</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-600">Ticket #07</td>
|
||||
<td><span class="badge bgc-blue-50 c-blue-700 p-10 lh-0 tt-c rounded-pill">Pending</span></td>
|
||||
<td>Jan 22</td>
|
||||
<td><span class="">Sales</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ta-c bdT w-100 p-20">
|
||||
<a href="#">Check all the tickets</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="masonry-item col-md-6">
|
||||
<div class="bgc-white p-20 bd">
|
||||
<h6 class="c-grey-900">Bar Chart</h6>
|
||||
<div class="mT-30">
|
||||
<canvas id="bar-chart" height="220"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
<!-- Specific Page JS goes HERE -->
|
||||
{% block javascripts %}{% endblock javascripts %}
|
35
apps/templates/home/newticket.html
Normal file
@ -0,0 +1,35 @@
|
||||
{% extends "layouts/base.html" %}
|
||||
|
||||
{% block title %} New Ticket {% endblock title %}
|
||||
|
||||
<!-- Specific CSS goes HERE -->
|
||||
{% block stylesheets %}{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- ### $App Screen Content ### -->
|
||||
<main class='main-content bgc-grey-100'>
|
||||
<div id='mainContent'>
|
||||
<div class="row gap-20 masonry pos-r">
|
||||
<div class="masonry-sizer col-md-6"></div>
|
||||
<div class="masonry-item col-md-6">
|
||||
<div class="bgc-white p-20 bd">
|
||||
<h6 class="c-grey-900">Basic Form</h6>
|
||||
<div class="mT-30">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="input1" class="form-label">Input 1</label>
|
||||
<input type="text" id="input1" class="form-control" placeholder="Enter Input 1">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
<!-- Specific Page JS goes HERE -->
|
||||
{% block javascripts %}{% endblock javascripts %}
|
422
apps/templates/home/tickets.html
Normal file
@ -0,0 +1,422 @@
|
||||
{% extends "layouts/base.html" %}
|
||||
|
||||
{% block title %} Tickets {% endblock title %}
|
||||
|
||||
<!-- Specific CSS goes HERE -->
|
||||
{% block stylesheets %}{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- ### $App Screen Content ### -->
|
||||
<main class='main-content bgc-grey-100'>
|
||||
<div id='mainContent'>
|
||||
<div class="full-container">
|
||||
<div class="email-app">
|
||||
<div class="email-side-nav remain-height ov-h">
|
||||
<div class="h-100 layers">
|
||||
<div class="p-20 bgc-grey-100 layer w-100">
|
||||
<button type="button" class="btn btn-danger c-white w-100" data-bs-toggle="modal" data-bs-target="#ticketModal">New Ticket</button>
|
||||
</div>
|
||||
<div class="scrollable pos-r bdT layer w-100 fxg-1">
|
||||
<ul class="p-20 nav flex-column">
|
||||
<li class="nav-item">
|
||||
<h6>Filters</h6>
|
||||
</li>
|
||||
<li class="nav-item ps-3 mT-15">
|
||||
<h6 class="small">Priority</h6>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="priority1" class="form-check-input">
|
||||
<label for="priority1" class="form-check-label">High</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="priority2" class="form-check-input">
|
||||
<label for="priority2" class="form-check-label">Medium</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="priority3" class="form-check-input">
|
||||
<label for="priority3" class="form-check-label">Low</label>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item ps-3 mT-15">
|
||||
<h6 class="small">Department</h6>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="sales" class="form-check-input">
|
||||
<label for="sales" class="form-check-label">Sales</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="strategy" class="form-check-input">
|
||||
<label for="strategy" class="form-check-label">Strategy</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="marketing" class="form-check-input">
|
||||
<label for="marketing" class="form-check-label">Marketing</label>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item ps-3 mT-15">
|
||||
<h6 class="small">Tags</h6>
|
||||
</li>
|
||||
<!-- <li class="nav-item mt-5">
|
||||
<a href="javascript:void(0)" class="nav-link c-grey-800 cH-blue-500 actived">
|
||||
<div class="peers ai-c jc-sb">
|
||||
<div class="peer peer-greed">
|
||||
<i class="mR-10 ti-email"></i>
|
||||
<span>Inbox</span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="badge rounded-pill bgc-deep-purple-50 c-deep-purple-700">+99</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="" class="nav-link c-grey-800 cH-blue-500">
|
||||
<div class="peers ai-c jc-sb">
|
||||
<div class="peer peer-greed">
|
||||
<i class="mR-10 ti-share"></i>
|
||||
<span>Sent</span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="badge rounded-pill bgc-green-50 c-green-700">12</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="" class="nav-link c-grey-800 cH-blue-500">
|
||||
<div class="peers ai-c jc-sb">
|
||||
<div class="peer peer-greed">
|
||||
<i class="mR-10 ti-star"></i>
|
||||
<span>Important</span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="badge rounded-pill bgc-blue-50 c-blue-700">3</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="" class="nav-link c-grey-800 cH-blue-500">
|
||||
<div class="peers ai-c jc-sb">
|
||||
<div class="peer peer-greed">
|
||||
<i class="mR-10 ti-file"></i>
|
||||
<span>Drafts</span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="badge rounded-pill bgc-amber-50 c-amber-700">5</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="" class="nav-link c-grey-800 cH-blue-500">
|
||||
<div class="peers ai-c jc-sb">
|
||||
<div class="peer peer-greed">
|
||||
<i class="mR-10 ti-alert"></i>
|
||||
<span>Spam</span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="badge rounded-pill bgc-red-50 c-red-700">1</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="" class="nav-link c-grey-800 cH-blue-500">
|
||||
<div class="peers ai-c jc-sb">
|
||||
<div class="peer peer-greed">
|
||||
<i class="mR-10 ti-trash"></i>
|
||||
<span>Trash</span>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="badge rounded-pill bgc-red-50 c-red-700">+99</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="email-wrapper row remain-height bgc-white ov-h">
|
||||
<div class="email-list h-100 layers">
|
||||
<div class="layer w-100">
|
||||
<div class="bgc-grey-100 peers ai-c p-20 fxw-nw">
|
||||
<div class="peer me-auto">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="email-side-toggle d-n@md+ btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-menu"></i>
|
||||
</button>
|
||||
<button type="button" class="btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-folder"></i>
|
||||
</button>
|
||||
<button type="button" class="btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-tag"></i>
|
||||
</button>
|
||||
<div class="btn-group" role="group">
|
||||
<button id="btnGroupDrop1" type="button" class="btn cur-p bgc-white no-after dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="ti-more-alt"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu fsz-sm" aria-labelledby="btnGroupDrop1">
|
||||
<li>
|
||||
<a href="" class="d-b td-n pY-5 pX-10 bgcH-grey-100 c-grey-700">
|
||||
<i class="ti-trash mR-10"></i>
|
||||
<span>Delete</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="d-b td-n pY-5 pX-10 bgcH-grey-100 c-grey-700">
|
||||
<i class="ti-alert mR-10"></i>
|
||||
<span>Mark as Spam</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="d-b td-n pY-5 pX-10 bgcH-grey-100 c-grey-700">
|
||||
<i class="ti-star mR-10"></i>
|
||||
<span>Star</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="fsz-xs btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-angle-left"></i>
|
||||
</button>
|
||||
<button type="button" class="fsz-xs btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-angle-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layer w-100">
|
||||
<div class="bdT bdB">
|
||||
<input type="text" class="form-control m-0 bdw-0 pY-15 pX-20 bdrs-0" placeholder="Search...">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layer w-100 fxg-1 scrollable pos-r">
|
||||
{% for ticket in tickets %}
|
||||
<div class="email-list-item peers fxw-nw p-20 bdB bgcH-grey-100 cur-p" data-ticket-id="{{ ticket.id }}" data-author-icon="{{ ticket.author.icon.url }}">
|
||||
<div class="peer mR-10">
|
||||
<img src="{{ ticket.author.icon.url }}" alt="" class="w-2r bdrs-50p me-2">
|
||||
<!-- <div class="checkbox checkbox-circle checkbox-info peers ai-c">
|
||||
<input type="checkbox" id="inputCall1" name="inputCheckboxesCall" class="peer">
|
||||
<label for="inputCall1" class="form-label peers peer-greed js-sb ai-c"></label>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="peer peer-greed ov-h">
|
||||
<div class="peers ai-c">
|
||||
<div class="peer peer-greed">
|
||||
<h6 class="ticket-author mb-0">{{ ticket.author }}</h6>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<small class="ticket-timestamp">
|
||||
{% if ticket.is_older_than_day %}
|
||||
{{ ticket.timestamp|date:"w M, Y" }}
|
||||
{% else %}
|
||||
{{ ticket.timestamp|date:"H:i" }}
|
||||
{% endif %}
|
||||
</small>
|
||||
{% if ticket.is_edited %}
|
||||
<small>• edited</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="fsz-def tt-c c-grey-900 ticket-title">{{ ticket.title }}</h5>
|
||||
<span class="whs-nw w-100 ov-h tov-e d-b ticket-desc">{{ ticket.description }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="email-content h-100">
|
||||
<div class="h-100 scrollable pos-r">
|
||||
<div class="bgc-grey-100 peers ai-c jc-sb p-20 fxw-nw d-n@md+">
|
||||
<div class="peer">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="back-to-mailbox btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-angle-left"></i>
|
||||
</button>
|
||||
<button type="button" class="btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-folder"></i>
|
||||
</button>
|
||||
<button type="button" class="btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-tag"></i>
|
||||
</button>
|
||||
<div class="btn-group" role="group">
|
||||
<button id="btnGroupDrop1" type="button" class="btn cur-p bgc-white no-after dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="ti-more-alt"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu fsz-sm" aria-labelledby="btnGroupDrop1">
|
||||
<li>
|
||||
<a href="" class="d-b td-n pY-5 pX-10 bgcH-grey-100 c-grey-700">
|
||||
<i class="ti-trash mR-10"></i>
|
||||
<span>Delete</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="d-b td-n pY-5 pX-10 bgcH-grey-100 c-grey-700">
|
||||
<i class="ti-alert mR-10"></i>
|
||||
<span>Mark as Spam</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="d-b td-n pY-5 pX-10 bgcH-grey-100 c-grey-700">
|
||||
<i class="ti-star mR-10"></i>
|
||||
<span>Star</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="fsz-xs btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-angle-left"></i>
|
||||
</button>
|
||||
<button type="button" class="fsz-xs btn bgc-white bdrs-2 mR-3 cur-p">
|
||||
<i class="ti-angle-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="email-content-wrapper">
|
||||
<!-- Header -->
|
||||
<div class="peers ai-c jc-sb pX-40 pY-30">
|
||||
<div class="peers peer-greed">
|
||||
<div class="peer mR-20">
|
||||
<img id="ticketAuthorImg" class="bdrs-50p w-3r h-3r" alt="" src="" style="display: none;">
|
||||
</div>
|
||||
<div class="peer">
|
||||
<small id="ticketTimestamp"></small>
|
||||
<h5 id="ticketAuthor" class="c-grey-900 mB-5"></h5>
|
||||
<div id="ticketBadges" style="display: none;">
|
||||
<div class="badge bgc-pink-300">Urgent</div>
|
||||
<div class="badge bgc-deep-purple-400">IT</div>
|
||||
<div class="badge bgc-green-300">Open</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="peer">
|
||||
<div class="btn-group" role="group">
|
||||
<button id="btnGroupDrop2" class="btn btn-danger c-white bdrs-50p p-15 lh-0" style="display: none;" type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="ti-menu"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu fsz-sm" aria-labelledby="btnGroupDrop2">
|
||||
test
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="bdT pX-40 pY-30">
|
||||
|
||||
<h4 id="ticketTitle"></h4>
|
||||
<p id="ticketDesc"></p>
|
||||
<!-- <h4>Title of this email goes here</h4>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam
|
||||
</p> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div id="ticketModal" class="modal fade" aria-hidden="true">
|
||||
<div class="modal-dialog modal-fullscreen">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title fs-5">Modal</h3>
|
||||
<button type="button" class="btn-close" data-bs-toggle="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
<!-- Specific Page JS goes HERE -->
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
var displayedTicketID = -1;
|
||||
|
||||
$(document).ready(function() {
|
||||
$(".email-list-item").on("click", function() {
|
||||
displayTicket(this);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
function displayTicket(ticketElement) {
|
||||
ticket = $(ticketElement);
|
||||
ticketID = ticket.data("ticket-id");
|
||||
|
||||
$(".back-to-mailbox").off("click").on("click", function(event) {
|
||||
event.preventDefault();
|
||||
$('.email-content').toggleClass('open');
|
||||
displayTicket(ticketElement);
|
||||
});
|
||||
|
||||
if (displayedTicketID === ticketID) {
|
||||
$("#ticketTitle").text("")
|
||||
$("#ticketDesc").text("");
|
||||
$("#ticketAuthor").text("");
|
||||
$("#ticketAuthorImg").hide();
|
||||
$("#ticketAuthorImg").prop("src", "");
|
||||
$("#ticketTimestamp").text("");
|
||||
$("#btnGroupDrop2").hide();
|
||||
$("#ticketBadges").hide();
|
||||
|
||||
displayedTicketID = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
displayedTicketID = ticketID;
|
||||
|
||||
title = ticket.find(".ticket-title").text();
|
||||
desc = ticket.find(".ticket-desc").text();
|
||||
author = ticket.find(".ticket-author").text();
|
||||
authorIcon = ticket.data("author-icon");
|
||||
timestamp = ticket.find(".ticket-timestamp").text();
|
||||
|
||||
$("#ticketTitle").text(title)
|
||||
$("#ticketDesc").text(desc);
|
||||
$("#ticketAuthor").text(author);
|
||||
$("#ticketAuthorImg").show();
|
||||
$("#ticketAuthorImg").prop("src", authorIcon);
|
||||
$("#ticketTimestamp").text(timestamp);
|
||||
$("#btnGroupDrop2").show();
|
||||
$("#ticketBadges").show();
|
||||
}
|
||||
</script>
|
||||
{% endblock javascripts %}
|
@ -1,5 +1,5 @@
|
||||
<footer class="bdT ta-c p-30 lh-0 fsz-sm c-grey-600">
|
||||
<span>
|
||||
© Designed by Colorlib - Supported By <a href="https://appseed.us/" target="_blank">AppSeed</a>.
|
||||
© Designed by Colorlib.
|
||||
</span>
|
||||
</footer>
|
@ -181,10 +181,10 @@
|
||||
<li class="dropdown">
|
||||
<a href="" class="dropdown-toggle no-after peers fxw-nw ai-c lh-1" data-bs-toggle="dropdown">
|
||||
<div class="peer mR-10">
|
||||
<img class="w-2r bdrs-50p" src="https://randomuser.me/api/portraits/men/10.jpg" alt="">
|
||||
<img class="w-2r bdrs-50p" src="{{ request.user.icon.url }}" alt="">
|
||||
</div>
|
||||
<div class="peer">
|
||||
<span class="fsz-sm c-grey-900">John Doe</span>
|
||||
<span class="fsz-sm c-grey-900">{{ request.user }}</span>
|
||||
</div>
|
||||
</a>
|
||||
<ul class="dropdown-menu fsz-sm">
|
||||
@ -195,7 +195,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="d-b td-n pY-5 bgcH-grey-100 c-grey-700">
|
||||
<a href="{% url 'profile' %}" class="d-b td-n pY-5 bgcH-grey-100 c-grey-700">
|
||||
<i class="ti-user mR-10"></i>
|
||||
<span>Profile</span>
|
||||
</a>
|
||||
|
@ -31,11 +31,31 @@
|
||||
<!-- ### $Sidebar Menu ### -->
|
||||
<ul class="sidebar-menu scrollable pos-r">
|
||||
<li class="nav-item mT-30 actived">
|
||||
<a class="sidebar-link" href="{% url 'dashboard' %}">
|
||||
<span class="icon-holder">
|
||||
<i class="c-blue-500 ti-home"></i>
|
||||
</span>
|
||||
<span class="title">New Dashboard</span>
|
||||
<!-- ti-comment-alt -->
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="sidebar-link" href="{% url 'tickets' %}">
|
||||
<span class="icon-holder">
|
||||
<i class="c-green-500 ti-ticket"></i>
|
||||
</span>
|
||||
<span class="title">Tickets</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<hr class="bgc-grey-500">
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="sidebar-link" href="/index.html">
|
||||
<span class="icon-holder">
|
||||
<i class="c-blue-500 ti-home"></i>
|
||||
</span>
|
||||
<span class="title">Dashboard</span>
|
||||
<span class="title">Template Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
|
@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>
|
||||
Django Adminator - {% block title %}{% endblock %} | AppSeed
|
||||
Django Adminator - {% block title %}{% endblock %}
|
||||
</title>
|
||||
|
||||
<link
|
||||
@ -73,6 +73,37 @@
|
||||
|
||||
<!-- Specific Page JS goes HERE -->
|
||||
{% block javascripts %}{% endblock javascripts %}
|
||||
<script>
|
||||
// $(document).ready(function() {
|
||||
// (function(){
|
||||
// var nativeAddClass = jQuery.fn.addClass;
|
||||
// var nativeRemoveClass = jQuery.fn.removeClass;
|
||||
|
||||
// jQuery.fn.addClass = function(){
|
||||
// var result = nativeAddClass.apply( this, arguments );
|
||||
// jQuery(this).trigger('cssClassChanged');
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// jQuery.fn.removeClass = function(){
|
||||
// var result = nativeRemoveClass.apply( this, arguments );
|
||||
// jQuery(this).trigger('cssClassChanged');
|
||||
// return result;
|
||||
// }
|
||||
// })();
|
||||
|
||||
// $(function() {
|
||||
// $("body").bind("cssClassChanged", function() {
|
||||
// alert("trigger");
|
||||
// localStorage.setItem("collapsed", $(this).hasClass("is-collapsed"));
|
||||
// });
|
||||
// });
|
||||
|
||||
// if (localStorage.getItem("collapsed") === "true") {
|
||||
// $("body").addClass("is-collapsed");
|
||||
// }
|
||||
// });
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,7 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
import os, environ
|
||||
|
||||
@ -27,7 +24,7 @@ DEBUG = env('DEBUG')
|
||||
ASSETS_ROOT = os.getenv('ASSETS_ROOT', '/static/assets')
|
||||
|
||||
# load production server from .env
|
||||
ALLOWED_HOSTS = ['localhost', 'localhost:85', '127.0.0.1', 'code.corbz.dev', env('SERVER', default='127.0.0.1') ]
|
||||
ALLOWED_HOSTS = ['localhost', 'localhost:85', '127.0.0.1', '192.168.0.19', env('SERVER', default='127.0.0.1') ]
|
||||
CSRF_TRUSTED_ORIGINS = ['http://localhost:85', 'http://127.0.0.1', 'https://' + env('SERVER', default='127.0.0.1') ]
|
||||
|
||||
# Application definition
|
||||
@ -39,7 +36,8 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'apps.home' # Enable the inner home (home)
|
||||
'apps.home', # Enable the inner home (home)
|
||||
'apps.authentication'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -120,9 +118,9 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
LANGUAGE_CODE = 'en-gb'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = 'Europe/London'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
@ -143,6 +141,16 @@ STATICFILES_DIRS = (
|
||||
os.path.join(CORE_DIR, 'apps/static'),
|
||||
)
|
||||
|
||||
# Media Files
|
||||
MEDIA_ROOT = os.path.join(CORE_DIR, 'media')
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
#############################################################
|
||||
#############################################################
|
||||
|
||||
# If route isnt found, try again with appended slash
|
||||
APPEND_SLASH = True
|
||||
|
||||
AUTH_USER_MODEL = "authentication.User"
|
||||
|
||||
LOGIN_URL = "/login/"
|
@ -1,16 +1,16 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2019 - present AppSeed.us
|
||||
"""
|
||||
|
||||
from django.contrib import admin
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.urls import path, include # add this
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls), # Django admin route
|
||||
path("", include("apps.authentication.urls")), # Auth routes - login / register
|
||||
|
||||
# ADD NEW Routes HERE
|
||||
*static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT),
|
||||
path("", include("apps.authentication.urls")), # Auth routes - login / register
|
||||
|
||||
# Leave `Home.Urls` as last the last line
|
||||
path("", include("apps.home.urls"))
|
||||
|
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 664 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 313 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 35 KiB |
BIN
media/users/default.webp
Normal file
After Width: | Height: | Size: 1.8 KiB |
@ -1,11 +1,12 @@
|
||||
Django==3.2.16
|
||||
asgiref==3.4.1
|
||||
autopep8==1.6.0
|
||||
dj-database-url==0.5.0
|
||||
Django==3.2.16
|
||||
django-environ==0.8.1
|
||||
gunicorn==20.1.0
|
||||
pillow==10.2.0
|
||||
pycodestyle==2.8.0
|
||||
pytz==2021.3
|
||||
sqlparse==0.4.2
|
||||
toml==0.10.2
|
||||
whitenoise==5.3.0
|
||||
django-environ==0.8.1
|
||||
|