Browse Source

Corrections diverses

olivier.massot 7 years ago
parent
commit
ac66bf8216

+ 1 - 0
main/forms.py

@@ -22,6 +22,7 @@ class StoryForm(forms.ModelForm):
  
     class Meta:
         model = Story
+        widgets = {'epic': forms.HiddenInput()}
         fields = ('epic', 'name', 'description', 'assignees', 'sprints')
         
     def __init__(self, *args, **kwargs):

+ 97 - 0
main/migrations/0003_auto_20181001_1721.py

@@ -0,0 +1,97 @@
+# Generated by Django 2.1.1 on 2018-10-01 15:21
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import martor.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('main', '0002_auto_20180928_1106'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='epic',
+            options={'ordering': ('-value',), 'verbose_name': 'epic', 'verbose_name_plural': 'epics'},
+        ),
+        migrations.AlterModelOptions(
+            name='project',
+            options={'verbose_name': 'projet', 'verbose_name_plural': 'projets'},
+        ),
+        migrations.AlterModelOptions(
+            name='sprint',
+            options={'ordering': ('date_start',), 'verbose_name_plural': 'sprints'},
+        ),
+        migrations.AlterModelOptions(
+            name='story',
+            options={'ordering': ('closed', '-updated'), 'verbose_name': 'story', 'verbose_name_plural': 'stories'},
+        ),
+        migrations.AddField(
+            model_name='epic',
+            name='closed',
+            field=models.BooleanField(default=False, verbose_name='Clôturée'),
+        ),
+        migrations.AlterField(
+            model_name='epic',
+            name='description',
+            field=models.TextField(blank=True, default='', verbose_name='Description'),
+        ),
+        migrations.AlterField(
+            model_name='epic',
+            name='name',
+            field=models.CharField(default='', max_length=200, verbose_name='Nom'),
+        ),
+        migrations.AlterField(
+            model_name='epic',
+            name='project',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='main.Project', verbose_name='Projet'),
+        ),
+        migrations.AlterField(
+            model_name='epic',
+            name='size',
+            field=models.CharField(choices=[('XXS', 'XXS (< 1 sprints)'), ('XS', 'XS (1 sprint)'), ('S', 'S (1-2 sprints)'), ('M', 'M (2-3 sprints)'), ('L', 'L (3-4 sprints)'), ('XL', 'XL (4-6 sprints)'), ('XXL', 'XXL  (> 6 sprints)')], default='M', max_length=10, verbose_name='Taille'),
+        ),
+        migrations.AlterField(
+            model_name='epic',
+            name='value',
+            field=models.IntegerField(default=0, verbose_name='Valeur'),
+        ),
+        migrations.AlterField(
+            model_name='story',
+            name='assignees',
+            field=models.ManyToManyField(related_name='assigned', to=settings.AUTH_USER_MODEL, verbose_name='Assignés'),
+        ),
+        migrations.AlterField(
+            model_name='story',
+            name='author',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='stories', related_query_name='story', to=settings.AUTH_USER_MODEL, verbose_name='Auteur'),
+        ),
+        migrations.AlterField(
+            model_name='story',
+            name='closed',
+            field=models.BooleanField(default=False, verbose_name='Clôturée'),
+        ),
+        migrations.AlterField(
+            model_name='story',
+            name='description',
+            field=martor.models.MartorField(verbose_name='Description'),
+        ),
+        migrations.AlterField(
+            model_name='story',
+            name='epic',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='stories', to='main.Epic', verbose_name='Epic'),
+        ),
+        migrations.AlterField(
+            model_name='story',
+            name='name',
+            field=models.CharField(default='', max_length=200, verbose_name='Nom'),
+        ),
+        migrations.AlterField(
+            model_name='story',
+            name='sprints',
+            field=models.ManyToManyField(related_name='stories', related_query_name='story', to='main.Sprint', verbose_name='Sprints'),
+        ),
+    ]

+ 8 - 1
main/models.py

@@ -51,10 +51,17 @@ class Epic(BaseModel):
     value = models.IntegerField(default=0, verbose_name="Valeur")
     description = models.TextField(default="", blank=True, verbose_name="Description")
     project = models.ForeignKey(Project, on_delete=models.PROTECT, null=True, verbose_name="Projet")
+    closed = models.BooleanField(default=False, verbose_name="Clôturée")
     
     def __str__(self):
         return self.name
     
+    def nb_stories(self):
+        return len(self.stories.all())
+    
+    def nb_closed_stories(self):
+        return len(self.stories.filter(closed=True))
+    
 class Sprint(BaseModel):
     class Meta:
         verbose_name_plural = "sprint"
@@ -70,7 +77,7 @@ class Story(BaseModel):
     class Meta:
         verbose_name = "story"
         verbose_name_plural = "stories"
-        ordering = ('-updated', )
+        ordering = ('closed', '-updated')
     epic = models.ForeignKey(Epic, on_delete=models.PROTECT, null=True, related_name="stories", verbose_name="Epic")
     name = models.CharField(max_length=200, default="", verbose_name="Nom")
     description = MartorField(verbose_name="Description")

+ 8 - 1
main/static/css/custom.css

@@ -106,4 +106,11 @@ select[multiple] {
 
 .issue-title a:hover {
 	text-decoration: underline;
-}
+}
+
+/* Epic details */
+
+.story-closed {
+	text-decoration: line-through #666666 !important;
+	color: #666666 !important;
+}

+ 1 - 1
main/templates/_layout.html

@@ -58,7 +58,7 @@
 		<nav id="menu">
 			<ul class="links">
 				<li><a href="{% url 'index' %}">Accueil</a></li>
-				<li><a href="">Projets</a></li>
+				<li><a href="">Rapports</a></li>
 				<li><a href="{% url 'admin:index' %}">Administration</a></li>
 			</ul>
 			<ul class="actions vertical">

+ 9 - 5
main/templates/epic_details.html

@@ -8,8 +8,8 @@
 			<h2 class="flex-extend">{{ epic.name }}</h2>
 		
 			<ul class="actions small">
-				<li><a class="button special icon fa-edit tool-btn" href="{% url 'epic_edit' epic_id=epic.id %}"></a></li>
-				<li><a class="button icon fa-trash tool-btn" href="{% url 'epic_delete' epic_id=epic.id %}"></a></li>
+				<li><a class="button special icon fa-edit tool-btn" href="{% url 'epic_edit' epic_id=epic.id %}" title="Modifier"></a></li>
+				<!-- <li><a class="button icon fa-trash tool-btn" href="{% url 'epic_delete' epic_id=epic.id %}"></a></li> -->
 			</ul>
 		</div>
 		
@@ -24,7 +24,7 @@
 	
 	<div class="flex-row">
 		<h4 class="flex-extend">Stories</h4>
-		<a class="button special icon fa-plus tool-btn" href="{% url 'story_create' epic_id=epic.id %}"></a>
+		<a class="button special icon fa-plus tool-btn" href="{% url 'story_create' epic_id=epic.id %}" title="Créer une nouvelle Story"></a>
 	</div>
 	
 	{% if epic.stories.count %}
@@ -35,7 +35,11 @@
 		    	<div class="issue-frame flex-row">
 		    		<div class="issue-frame-left flex-extend">
 		    			<div class="issue-title">
-		        			<a href="{% url 'story_details' story_id=story.id %}">{{ story.name }}</a>
+		    			{% if story.closed %}
+		        			<a href="{% url 'story_details' story_id=story.id %}" class="story-closed"> {{ story.name }} </a>
+		        		{% else %}
+		        			<a href="{% url 'story_details' story_id=story.id %}"> {{ story.name }} </a>
+		        		{% endif %}
 		        		</div>
 		        		<div class="issue-infos">
 		        			<span class="annotation">Créée le {{ story.created }}, par {{ story.author.username }}</span>
@@ -45,7 +49,7 @@
 		        		<ul class="controls">
 		        		<!-- Icone commentaires ici -->
 		        		</ul>
-		        		<div class="annotation issue-last-update">Modifié le {{ story.updated }}</div>
+		        		<div class="annotation issue-last-update">Dernière mise à jour le {{ story.updated }}</div>
 		        	</div>
 		        </div>
 		    </li>

+ 2 - 3
main/templates/index.html

@@ -18,7 +18,7 @@
 		<th>Projet</th>
 		<th>Dim.</th>
 		<th>Val.</th>
-		<th>Stories</th>
+		<th>Prog.</th>
 	
 	</thead>
 	
@@ -30,11 +30,10 @@
 			<td>{{ epic.project.name }}</td>
 			<td>{{ epic.size }}</td>
 			<td>{{ epic.value }}</td>
-			<td>{{ epic.stories.count }}</td>
+			<td>{{ epic.nb_closed_stories }} / {{ epic.nb_stories }}</td>
 		</tr>
 		{% endfor %}
 	
-	
 	</tbody>
 
 </table>

+ 13 - 3
main/templates/story_details.html

@@ -9,11 +9,21 @@
 			<blockquote class="annotation">Créée par {{ story.author.get_full_name }}, le {{ story.created }}</blockquote>
 		</div>
 		<div class="flex-row">
-			<h2 class="flex-extend">{{ story.name }}</h2>
 		
+			{% if story.closed %}
+				<h2 class="flex-extend" style="color: grey;">[Terminée] {{ story.name }}</h2>
+			{% else %}
+				<h2 class="flex-extend">{{ story.name }}</h2>
+			{% endif %}
+			
 			<ul class="actions small">
-				<li><a class="button special icon fa-edit tool-btn" href="{% url 'story_edit' story_id=story.id %}"></a></li>
-				<li><a class="button icon fa-trash tool-btn" href="{% url 'story_delete' story_id=story.id %}"></a></li>
+				{% if story.closed %}
+					<li><a class="button alt icon fa-folder-open tool-btn" href="{% url 'story_reopen' story_id=story.id %}" title="Ré-ouvrir">Ré-ouvrir</a></li>
+				{% else %}
+					<li><a class="button special icon fa-check tool-btn" href="{% url 'story_close' story_id=story.id %}" title="Marquer comme terminée">Cloturer</a></li>
+				{% endif %}
+				<li><a class="button special icon fa-edit tool-btn" href="{% url 'story_edit' story_id=story.id %}" title="Modifier"></a></li>
+				<!-- <li><a class="button icon fa-trash tool-btn" href="{% url 'story_delete' story_id=story.id %}" title="Supprimer"></a></li> -->
 			</ul>
 		</div>
 	</header>

+ 2 - 0
main/urls.py

@@ -15,6 +15,8 @@ urlpatterns = [
     path('stories/create/<int:epic_id>/', views.story_create, name='story_create'),
     path('stories/edit/<int:story_id>/', views.story_edit, name='story_edit'),
     path('stories/delete/<int:story_id>/', views.story_delete, name='story_delete'),
+    path('stories/close/<int:story_id>/', views.story_close, name='story_close'),
+    path('stories/reopen/<int:story_id>/', views.story_reopen, name='story_reopen'),
     path('epics/<int:epic_id>', views.epic_details, name='epic_details'),
     path('epics/create/', views.epic_create, name='epic_create'),
     path('epics/edit/<int:epic_id>/', views.epic_edit, name='epic_edit'),

+ 15 - 3
main/views.py

@@ -6,7 +6,7 @@ from main.models import Story, Epic
 
 
 def index(request):
-    epics = Epic.objects.all()
+    epics = Epic.objects.filter(closed=False)
     return render(request, 'index.html', {'epics': epics})
 
 def story_index(request):
@@ -50,13 +50,25 @@ def story_edit(request, story_id):
 
 def story_delete(request, story_id):
     if request.method == 'POST':
-        story = Story.objects.get(id=story_id)
+        story = get_object_or_404(Story, id=story_id)
         story.delete()
         return redirect("index")
     else:
-        story = Story.objects.get(id=story_id)
+        story = get_object_or_404(Story, id=story_id)
         return render(request, 'deletion.html', {'object': story})
     
+def story_close(request, story_id):
+    story = get_object_or_404(Story, id=story_id)
+    story.closed = True
+    story.save()
+    return render(request, 'epic_details.html', {'epic': story.epic})
+
+def story_reopen(request, story_id):
+    story = get_object_or_404(Story, id=story_id)
+    story.closed = False
+    story.save()
+    return render(request, 'story_details.html', {'story': story})
+
 def epic_details(request, epic_id):
     epic = get_object_or_404(Epic, id=epic_id)
     return render(request, 'epic_details.html', {'epic': epic})