main
parent
73eb499e7a
commit
43d52a360c
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-05 13:38
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('osinacore', '0109_remove_status_task'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='projectrequirement',
|
||||||
|
name='milestone',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='osinacore.milestone'),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-05 13:40
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('osinacore', '0110_projectrequirement_milestone'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name='ProjectRequirement',
|
||||||
|
new_name='UserStory',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='task',
|
||||||
|
old_name='requirement',
|
||||||
|
new_name='userstory',
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-05 14:13
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('osinacore', '0111_rename_projectrequirement_userstory_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='milestone',
|
||||||
|
old_name='title',
|
||||||
|
new_name='name',
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-05 14:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('osinacore', '0112_rename_title_milestone_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userstory',
|
||||||
|
name='completed',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userstory',
|
||||||
|
name='confirmed',
|
||||||
|
field=models.BooleanField(default=True),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-05 15:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('osinacore', '0113_userstory_completed_userstory_confirmed'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='project',
|
||||||
|
name='end_date',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-05 15:18
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('osinacore', '0114_alter_project_end_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='projectstatus',
|
||||||
|
name='default_created',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-05 15:19
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('osinacore', '0115_projectstatus_default_created'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='projectstatus',
|
||||||
|
name='default_created',
|
||||||
|
),
|
||||||
|
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,45 @@
|
|||||||
|
{% extends "add-edit-main.html" %}
|
||||||
|
{%load static%}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="w-full px-5 s:px-9 mb-5">
|
||||||
|
<div class="w-full bg-white h-fit shadow-md rounded-md p-5">
|
||||||
|
<h1 class="text-3xl text-secondosiblue text-center font-semibold">
|
||||||
|
Create Milestone For {{project.name}}
|
||||||
|
</h1>
|
||||||
|
<form class="mx-auto w-full flex flex-col gap-5 justify-center items-center mt-5" method="POST"
|
||||||
|
action="{% url 'addmilestone' project.project_id %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="w-full">
|
||||||
|
<label class="text-gray-500">Name:</label>
|
||||||
|
<input required name="name" type="text"
|
||||||
|
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md mt-1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full">
|
||||||
|
<label class="text-gray-500">Description:</label>
|
||||||
|
<textarea required name="description" type="text" placeholder="Description..." rows="5" cols="5"
|
||||||
|
class="w-full py-3 px-3 border border-gray-300 outline-none rounded-md resize-none mt-1"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full">
|
||||||
|
<label class="text-gray-500">Start Date:</label>
|
||||||
|
<input required name="start_date" type="date" id="date" name="date"
|
||||||
|
class="w-full p-3 border border-gray-300 rounded-md bg-transparent outline-none mt-1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full">
|
||||||
|
<label class="text-gray-500">End Date:</label>
|
||||||
|
<input required name="end_date" type="date" id="date" name="date"
|
||||||
|
class="w-full p-3 border border-gray-300 rounded-md bg-transparent outline-none mt-1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full flex justify-center items-center mt-3">
|
||||||
|
<button type="submit"
|
||||||
|
class="w-fit py-1 px-5 bg-osiblue rounded-md outline-none text-white border border-osiblue text-xl cursor-pointer hover:bg-white hover:text-osiblue duration-300">Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock content %}
|
@ -0,0 +1,180 @@
|
|||||||
|
{% extends "main.html" %}
|
||||||
|
{%load static%}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="w-full xxlg1:w-[75%] bg-white h-fit rounded-md shadow-md p-5">
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="w-full rounded-md flex flex-col justify-center items-center py-3 bg-osiblue bg-opacity-70">
|
||||||
|
<h1 class="text-xl md:text-3xl text-white font-semibold text-center">{{milestone.name}}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="w-full flex flex-col gap-5 mt-5">
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-500 text-xl">Project: <a href="{% url 'detailed-project' milestone.project.project_id %}"
|
||||||
|
class="text-slate-800 text-xl font-semibold hover:text-secondosiblue duration-300">{{milestone.project.name}}</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-500 text-xl">Title: <span
|
||||||
|
class="text-slate-800 text-xl font-semibold">{{milestone.name}}</span></p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-500 text-xl">Description: <span
|
||||||
|
class="text-slate-800 text-xl font-semibold">{{milestone.description}}</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-500 text-xl">Start Date: <span
|
||||||
|
class="text-slate-800 text-xl font-semibold">{{milestone.start_date}}</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-500 text-xl">End Date: <span
|
||||||
|
class="text-slate-800 text-xl font-semibold">{{milestone.end_date}}</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- STORIES -->
|
||||||
|
<div class="mt-5 relative">
|
||||||
|
<div class="overflow-x-auto border border-gray-300 rounded-b-md mt-5 tableContainer">
|
||||||
|
<div
|
||||||
|
class=" bg-gray-200 rounded-t-md flex justify-between items-center text-white text-xl font-bold h-[50px]">
|
||||||
|
<div class="px-3">
|
||||||
|
<p class="text-secondosiblue uppercase font-bold">User Stories</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="h-full rounded-tr-md px-4 bg-secondosiblue text-gray-200 text-[18px] outline-none border-none cursor-pointer flex justify-center items-center addUserStoryButton"
|
||||||
|
data-modal-url="{% url 'addmilestoneuserstorymodal' milestone_id=milestone.id %}">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<table class="min-w-full divide-y">
|
||||||
|
<!-- TABLE HEADER -->
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th scope="col"
|
||||||
|
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||||
|
Story
|
||||||
|
</th>
|
||||||
|
<th scope="col"
|
||||||
|
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||||
|
Confirmed
|
||||||
|
</th>
|
||||||
|
<th scope="col"
|
||||||
|
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||||
|
Completed
|
||||||
|
</th>
|
||||||
|
<th scope="col"
|
||||||
|
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||||
|
Related Task
|
||||||
|
</th>
|
||||||
|
<th scope="col"
|
||||||
|
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase whitespace-nowrap">
|
||||||
|
Actions
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<!-- TABLE BODY -->
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
|
<!-- 1st row -->
|
||||||
|
{% if stories %}
|
||||||
|
{% for story in stories %}
|
||||||
|
<tr>
|
||||||
|
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||||
|
<p class="text-secondosiblue">{{story.content}}</p>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||||
|
<p class="text-secondosiblue">{{story.confirmed}}</p>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||||
|
<p class="text-secondosiblue">{{story.completed}}</p>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||||
|
{% if story.task_set.all %}
|
||||||
|
{% for task in story.task_set.all %}
|
||||||
|
<div class="w-full flex flex-col justify-center items-center gap-2">
|
||||||
|
<a class="text-gray-500 underline flex justify-center items-center gap-1 hover:text-secondosiblue duration-300 cursor-pointer"
|
||||||
|
href="{% url 'detailed-task' task.task_id %}">{{task.name}}
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'adduserstorytask' milestone.project.project_id story.id %}">
|
||||||
|
<div
|
||||||
|
class="w-[30px] h-[30px] rounded-full shadow-md bg-gray-50 text-secondosiblue border border-gray-100 flex justify-center items-center hover:bg-secondosiblue hover:text-gray-50 duration-300">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M12 4.5v15m7.5-7.5h-15" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<div class="w-full flex flex-col justify-center items-center gap-2">
|
||||||
|
<p class="text-secondosiblue">Add Task</p>
|
||||||
|
<a href="{% url 'adduserstorytask' milestone.project.project_id story.id %}">
|
||||||
|
<div
|
||||||
|
class="w-[30px] h-[30px] rounded-full shadow-md bg-gray-50 text-secondosiblue border border-gray-100 flex justify-center items-center hover:bg-secondosiblue hover:text-gray-50 duration-300">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M12 4.5v15m7.5-7.5h-15" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
<td class="px-6 py-4 text-center text-sm">
|
||||||
|
<div class="w-full flex justify-center items-center gap-3">
|
||||||
|
<a data-modal-url="{% url 'edituserstorymodal' story.id %}" class="addUserStoryButton">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5" stroke="currentColor"
|
||||||
|
class="w-[18px] text-fifthosiblue hover:scale-110 duration-500 transition-transform">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<div class="cursor-pointer" data-modal-url="">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5" stroke="currentColor"
|
||||||
|
class="w-[18px] text-red-500 hover:scale-110 duration-500 transition-transform">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" class="px-6 py-4 text-center text-sm text-secondosiblue">
|
||||||
|
No Stories at the moment
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %}
|
@ -0,0 +1,57 @@
|
|||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Osina</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href='{% static "dist/output.css" %}'>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="font-poppinsLight">
|
||||||
|
<form method="POST" action="{% url 'edituserstorymodal' story.id %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<h1 class="text-secondosiblue text-2xl font-semibold text-center">Edit User Story</h1>
|
||||||
|
|
||||||
|
{% if not milestone %}
|
||||||
|
<div class="w-full">
|
||||||
|
<label class="text-gray-500">Milestone:</label>
|
||||||
|
<select required name="milestone" id=""
|
||||||
|
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md text-gray-500 mt-1">
|
||||||
|
{% for milestone in milestones %}
|
||||||
|
<option {% if story.milestone.id == milestone.id %} selected {% endif %} value="{{milestone.id}}">{{milestone.name}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="w-full flex justify-center items-center">
|
||||||
|
<input name="content" type="text" placeholder="User Story"
|
||||||
|
class="w-full p-3 border border-gray-300 rounded-md bg-transparent outline-none mt-4" value="{{story.content}}"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="w-full flex justify-start items-center gap-2 mt-4">
|
||||||
|
<input name="completed" type="checkbox" {% if story.completed %}checked{% endif %}>
|
||||||
|
<p class="text-gray-500">Completed</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full flex justify-start items-center gap-2 mt-4">
|
||||||
|
<input name="confirmed" type="checkbox" {% if story.confirmed %}checked{% endif %}>
|
||||||
|
<p class="text-gray-500">Confirmed</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="w-full flex justify-center items-center mt-4">
|
||||||
|
<button type="submit"
|
||||||
|
class="w-fit bg-osiblue border border-osiblue rounded-md text-white text-xl px-5 py-1 hover:bg-white hover:text-osiblue duration-300">Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,18 +0,0 @@
|
|||||||
const addReqButton = document.getElementById("addReqButton");
|
|
||||||
const addReqContainerTemplate = document.getElementById("addReqContainerTemplate");
|
|
||||||
const addReqContainer = document.getElementById("addReqContainer");
|
|
||||||
|
|
||||||
addReqButton.addEventListener("click", function () {
|
|
||||||
// Clone the template and remove the "hidden" class
|
|
||||||
const newContainer = addReqContainerTemplate.cloneNode(true);
|
|
||||||
newContainer.classList.remove("hidden");
|
|
||||||
|
|
||||||
// Add an event listener to the new container's remove button
|
|
||||||
const removeReqButton = newContainer.querySelector("#removeReqButton");
|
|
||||||
removeReqButton.addEventListener("click", function () {
|
|
||||||
// Remove the clicked container when the remove button is clicked
|
|
||||||
newContainer.remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
addReqContainer.appendChild(newContainer);
|
|
||||||
});
|
|
Loading…
Reference in New Issue