Version 0.1.0 0.1.0
authorThierry Florac <thierry.florac@onf.fr>
Wed, 17 Jun 2015 10:02:06 +0200
changeset 11 f25326715002
parent 10 41ac20351fe2
child 12 ab8948c2b00b
Version 0.1.0
.installed.cfg
buildout.cfg
setup.py
src/pyams_workflow.egg-info/SOURCES.txt
src/pyams_workflow.egg-info/entry_points.txt
src/pyams_workflow/__init__.py
src/pyams_workflow/content.py
src/pyams_workflow/interfaces/__init__.py
src/pyams_workflow/locales/fr/LC_MESSAGES/pyams_workflow.mo
src/pyams_workflow/locales/fr/LC_MESSAGES/pyams_workflow.po
src/pyams_workflow/locales/pyams_workflow.pot
src/pyams_workflow/resources/js/workflow.js
src/pyams_workflow/versions.py
src/pyams_workflow/workflow.py
src/pyams_workflow/zmi/transition.py
src/pyams_workflow/zmi/versions.py
src/pyams_workflow/zmi/viewlet/__init__.py
src/pyams_workflow/zmi/viewlet/templates/versions.pt
src/pyams_workflow/zmi/viewlet/versions.py
src/pyams_workflow/zmi/workflow.py
--- a/.installed.cfg	Wed May 20 14:57:49 2015 +0200
+++ b/.installed.cfg	Wed Jun 17 10:02:06 2015 +0200
@@ -1,16 +1,19 @@
 [buildout]
-installed_develop_eggs = /home/tflorac/Dropbox/src/PyAMS/pyams_workflow/develop-eggs/pyams-security.egg-link
+installed_develop_eggs = /home/tflorac/Dropbox/src/PyAMS/pyams_workflow/develop-eggs/pyams-file.egg-link
+	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/develop-eggs/pyams-security.egg-link
+	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/develop-eggs/pyams-i18n.egg-link
+	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/develop-eggs/pyams-catalog.egg-link
 parts = package i18n pyflakes test
 
 [package]
 __buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/pyams_upgrade
+	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/pcreate
+	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/proutes
 	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/pshell
-	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/pserve
-	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/prequest
-	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/proutes
-	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/pcreate
 	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/pdistreport
 	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/ptweens
+	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/prequest
+	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/pserve
 	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/pviews
 __buildout_signature__ = zc.recipe.egg-2.0.1-py3.4.egg setuptools-14.0-py3.4.egg zc.buildout-2.3.1-py3.4.egg
 _b = /home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin
@@ -66,7 +69,7 @@
 [test]
 __buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_workflow/parts/test
 	/home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin/test
-__buildout_signature__ = zc.recipe.testrunner-2.0.0-py3.4.egg zc.recipe.egg-2.0.1-py3.4.egg setuptools-14.0-py3.4.egg zope.testrunner-4.4.6-py3.4.egg zc.buildout-2.3.1-py3.4.egg zope.interface-4.1.2-py3.4-linux-x86_64.egg zope.exceptions-4.0.7-py3.4.egg six-1482e89f68d85eea27f4ed7749df2819
+__buildout_signature__ = zc.recipe.testrunner-2.0.0-py3.4.egg zc.recipe.egg-2.0.1-py3.4.egg setuptools-14.0-py3.4.egg zope.testrunner-4.4.6-py3.4.egg zc.buildout-2.3.1-py3.4.egg zope.interface-4.1.2-py3.4-linux-x86_64.egg zope.exceptions-4.0.7-py3.4.egg six-e6b62e54b4df360c40dfcbb76c1ecf1a
 _b = /home/tflorac/Dropbox/src/PyAMS/pyams_workflow/bin
 _d = /home/tflorac/Dropbox/src/PyAMS/pyams_workflow/develop-eggs
 _e = /var/local/env/pyams/eggs
--- a/buildout.cfg	Wed May 20 14:57:49 2015 +0200
+++ b/buildout.cfg	Wed Jun 17 10:02:06 2015 +0200
@@ -17,17 +17,21 @@
 #allow-picked-versions = false
 
 src = src
-develop = .
-          ../pyams_form
-          ../pyams_mail
-          ../pyams_pagelet
-          ../pyams_security
-          ../pyams_skin
-          ../pyams_template
-          ../pyams_utils
-          ../pyams_viewlet
-          ../pyams_zmi
-          ../pyams_zmq
+develop =
+    .
+    ../pyams_catalog
+    ../pyams_file
+    ../pyams_form
+    ../pyams_i18n
+    ../pyams_mail
+    ../pyams_pagelet
+    ../pyams_security
+    ../pyams_skin
+    ../pyams_template
+    ../pyams_utils
+    ../pyams_viewlet
+    ../pyams_zmi
+    ../pyams_zmq
 
 parts =
     package
--- a/setup.py	Wed May 20 14:57:49 2015 +0200
+++ b/setup.py	Wed Jun 17 10:02:06 2015 +0200
@@ -68,7 +68,8 @@
           'zope.copy',
           'zope.interface',
       ],
-      entry_points="""
-      # -*- Entry points: -*-
-      """,
-      )
+      entry_points={
+          'fanstatic.libraries': [
+              'pyams_workflow = pyams_workflow:library'
+          ]
+      })
--- a/src/pyams_workflow.egg-info/SOURCES.txt	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow.egg-info/SOURCES.txt	Wed Jun 17 10:02:06 2015 +0200
@@ -3,7 +3,6 @@
 docs/HISTORY.txt
 docs/README.txt
 src/pyams_workflow/__init__.py
-src/pyams_workflow/configure.zcml
 src/pyams_workflow/content.py
 src/pyams_workflow/include.py
 src/pyams_workflow/versions.py
@@ -18,9 +17,19 @@
 src/pyams_workflow.egg-info/top_level.txt
 src/pyams_workflow/doctests/README.txt
 src/pyams_workflow/interfaces/__init__.py
+src/pyams_workflow/locales/pyams_workflow.pot
+src/pyams_workflow/locales/fr/LC_MESSAGES/pyams_workflow.mo
+src/pyams_workflow/locales/fr/LC_MESSAGES/pyams_workflow.po
+src/pyams_workflow/resources/js/workflow.js
+src/pyams_workflow/resources/js/workflow.min.js
 src/pyams_workflow/tests/__init__.py
 src/pyams_workflow/tests/test_utilsdocs.py
 src/pyams_workflow/tests/test_utilsdocstrings.py
 src/pyams_workflow/zmi/__init__.py
 src/pyams_workflow/zmi/interfaces.py
-src/pyams_workflow/zmi/workflow.py
\ No newline at end of file
+src/pyams_workflow/zmi/transition.py
+src/pyams_workflow/zmi/versions.py
+src/pyams_workflow/zmi/workflow.py
+src/pyams_workflow/zmi/viewlet/__init__.py
+src/pyams_workflow/zmi/viewlet/versions.py
+src/pyams_workflow/zmi/viewlet/templates/versions.pt
\ No newline at end of file
--- a/src/pyams_workflow.egg-info/entry_points.txt	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow.egg-info/entry_points.txt	Wed Jun 17 10:02:06 2015 +0200
@@ -1,3 +1,3 @@
+[fanstatic.libraries]
+pyams_workflow = pyams_workflow:library
 
-      # -*- Entry points: -*-
-      
\ No newline at end of file
--- a/src/pyams_workflow/__init__.py	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/__init__.py	Wed Jun 17 10:02:06 2015 +0200
@@ -13,6 +13,9 @@
 __docformat__ = 'restructuredtext'
 
 
+from fanstatic import Library
+library = Library('pyams_workflow', 'resources')
+
 from pyramid.i18n import TranslationStringFactory
 _ = TranslationStringFactory('pyams_workflow')
 
--- a/src/pyams_workflow/content.py	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/content.py	Wed Jun 17 10:02:06 2015 +0200
@@ -17,7 +17,6 @@
 from datetime import datetime
 
 # import interfaces
-from pyams_security.interfaces import IPrincipalInfo
 from pyams_workflow.interfaces import IWorkflowManagedContent, IWorkflowPublicationInfo, IWorkflow, IWorkflowVersions, \
     IWorkflowPublicationSupport, IObjectClonedEvent, IWorkflowState
 from zope.annotation.interfaces import IAnnotations
@@ -45,32 +44,12 @@
 class WorkflowContentPublicationInfo(Persistent, Contained):
     """Workflow content info"""
 
-    _state_date = FieldProperty(IWorkflowPublicationInfo['state_date'])
-    _state_principal = FieldProperty(IWorkflowPublicationInfo['state_principal'])
     _publication_date = FieldProperty(IWorkflowPublicationInfo['publication_date'])
     _first_publication_date = FieldProperty(IWorkflowPublicationInfo['first_publication_date'])
     _publication_effective_date = FieldProperty(IWorkflowPublicationInfo['publication_effective_date'])
     _publication_expiration_date = FieldProperty(IWorkflowPublicationInfo['publication_expiration_date'])
 
     @property
-    def state_date(self):
-        return self._state_date
-
-    @state_date.setter
-    def state_date(self, value):
-        self._state_date = gmtime(value)
-
-    @property
-    def state_principal(self):
-        return self._state_principal
-
-    @state_principal.setter
-    def state_principal(self, value):
-        if IPrincipalInfo.providedBy(value):
-            value = value.id
-        self._state_principal = value
-
-    @property
     def publication_date(self):
         return self._publication_date
 
--- a/src/pyams_workflow/interfaces/__init__.py	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/interfaces/__init__.py	Wed Jun 17 10:02:06 2015 +0200
@@ -77,6 +77,8 @@
 class IWorkflowTransitionEvent(IObjectEvent):
     """Workflow transition event interface"""
 
+    wokflow = Attribute("Workflow utility")
+
     source = Attribute('Original state or None if initial state')
 
     destination = Attribute('New state')
@@ -90,8 +92,9 @@
 class WorkflowTransitionEvent(ObjectEvent):
     """Workflow transition event"""
 
-    def __init__(self, object, source, destination, transition, comment):
+    def __init__(self, object, workflow, source, destination, transition, comment):
         super(WorkflowTransitionEvent, self).__init__(object)
+        self.workflow = workflow
         self.source = source
         self.destination = destination
         self.transition = transition
@@ -108,8 +111,8 @@
 class WorkflowVersionTransitionEvent(WorkflowTransitionEvent):
     """Workflow version transition event"""
 
-    def __init__(self, object, old_object, source, destination, transition, comment):
-        super(WorkflowVersionTransitionEvent, self).__init__(object, source, destination, transition, comment)
+    def __init__(self, object, workflow, old_object, source, destination, transition, comment):
+        super(WorkflowVersionTransitionEvent, self).__init__(object, workflow, source, destination, transition, comment)
         self.old_object = old_object
 
 
@@ -145,6 +148,9 @@
     def refresh(self, transitions):
         """Refresh workflow completely with new transitions."""
 
+    def get_state_label(self, state):
+        """Get given state label"""
+
     def get_transitions(self, source):
         """Get all transitions from source"""
 
@@ -265,9 +271,15 @@
     Defined as an adapter.
     """
 
-    version_id = Attribute("Version ID")
+    version_id = Int(title=_("Version ID"))
+
+    state = TextLine(title=_("Version state"))
 
-    state = Attribute("Version state")
+    state_date = Datetime(title=_("State date"),
+                          description=_("Date at which the current state was applied"))
+
+    state_principal = Principal(title=_("State principal"),
+                                description=_("ID of the principal which defined current state"))
 
     history = List(title="Workflow states history",
                    value_type=Object(schema=IWorkflowStateHistoryItem))
@@ -296,7 +308,7 @@
     def has_version(self, state):
         """Return true if a version exists with the specific workflow state"""
 
-    def remove_version(self, version_id):
+    def remove_version(self, version_id, state='deleted', comment=None):
         """Remove version with given ID"""
 
 
@@ -334,13 +346,6 @@
 class IWorkflowPublicationInfo(Interface):
     """Workflow content publication info"""
 
-    state_date = Datetime(title=_("State date"),
-                          description=_("Date at which the current state was applied"),
-                          readonly=True)
-
-    state_principal = Principal(title=_("State principal"),
-                                description=_("ID of the principal which defined current state"))
-
     publication_date = Datetime(title=_("Publication date"),
                                 description=_("Last date at which content was accepted for publication"),
                                 required=False)
Binary file src/pyams_workflow/locales/fr/LC_MESSAGES/pyams_workflow.mo has changed
--- a/src/pyams_workflow/locales/fr/LC_MESSAGES/pyams_workflow.po	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/locales/fr/LC_MESSAGES/pyams_workflow.po	Wed Jun 17 10:02:06 2015 +0200
@@ -5,7 +5,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2015-05-12 11:59+0200\n"
+"POT-Creation-Date: 2015-06-02 10:29+0200\n"
 "PO-Revision-Date: 2015-05-12 11:59+0200\n"
 "Last-Translator: Thierry Florac <tflorac@ulthar.net>\n"
 "Language-Team: French <traduc@traduc.org>\n"
@@ -16,131 +16,156 @@
 "Generated-By: Lingua 3.8\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 
-#: src/pyams_workflow/content.py:176
+#: src/pyams_workflow/content.py:155
 #, python-format
 msgid "Clone created from version {source}"
 msgstr "Duplication de la version {source}"
 
-#: src/pyams_workflow/zmi/workflow.py:57
+#: src/pyams_workflow/zmi/workflow.py:66
 msgid "Change status..."
-msgstr "Modifier le statut..."
+msgstr "Agir sur le statut..."
+
+#: src/pyams_workflow/zmi/workflow.py:111
+msgid "Older versions"
+msgstr "Versions plus anciennes"
 
-#: src/pyams_workflow/zmi/versions.py:51
+#: src/pyams_workflow/zmi/workflow.py:132
+#: src/pyams_workflow/zmi/workflow.py:104
+#, python-format
+msgid "Version {version} ({state} - last update {date})"
+msgstr "Version {version} ({state} - dernière modification {date})"
+
+#: src/pyams_workflow/zmi/versions.py:49
 msgid "Version history..."
 msgstr "Historique de la version..."
 
-#: src/pyams_workflow/zmi/versions.py:105
+#: src/pyams_workflow/zmi/versions.py:99
 msgid "Date"
 msgstr "Date"
 
-#: src/pyams_workflow/zmi/versions.py:117
+#: src/pyams_workflow/zmi/versions.py:111
 msgid "Principal"
 msgstr "Utilisateur"
 
-#: src/pyams_workflow/zmi/versions.py:133
-msgid "Transition"
-msgstr "Opération"
-
-#: src/pyams_workflow/zmi/versions.py:142
+#: src/pyams_workflow/zmi/versions.py:127
 msgid "Source"
 msgstr "Source"
 
-#: src/pyams_workflow/zmi/versions.py:163
+#: src/pyams_workflow/zmi/versions.py:146
+msgid "Transition"
+msgstr "Opération"
+
+#: src/pyams_workflow/zmi/versions.py:155
 msgid "Target state"
 msgstr "Nouveau statut"
 
-#: src/pyams_workflow/zmi/versions.py:177
-#: src/pyams_workflow/interfaces/__init__.py:381
+#: src/pyams_workflow/zmi/versions.py:164
+#: src/pyams_workflow/interfaces/__init__.py:383
 msgid "Comment"
 msgstr "Commentaire"
 
-#: src/pyams_workflow/zmi/versions.py:76
+#: src/pyams_workflow/zmi/versions.py:70
 #, python-format
 msgid "Version {version} history"
 msgstr "Historique de la version {version}"
 
-#: src/pyams_workflow/zmi/versions.py:150
-#: src/pyams_workflow/zmi/versions.py:154
+#: src/pyams_workflow/zmi/versions.py:133
+#: src/pyams_workflow/zmi/versions.py:137
 #, python-format
 msgid "Version {version} ({status})"
 msgstr "Version {version} ({status})"
 
-#: src/pyams_workflow/interfaces/__init__.py:308
+#: src/pyams_workflow/zmi/viewlet/templates/versions.pt:5
+#: src/pyams_workflow/zmi/viewlet/templates/versions.pt:25
+msgid "Version ${version} - ${state}"
+msgstr "Version ${version} - ${state}"
+
+#: src/pyams_workflow/interfaces/__init__.py:271
+msgid "Version ID"
+msgstr "N° de version"
+
+#: src/pyams_workflow/interfaces/__init__.py:273
+msgid "Version state"
+msgstr "Statut actuel"
+
+#: src/pyams_workflow/interfaces/__init__.py:275
+msgid "State date"
+msgstr "Date du statut"
+
+#: src/pyams_workflow/interfaces/__init__.py:276
+msgid "Date at which the current state was applied"
+msgstr "Date à laquelle le changement d'état a été effectué"
+
+#: src/pyams_workflow/interfaces/__init__.py:278
+msgid "State principal"
+msgstr "Statut défini par"
+
+#: src/pyams_workflow/interfaces/__init__.py:279
+msgid "ID of the principal which defined current state"
+msgstr "Utilisateur ayant effectué défini ce statut"
+
+#: src/pyams_workflow/interfaces/__init__.py:317
 msgid "Workflow name"
 msgstr "Nom du workflow"
 
-#: src/pyams_workflow/interfaces/__init__.py:309
+#: src/pyams_workflow/interfaces/__init__.py:318
 msgid "Name of workflow utility managing this content"
 msgstr "Nom de l'outil de workflow gérant ce contenu"
 
-#: src/pyams_workflow/interfaces/__init__.py:313
+#: src/pyams_workflow/interfaces/__init__.py:322
 msgid "View permission"
 msgstr "Permission de consultation"
 
-#: src/pyams_workflow/interfaces/__init__.py:314
+#: src/pyams_workflow/interfaces/__init__.py:323
 msgid "This permission will be required to display content"
 msgstr "Cette permission sera nécessaire pour afficher le contenu"
 
-#: src/pyams_workflow/interfaces/__init__.py:330
+#: src/pyams_workflow/interfaces/__init__.py:339
 msgid "Transition ID"
 msgstr "ID de la transition"
 
-#: src/pyams_workflow/interfaces/__init__.py:337
-msgid "State date"
-msgstr "Date"
-
-#: src/pyams_workflow/interfaces/__init__.py:338
-msgid "Date at which the current state was applied"
-msgstr "Date à laquelle le changement d'état a été effectué"
-
-#: src/pyams_workflow/interfaces/__init__.py:341
-msgid "State principal"
-msgstr "Utilisateur"
-
-#: src/pyams_workflow/interfaces/__init__.py:342
-msgid "ID of the principal which defined current state"
-msgstr "ID d el'utilisateur ayant effectué l'opération"
-
-#: src/pyams_workflow/interfaces/__init__.py:344
+#: src/pyams_workflow/interfaces/__init__.py:346
 msgid "Publication date"
 msgstr "Date de publication"
 
-#: src/pyams_workflow/interfaces/__init__.py:345
+#: src/pyams_workflow/interfaces/__init__.py:347
 msgid "Last date at which content was accepted for publication"
 msgstr "Dernière date à laquelle le contenu a été accepté pour publication"
 
-#: src/pyams_workflow/interfaces/__init__.py:348
+#: src/pyams_workflow/interfaces/__init__.py:350
 msgid "First publication date"
 msgstr "Première date de publication"
 
-#: src/pyams_workflow/interfaces/__init__.py:349
+#: src/pyams_workflow/interfaces/__init__.py:351
 msgid "First date at which content was accepted for publication"
 msgstr "Première date à laquelle ce contenu a été accepté pour publication"
 
-#: src/pyams_workflow/interfaces/__init__.py:352
+#: src/pyams_workflow/interfaces/__init__.py:354
 msgid "Publication start date"
 msgstr "Début de publication"
 
-#: src/pyams_workflow/interfaces/__init__.py:353
+#: src/pyams_workflow/interfaces/__init__.py:355
 msgid "Date from which content will be visible"
 msgstr "Date à partir de laquelle ce contenu sera visible"
 
-#: src/pyams_workflow/interfaces/__init__.py:356
+#: src/pyams_workflow/interfaces/__init__.py:358
 msgid "Publication end date"
 msgstr "Fin de publication"
 
-#: src/pyams_workflow/interfaces/__init__.py:357
+#: src/pyams_workflow/interfaces/__init__.py:359
 msgid "Date past which content will not be visible"
 msgstr "Date à partir de laquelle ce contenu ne sera plus consultable"
 
-#: src/pyams_workflow/interfaces/__init__.py:382
+#: src/pyams_workflow/interfaces/__init__.py:384
 msgid "Comment associated with this operation"
 msgstr "Commentaire associé à cette opération"
 
-#: src/pyams_workflow/interfaces/__init__.py:364
+#: src/pyams_workflow/interfaces/__init__.py:366
 msgid "Can't define publication end date without publication start date!"
-msgstr "Impossible de définir une date de fin de publication sans date de début !"
+msgstr ""
+"Impossible de définir une date de fin de publication sans date de début !"
 
-#: src/pyams_workflow/interfaces/__init__.py:366
+#: src/pyams_workflow/interfaces/__init__.py:368
 msgid "Publication end date must be defined after publication start date!"
-msgstr "La date de fin de publication doit être postérieure à la date de début !"
+msgstr ""
+"La date de fin de publication doit être postérieure à la date de début !"
--- a/src/pyams_workflow/locales/pyams_workflow.pot	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/locales/pyams_workflow.pot	Wed Jun 17 10:02:06 2015 +0200
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2015-05-12 11:59+0200\n"
+"POT-Creation-Date: 2015-06-02 10:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,131 +16,154 @@
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: Lingua 3.8\n"
 
-#: ./src/pyams_workflow/content.py:176
+#: ./src/pyams_workflow/content.py:155
 #, python-format
 msgid "Clone created from version {source}"
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/workflow.py:57
+#: ./src/pyams_workflow/zmi/workflow.py:66
 msgid "Change status..."
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/versions.py:51
+#: ./src/pyams_workflow/zmi/workflow.py:111
+msgid "Older versions"
+msgstr ""
+
+#: ./src/pyams_workflow/zmi/workflow.py:132
+#: ./src/pyams_workflow/zmi/workflow.py:104
+#, python-format
+msgid "Version {version} ({state} - last update {date})"
+msgstr ""
+
+#: ./src/pyams_workflow/zmi/versions.py:49
 msgid "Version history..."
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/versions.py:105
+#: ./src/pyams_workflow/zmi/versions.py:99
 msgid "Date"
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/versions.py:117
+#: ./src/pyams_workflow/zmi/versions.py:111
 msgid "Principal"
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/versions.py:133
-msgid "Transition"
-msgstr ""
-
-#: ./src/pyams_workflow/zmi/versions.py:142
+#: ./src/pyams_workflow/zmi/versions.py:127
 msgid "Source"
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/versions.py:163
+#: ./src/pyams_workflow/zmi/versions.py:146
+msgid "Transition"
+msgstr ""
+
+#: ./src/pyams_workflow/zmi/versions.py:155
 msgid "Target state"
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/versions.py:177
-#: ./src/pyams_workflow/interfaces/__init__.py:381
+#: ./src/pyams_workflow/zmi/versions.py:164
+#: ./src/pyams_workflow/interfaces/__init__.py:383
 msgid "Comment"
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/versions.py:76
+#: ./src/pyams_workflow/zmi/versions.py:70
 #, python-format
 msgid "Version {version} history"
 msgstr ""
 
-#: ./src/pyams_workflow/zmi/versions.py:150
-#: ./src/pyams_workflow/zmi/versions.py:154
+#: ./src/pyams_workflow/zmi/versions.py:133
+#: ./src/pyams_workflow/zmi/versions.py:137
 #, python-format
 msgid "Version {version} ({status})"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:308
+#: ./src/pyams_workflow/zmi/viewlet/templates/versions.pt:5
+#: ./src/pyams_workflow/zmi/viewlet/templates/versions.pt:25
+msgid "Version ${version} - ${state}"
+msgstr ""
+
+#: ./src/pyams_workflow/interfaces/__init__.py:271
+msgid "Version ID"
+msgstr ""
+
+#: ./src/pyams_workflow/interfaces/__init__.py:273
+msgid "Version state"
+msgstr ""
+
+#: ./src/pyams_workflow/interfaces/__init__.py:275
+msgid "State date"
+msgstr ""
+
+#: ./src/pyams_workflow/interfaces/__init__.py:276
+msgid "Date at which the current state was applied"
+msgstr ""
+
+#: ./src/pyams_workflow/interfaces/__init__.py:278
+msgid "State principal"
+msgstr ""
+
+#: ./src/pyams_workflow/interfaces/__init__.py:279
+msgid "ID of the principal which defined current state"
+msgstr ""
+
+#: ./src/pyams_workflow/interfaces/__init__.py:317
 msgid "Workflow name"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:309
+#: ./src/pyams_workflow/interfaces/__init__.py:318
 msgid "Name of workflow utility managing this content"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:313
+#: ./src/pyams_workflow/interfaces/__init__.py:322
 msgid "View permission"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:314
+#: ./src/pyams_workflow/interfaces/__init__.py:323
 msgid "This permission will be required to display content"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:330
+#: ./src/pyams_workflow/interfaces/__init__.py:339
 msgid "Transition ID"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:337
-msgid "State date"
-msgstr ""
-
-#: ./src/pyams_workflow/interfaces/__init__.py:338
-msgid "Date at which the current state was applied"
-msgstr ""
-
-#: ./src/pyams_workflow/interfaces/__init__.py:341
-msgid "State principal"
-msgstr ""
-
-#: ./src/pyams_workflow/interfaces/__init__.py:342
-msgid "ID of the principal which defined current state"
-msgstr ""
-
-#: ./src/pyams_workflow/interfaces/__init__.py:344
+#: ./src/pyams_workflow/interfaces/__init__.py:346
 msgid "Publication date"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:345
+#: ./src/pyams_workflow/interfaces/__init__.py:347
 msgid "Last date at which content was accepted for publication"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:348
+#: ./src/pyams_workflow/interfaces/__init__.py:350
 msgid "First publication date"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:349
+#: ./src/pyams_workflow/interfaces/__init__.py:351
 msgid "First date at which content was accepted for publication"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:352
+#: ./src/pyams_workflow/interfaces/__init__.py:354
 msgid "Publication start date"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:353
+#: ./src/pyams_workflow/interfaces/__init__.py:355
 msgid "Date from which content will be visible"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:356
+#: ./src/pyams_workflow/interfaces/__init__.py:358
 msgid "Publication end date"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:357
+#: ./src/pyams_workflow/interfaces/__init__.py:359
 msgid "Date past which content will not be visible"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:382
+#: ./src/pyams_workflow/interfaces/__init__.py:384
 msgid "Comment associated with this operation"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:364
+#: ./src/pyams_workflow/interfaces/__init__.py:366
 msgid "Can't define publication end date without publication start date!"
 msgstr ""
 
-#: ./src/pyams_workflow/interfaces/__init__.py:366
+#: ./src/pyams_workflow/interfaces/__init__.py:368
 msgid "Publication end date must be defined after publication start date!"
 msgstr ""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_workflow/resources/js/workflow.js	Wed Jun 17 10:02:06 2015 +0200
@@ -0,0 +1,50 @@
+(function($) {
+
+	window.PyAMS_workflow = {
+
+		/**
+		 * Versions list management
+		 */
+		versions_list: {
+
+			switchVersions: function() {
+				return function() {
+					var versions = $(this).siblings('ul.versions');
+					if (versions.hasClass('hidden')) {
+						versions.removeClass('hidden');
+						$(this).removeClass('fa-caret-right')
+							   .addClass('fa-caret-down');
+					} else {
+						versions.addClass('hidden');
+						$(this).removeClass('fa-caret-down')
+							   .addClass('fa-caret-right');
+					}
+				}
+			},
+
+			switchAllVersions: function() {
+				return function() {
+					var link = $(this);
+					var versions = link.siblings('ul.old_versions');
+					if (versions.hasClass('hidden')) {
+						$('i', link).removeClass('fa-caret-right')
+									.addClass('fa-spin fa-gear');
+						var location = link.parents('[data-ams-location]').data('ams-location');
+						var element_name = link.parents('tr').data('ams-element-name');
+						MyAMS.skin.loadURL(location + '/get-old-versions.html?element_name=' + element_name, versions, {
+							afterLoadCallback: function() {
+								$('i', link).removeClass('fa-spin fa-gear')
+											.addClass('fa-caret-down');
+							}
+						});
+					} else {
+						versions.addClass('hidden');
+						$('i', link).removeClass('fa-caret-down')
+									.addClass('fa-caret-right');
+					}
+				}
+			}
+		}
+	};
+
+})(jQuery);
--- a/src/pyams_workflow/versions.py	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/versions.py	Wed Jun 17 10:02:06 2015 +0200
@@ -18,8 +18,9 @@
 
 # import interfaces
 from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowManagedContent, VersionError, IWorkflowState, \
-    IWorkflowVersion, IWorkflowStateHistoryItem, IWorkflowTransitionEvent, IWorkflowVersionTransitionEvent
+    IWorkflowVersion, IWorkflowStateHistoryItem, IWorkflowTransitionEvent, IWorkflowVersionTransitionEvent, IWorkflow
 from zope.annotation.interfaces import IAnnotations
+from zope.location.interfaces import ISublocations
 from zope.traversing.interfaces import ITraversable
 
 # import packages
@@ -27,7 +28,8 @@
 from persistent.list import PersistentList
 from persistent.mapping import PersistentMapping
 from pyams_utils.adapter import adapter_config, ContextAdapter
-from pyams_utils.request import check_request
+from pyams_utils.registry import get_utility
+from pyams_utils.request import check_request, query_request
 from pyams_utils.traversing import get_parent
 from pyramid.events import subscriber
 from pyramid.threadlocal import get_current_registry
@@ -60,22 +62,47 @@
     """Workflow managed content version object"""
 
     version_id = None
-    state = None
+    _state = None
+    _state_date = FieldProperty(IWorkflowState['state_date'])
+    _state_principal = FieldProperty(IWorkflowState['state_principal'])
 
     def __init__(self):
         self.history = PersistentList()
 
+    @property
+    def state(self):
+        return self._state
+
+    @state.setter
+    def state(self, value):
+        self._state = value
+        self._state_date = datetime.utcnow()
+        request = query_request()
+        if request is not None:
+            self._state_principal = request.principal.id
+
+    @property
+    def state_date(self):
+        return self._state_date
+
+    @property
+    def state_principal(self):
+        return self._state_principal
+
 
 @subscriber(IWorkflowTransitionEvent)
 def handle_workflow_transition(event):
     """Handle workflow transition"""
     if IWorkflowVersionTransitionEvent.providedBy(event):
         return
+    workflow = event.workflow
     request = check_request()
+    translate = request.localizer.translate
     item = WorkflowHistoryItem(date=datetime.utcnow(),
-                               source_state=event.source,
-                               target_state=event.destination,
-                               transition=event.transition.title,
+                               source_state=translate(workflow.states.getTerm(event.source).title)
+                                            if event.source else None,
+                               target_state=translate(workflow.states.getTerm(event.destination).title),
+                               transition=translate(event.transition.title),
                                principal=request.principal.id,
                                comment=event.comment)
     IWorkflowState(event.object).history.append(item)
@@ -84,12 +111,14 @@
 @subscriber(IWorkflowVersionTransitionEvent)
 def handle_workflow_version_transition(event):
     """Handle workflow version transition"""
+    workflow = event.workflow
     request = check_request()
+    translate = request.localizer.translate
     item = WorkflowHistoryItem(date=datetime.utcnow(),
                                source_version=IWorkflowState(event.old_object).version_id,
-                               source_state=event.source,
-                               target_state=event.destination,
-                               transition=event.transition.title,
+                               source_state=translate(workflow.states.getTerm(event.source).title),
+                               target_state=translate(workflow.states.getTerm(event.destination).title),
+                               transition=translate(event.transition.title),
                                principal=request.principal.id,
                                comment=event.comment)
     IWorkflowState(event.object).history.append(item)
@@ -193,9 +222,25 @@
             state = '__none__'
         return bool(self.versions_by_state.get(state, ()))
 
-    def remove_version(self, version_id):
+    def remove_version(self, version_id, state='deleted', comment=None):
         if str(version_id) not in self:
-            pass
+            return
+        # update version state
+        version = self[str(version_id)]
+        wf_state = IWorkflowState(version)
+        if comment:
+            request = check_request()
+            translate = request.localizer.translate
+            workflow = get_utility(IWorkflow, name=get_parent(self, IWorkflowManagedContent).workflow_name)
+            item = WorkflowHistoryItem(date=datetime.utcnow(),
+                                       source_version=wf_state.version_id,
+                                       source_state=translate(workflow.states.getTerm(wf_state.state).title),
+                                       target_state=translate(workflow.states.getTerm(state).title),
+                                       principal=request.principal.id,
+                                       comment=comment)
+            wf_state.history.append(item)
+        wf_state.state = state
+        # remove given version
         state = self.state_by_version[version_id]
         versions = self.versions_by_state[state]
         versions.remove(version_id)
@@ -242,3 +287,11 @@
             return versions[name]
         else:
             return versions
+
+
+@adapter_config(name='versions', context=IWorkflowManagedContent, provides=ISublocations)
+class WorkflowVersionsSublocations(ContextAdapter):
+    """Workflow versions sub-locations"""
+
+    def sublocations(self):
+        return IWorkflowVersions(self.context).values()
--- a/src/pyams_workflow/workflow.py	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/workflow.py	Wed Jun 17 10:02:06 2015 +0200
@@ -32,6 +32,8 @@
 from zope.lifecycleevent import ObjectModifiedEvent
 from zope.schema.vocabulary import getVocabularyRegistry
 
+from pyams_workflow import _
+
 
 def NullCondition(wf, context):
     """Null condition"""
@@ -93,6 +95,12 @@
         for transition in transitions:
             self._register(transition)
 
+    def get_state_label(self, state):
+        try:
+            return self.states.getTerm(state).title
+        except LookupError:
+            return _('-- unknown --')
+
     def get_transitions(self, source):
         try:
             return self._sources[source].values()
@@ -151,7 +159,7 @@
             # execute any side effect:
             if side_effect is not None:
                 side_effect(result)
-            event = WorkflowVersionTransitionEvent(result, self.context,
+            event = WorkflowVersionTransitionEvent(result, self.wf, self.context,
                                                    transition.source,
                                                    transition.destination,
                                                    transition, comment)
@@ -160,7 +168,7 @@
             # execute any side effect
             if side_effect is not None:
                 side_effect(self.context)
-            event = WorkflowTransitionEvent(self.context,
+            event = WorkflowTransitionEvent(self.context, self.wf,
                                             transition.source,
                                             transition.destination,
                                             transition, comment)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_workflow/zmi/transition.py	Wed Jun 17 10:02:06 2015 +0200
@@ -0,0 +1,78 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_workflow.interfaces import IWorkflowManagedContent, IWorkflow, IWorkflowTransitionInfo, IWorkflowCommentInfo, \
+    IWorkflowInfo
+from z3c.form.interfaces import HIDDEN_MODE
+
+# import packages
+from pyams_utils.registry import query_utility
+from pyams_utils.traversing import get_parent
+from pyams_utils.url import absolute_url
+from pyams_zmi.form import AdminDialogAddForm
+from pyramid.decorator import reify
+from zope.lifecycleevent import ObjectModifiedEvent
+from z3c.form import field
+
+
+class WorkflowContentTransitionForm(AdminDialogAddForm):
+    """Workflow content transition form"""
+
+    @reify
+    def transition(self):
+        parent = get_parent(self.context, IWorkflowManagedContent)
+        workflow = query_utility(IWorkflow, name=parent.workflow_name)
+        return workflow.get_transition_by_id(self.request.params.get('form.widgets.transition_id'))
+
+    @property
+    def legend(self):
+        return self.request.localizer.translate(self.transition.title)
+
+    fields = field.Fields(IWorkflowTransitionInfo) + \
+             field.Fields(IWorkflowCommentInfo)
+
+    @property
+    def edit_permission(self):
+        return self.transition.permission
+
+    @property
+    def icon_css_class(self):
+        return self.transition.user_data.get('menu_css_class')
+
+    def updateWidgets(self, prefix=None):
+        super(WorkflowContentTransitionForm, self).updateWidgets(prefix)
+        if 'transition_id' in self.widgets:
+            self.widgets['transition_id'].mode = HIDDEN_MODE
+            self.widgets['transition_id'].value = self.request.params.get('form.widgets.transition_id')
+        if 'comment' in self.widgets:
+            self.widgets['comment'].label_css_class = 'textarea'
+
+    def updateActions(self):
+        super(WorkflowContentTransitionForm, self).updateActions()
+        if 'action' in self.actions:
+            self.actions['action'].addClass('btn-primary')
+
+    def createAndAdd(self, data):
+        info = IWorkflowInfo(self.context)
+        info.fire_transition(self.transition.transition_id, comment=data.get('comment'))
+        info.fire_automatic()
+        self.request.registry.notify(ObjectModifiedEvent(self.context))
+        return info
+
+    def nextURL(self):
+        return absolute_url(self.context, self.request, 'summary.html')
--- a/src/pyams_workflow/zmi/versions.py	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/zmi/versions.py	Wed Jun 17 10:02:06 2015 +0200
@@ -19,19 +19,18 @@
 from pyams_form.interfaces.form import IWidgetsSuffixViewletsManager
 from pyams_security.interfaces import ISecurityManager
 from pyams_skin.layer import IPyAMSLayer
-from pyams_workflow.interfaces import IWorkflowVersion, IWorkflowState, IWorkflowManagedContent, IWorkflow
+from pyams_workflow.interfaces import IWorkflowVersion, IWorkflowState
 from pyams_zmi.interfaces.menu import IPropertiesMenu
 from z3c.table.interfaces import IValues, IColumn
 
 # import packages
 from pyams_pagelet.pagelet import pagelet_config
 from pyams_skin.table import BaseTable, I18nColumn
-from pyams_skin.viewlet.menu import MenuItem
+from pyams_skin.viewlet.menu import MenuItem, MenuDivider
 from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
 from pyams_utils.date import format_datetime
 from pyams_utils.registry import query_utility
 from pyams_utils.text import text_to_html
-from pyams_utils.traversing import get_parent
 from pyams_viewlet.viewlet import viewlet_config, Viewlet
 from pyams_zmi.form import AdminDialogDisplayForm
 from pyams_zmi.layer import IAdminLayer
@@ -43,7 +42,7 @@
 
 
 @viewlet_config(name='workflow-history.menu', context=IWorkflowVersion, layer=IAdminLayer,
-                manager=IPropertiesMenu, permission='manage', weight=1)
+                manager=IPropertiesMenu, permission='manage', weight=999)
 class WorkflowVersionHistoryMenuItem(MenuItem):
     """Workflow history menu item"""
 
@@ -58,10 +57,6 @@
 class WorkflowVersionHistoryDisplayForm(AdminDialogDisplayForm):
     """Workflow version history view"""
 
-    @property
-    def title(self):
-        return self.context.name
-
     dialog_class = 'modal-large'
     fields = field.Fields(Interface)
 
@@ -125,15 +120,6 @@
             return item.principal
 
 
-@adapter_config(name='transition', context=(Interface, IAdminLayer, WorkflowVersionHistoryTable), provides=IColumn)
-class WorkflowVersionHistoryTransitionColumn(I18nColumn, GetAttrColumn):
-    """Workflow version history source column"""
-
-    _header = _("Transition")
-    attrName = 'transition'
-    weight = 5
-
-
 @adapter_config(name='source', context=(Interface, IAdminLayer, WorkflowVersionHistoryTable), provides=IColumn)
 class WorkflowVersionHistorySourceColumn(I18nColumn, GetAttrColumn):
     """Workflow version history source column"""
@@ -142,17 +128,24 @@
     weight = 10
 
     def renderCell(self, item):
-        content = get_parent(self.context, IWorkflowManagedContent)
-        workflow = query_utility(IWorkflow, name=content.workflow_name)
         translate = self.request.localizer.translate
         if item.source_version:
             return translate(_("Version {version} ({status})")).format(
                 version=item.source_version,
-                status=translate(workflow.states.getTerm(item.source_state).title))
+                status=item.source_state)
         else:
             return translate(_("Version {version} ({status})")).format(
                 version=IWorkflowState(self.context).version_id,
-                status=translate(workflow.states.getTerm(item.source_state).title) if item.source_state else '--')
+                status=item.source_state if item.source_state else '--')
+
+
+@adapter_config(name='transition', context=(Interface, IAdminLayer, WorkflowVersionHistoryTable), provides=IColumn)
+class WorkflowVersionHistoryTransitionColumn(I18nColumn, GetAttrColumn):
+    """Workflow version history source column"""
+
+    _header = _("Transition")
+    attrName = 'transition'
+    weight = 11
 
 
 @adapter_config(name='target', context=(Interface, IAdminLayer, WorkflowVersionHistoryTable), provides=IColumn)
@@ -160,13 +153,8 @@
     """Workflow version history source column"""
 
     _header = _("Target state")
-    weight = 11
-
-    def renderCell(self, item):
-        content = get_parent(self.context, IWorkflowManagedContent)
-        workflow = query_utility(IWorkflow, name=content.workflow_name)
-        translate = self.request.localizer.translate
-        return translate(workflow.states.getTerm(item.target_state).title)
+    attrName = 'target_state'
+    weight = 12
 
 
 @adapter_config(name='comment', context=(Interface, IAdminLayer, WorkflowVersionHistoryTable), provides=IColumn)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_workflow/zmi/viewlet/__init__.py	Wed Jun 17 10:02:06 2015 +0200
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+
+# import packages
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_workflow/zmi/viewlet/templates/versions.pt	Wed Jun 17 10:02:06 2015 +0200
@@ -0,0 +1,26 @@
+<div class="btn-group margin-right-20"
+	 tal:define="current_state view.get_workflow_state()"
+	 i18n:domain="pyams_workflow">
+	<button data-toggle="dropdown" class="btn btn-xs btn-primary dropdown-toggle">
+		<tal:var i18n:translate="">
+			Version <i18n:var name="version" tal:content="current_state['version']" /> -
+			<i18n:var name="state" tal:content="current_state['state_label']" />
+		</tal:var>
+		&nbsp;<i class="fa fa-fw fa-caret-down"></i>
+	</button>
+	<ul class="dropdown-menu">
+		<li class="small"
+			tal:repeat="version view.workflow_versions">
+			<a tal:define="url extension:absolute_url(version);
+						   state view.get_workflow_state(version);"
+			   tal:attributes="data-ams-url string:${url}/admin.html#${request.view_name}">
+				<i class="fa fa-fw"
+				   tal:attributes="class 'fa fa-fw fa-arrow-right {0}'.format('txt-color-white' if current_state['version'] != state['version'] else '')"></i>
+				<tal:var i18n:translate="">
+					Version <i18n:var name="version" tal:content="state['version']" /> -
+					<i18n:var name="state" tal:content="state['state_label']" />
+				</tal:var>
+			</a>
+		</li>
+	</ul>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_workflow/zmi/viewlet/versions.py	Wed Jun 17 10:02:06 2015 +0200
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_skin.interfaces.viewlet import IToolbarViewletManager
+from pyams_skin.layer import IPyAMSLayer
+from pyams_workflow.interfaces import IWorkflowVersion, IWorkflowState, IWorkflowVersions, IWorkflowManagedContent, \
+    IWorkflow
+
+# import packages
+from pyams_template.template import template_config
+from pyams_utils.registry import get_utility
+from pyams_utils.traversing import get_parent
+from pyams_viewlet.viewlet import viewlet_config, Viewlet
+from pyramid.decorator import reify
+
+
+@viewlet_config(name='pyams_workflow.versions', context=IWorkflowVersion, layer=IPyAMSLayer,
+                manager=IToolbarViewletManager, weight=1)
+@template_config(template='templates/versions.pt', layer=IPyAMSLayer)
+class WorkflowVersionMenuProvider(Viewlet):
+    """Workflow versions menu content provider"""
+
+    @reify
+    def workflow(self):
+        content = get_parent(self.context, IWorkflowManagedContent)
+        return get_utility(IWorkflow, name=content.workflow_name)
+
+    def get_workflow_state(self, context=None):
+        if context is None:
+            context = self.context
+        state = IWorkflowState(context)
+        return {'version': state.version_id,
+                'state': state.state,
+                'state_label': self.request.localizer.translate(self.workflow.get_state_label(state.state))}
+
+    @property
+    def workflow_versions(self):
+        return IWorkflowVersions(self.context).get_last_versions(count=0)
--- a/src/pyams_workflow/zmi/workflow.py	Wed May 20 14:57:49 2015 +0200
+++ b/src/pyams_workflow/zmi/workflow.py	Wed Jun 17 10:02:06 2015 +0200
@@ -16,19 +16,28 @@
 # import standard library
 
 # import interfaces
+from pyams_i18n.interfaces import II18n
 from pyams_skin.interfaces.viewlet import IToolbarViewletManager
+from pyams_skin.layer import IPyAMSLayer
 from pyams_workflow.interfaces import IWorkflow, IWorkflowInfo, IWorkflowVersion, IWorkflowManagedContent, \
-    IWorkflowVersions
+    IWorkflowVersions, IWorkflowState
 from pyams_workflow.zmi.interfaces import IWorkflowMenu
 from pyams_zmi.layer import IAdminLayer
+from zope.container.interfaces import IContainer
+from zope.dublincore.interfaces import IZopeDublinCore
 
 # import packages
 from pyams_skin.table import NameColumn
 from pyams_skin.viewlet.toolbar import ToolbarMenu, ToolbarMenuItem
 from pyams_utils.registry import query_utility
+from pyams_utils.date import format_datetime
+from pyams_utils.timezone import tztime
 from pyams_utils.traversing import get_parent
+from pyams_utils.url import absolute_url
 from pyams_viewlet.manager import viewletmanager_config
 from pyams_viewlet.viewlet import viewlet_config
+from pyramid.response import Response
+from pyramid.view import view_config
 from zope.interface import implementer, Interface
 
 from pyams_workflow import _
@@ -41,14 +50,14 @@
         super(WorkflowMenuItem, self).__init__(context, request, view, manager)
         self.label = transition.title
         self.label_css_class = transition.user_data.get('menu_css_class') or 'fa fa-fw'
-        self.url = '{url}?transition_id={transition}'.format(url=transition.user_data.get('view_name'),
-                                                             transition=transition.transition_id)
+        self.url = '{url}?form.widgets.transition_id={transition}'.format(url=transition.user_data.get('view_name'),
+                                                                          transition=transition.transition_id)
         self.weight = transition.order
         self.modal_target = True
 
 
 @viewlet_config(name='workflow.menu', view=Interface, layer=IAdminLayer, context=IWorkflowVersion,
-                manager=IToolbarViewletManager, permission='portal.templates.manage', weight=200)
+                manager=IToolbarViewletManager, weight=800)
 @viewletmanager_config(name='workflow.menu', layer=IAdminLayer, provides=IWorkflowMenu)
 @implementer(IWorkflowMenu)
 class WorkflowMenu(ToolbarMenu):
@@ -75,11 +84,53 @@
 class WorkflowContentNameColumn(NameColumn):
     """Workflow content name column"""
 
+    name_field = 'title'
+
     def getValue(self, obj):
-        wf_versions = IWorkflowVersions(obj, None)
-        if wf_versions is None:
-            return super(WorkflowContentNameColumn, self).getValue(obj)
-        versions = wf_versions.get_last_versions(count=1)
-        if len(versions) > 0:
-            version = versions[0]
-            return super(WorkflowContentNameColumn, self).getValue(version)
+        result = ''
+        wf_versions = IWorkflowVersions(obj).get_last_versions(count=0)
+        if wf_versions:
+            content = get_parent(obj, IWorkflowManagedContent)
+            workflow = query_utility(IWorkflow, name=content.workflow_name)
+            result += '<i class="fa fa-fw fa-caret-right margin-top-2 pull-left" ' \
+                      'data-ams-url="PyAMS_workflow.versions_list.switchVersions"></i>'
+            result += '<span class="title">{0}</span>'.format(II18n(wf_versions[0]).query_attribute(self.name_field))
+            result += '<ul class="hidden versions">'
+            translate = self.request.localizer.translate
+            for version in wf_versions[:3]:
+                state = IWorkflowState(version)
+                result += '<li><a data-ams-url="{url}">{version}</a></li>'.format(
+                    url=absolute_url(version, self.request, 'admin.html'),
+                    version=translate(_("Version {version} ({state} - last update {date})")).format(
+                        version=state.version_id,
+                        state=translate(workflow.states.getTerm(state.state).title),
+                        date=format_datetime(tztime(IZopeDublinCore(version).modified))))
+            if len(wf_versions) > 3:
+                result += '<li class="nodot"><span data-ams-url="PyAMS_workflow.versions_list.switchAllVersions">' \
+                          '<i class="fa fa-fw fa-caret-right margin-top-2 pull-left"></i>' + \
+                          translate(_("Older versions")) + '</span>'
+                result += '<ul class="hidden old_versions"></ul></li>'
+            result += '</ul>'
+        return result
+
+
+@view_config(name='get-old-versions.html', context=IContainer, request_type=IPyAMSLayer,
+             permission='system.view', xhr=True)
+def get_old_versions(request):
+    """Get old_versions of template"""
+    container = request.context
+    element = container.get(request.params.get('element_name'))
+    ignore = int(request.params.get('ignore', 3))
+    translate = request.localizer.translate
+    result = []
+    content = get_parent(element, IWorkflowManagedContent)
+    workflow = query_utility(IWorkflow, name=content.workflow_name)
+    for version in IWorkflowVersions(element).get_last_versions(count=0)[ignore:]:
+        state = IWorkflowState(version)
+        result += '<li><a data-ams-url="{url}">{version}</a></li>'.format(
+            url=absolute_url(version, request, 'admin.html'),
+            version=translate(_("Version {version} ({state} - last update {date})")).format(
+                version=state.version_id,
+                state=translate(workflow.states.getTerm(state.state).title),
+                date=format_datetime(tztime(IZopeDublinCore(version).modified))))
+    return Response(''.join(result))