Merge lp:~mttronchetti/novacut/history into lp:novacut

Proposed by Matteo Ronchetti
Status: Merged
Merged at revision: 271
Proposed branch: lp:~mttronchetti/novacut/history
Merge into: lp:novacut
Diff against target: 356 lines (+198/-40)
5 files modified
novacut-gtk (+11/-4)
novacut/schema.py (+1/-0)
ui/bucket.js (+16/-0)
ui/projects.html (+96/-3)
ui/projects.js (+74/-33)
To merge this branch: bzr merge lp:~mttronchetti/novacut/history
Reviewer Review Type Date Requested Status
Jason Gerard DeRose Approve
Review via email: mp+109928@code.launchpad.net

Description of the change

Added lazy delete for project with a cool drop down menu called history

To post a comment you must log in.
lp:~mttronchetti/novacut/history updated
272. By Matteo Ronchetti

added possibility to duplicate a slice with d button on keyboard

273. By Matteo Ronchetti

added possibility to duplicate a slice with d button on keyboard

Revision history for this message
Jason Gerard DeRose (jderose) wrote :

Matteo,

First of all, thanks for jumping into Novacut full-force! Looks like you really have a handle on interacting with CouchDB, from both JavaScript and Python. And as lots of this lacks documentation still, that's no small feat!

First problem I encountered is the "history" DB isn't getting created if it doesn't already exist. Second, my gut feeling is we don't want to store this is a 2nd database, basically because it creates a lot of consistency and sync issues.

From what I've learned so far from working with CouchDB, you really don't want the state of a "thing" to span multiple documents, and you especially don't want it to span multiple databases. Updates to documents can arrive at one node in a different order than they were saved in another, and the problem gets much more complicated if you're talking about multiple databases.

I think instead we should have some flag attribute on the novacut/project documents. Say a hypothetical "isdeleted" attribute. And we'll make the view that lists project on the starting novacut page show all novacut/project documents such that `!doc.isdeleted` and make the History menu show all novacut/project documents such that `doc.isdeleted`.

Does that make sense? Lets discuss the schema when we're next both on IRC, okay?

Thanks again!

review: Needs Fixing
lp:~mttronchetti/novacut/history updated
274. By Matteo Ronchetti

changed the way projects are removed

Revision history for this message
Jason Gerard DeRose (jderose) wrote :

Matteo,

Okay, this is a lot better now, thanks! I'm going to merge this because I want you to have code in this release, but fair warning... this still needs some more work, and I reserve the right to use my "executive powers" to potentially make same changes later :P

Things I really like:

1) Using the same visual representation for the project inside the History/Trash... makes it much clearer what the "thing" is in there, nice work

2) Dragging out of the History/Trash to undelete... simple, and fits with the interaction patterns we use elsewhere

Things I think need improvement:

1) As it stands, "History" is a confusing term for what this menu does, and I personally don't think this is the place to expose your project's history of snapshots (that should be inside the project).

2) I don't like using onmouseover to show the History menu. Despite it's popularity in a lot of web sites lately (Google+ and Vimeo are big offenders in my mind), I think using onmouseover to reveal something is fundamentally bad UX. It also making it difficult to keep our interactions consistent between touch and mouse (but I don't think that's the biggest reason to avoid it).

Anyway, thanks again and talk to you more once you get back from the UK!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'novacut-gtk'
--- novacut-gtk 2012-06-08 16:59:15 +0000
+++ novacut-gtk 2012-06-19 17:00:25 +0000
@@ -126,6 +126,7 @@
126 'render_job': ['job_id'],126 'render_job': ['job_id'],
127 'job_rendered': ['job_id', 'file_id', 'link'],127 'job_rendered': ['job_id', 'file_id', 'link'],
128 'delete_project': ['project_id'],128 'delete_project': ['project_id'],
129 'sos_project': ['project_id'],
129 }130 }
130131
131 __Renderer = None132 __Renderer = None
@@ -161,6 +162,7 @@
161 hub.connect('hash_job', self.on_hash_job)162 hub.connect('hash_job', self.on_hash_job)
162 hub.connect('render_job', self.on_render_job)163 hub.connect('render_job', self.on_render_job)
163 hub.connect('delete_project', self.on_delete_project)164 hub.connect('delete_project', self.on_delete_project)
165 hub.connect('sos_project', self.on_sos_project)
164166
165 def post_env_init(self):167 def post_env_init(self):
166 views.init_views(self.db, views.novacut_main)168 views.init_views(self.db, views.novacut_main)
@@ -181,12 +183,17 @@
181183
182 def on_delete_project(self, hub, project_id):184 def on_delete_project(self, hub, project_id):
183 print('delete_project', project_id)185 print('delete_project', project_id)
186 doc = self.db.get(project_id)
187 doc['isdeleted'] = True
188 self.db.post(doc)
189
190 def on_sos_project(self,hub,project_id):
191 print('sos_project', project_id)
184 doc = self.db.get(project_id)192 doc = self.db.get(project_id)
185 print(doc)193 print(doc)
186 db = self.server.database(schema.project_db_name(project_id))194 doc['isdeleted'] = False
187 db.delete()195 self.db.post(doc)
188 db = self.server196
189 db.delete('novacut-0',project_id,rev=doc['_rev'])
190197
191 def on_load_project(self, hub, project_id):198 def on_load_project(self, hub, project_id):
192 print('load_project', project_id)199 print('load_project', project_id)
193200
=== modified file 'novacut/schema.py'
--- novacut/schema.py 2012-03-18 07:38:42 +0000
+++ novacut/schema.py 2012-06-19 17:00:25 +0000
@@ -370,6 +370,7 @@
370 'atime': ts,370 'atime': ts,
371 'db_name': project_db_name(_id),371 'db_name': project_db_name(_id),
372 'title': title,372 'title': title,
373 'isdeleted': False,
373 }374 }
374375
375376
376377
=== modified file 'ui/bucket.js'
--- ui/bucket.js 2012-04-25 04:01:29 +0000
+++ ui/bucket.js 2012-06-19 17:00:25 +0000
@@ -1735,6 +1735,19 @@
1735 }1735 }
1736 },1736 },
17371737
1738 duplicate_selected: function(dnd) {
1739 var element = $(UI.selected);
1740 var doc = UI.session.get_doc(element.id);
1741 var ndoc = create_slice(doc.node.src,doc.node.stop.frame);
1742 ndoc.node.start.frame = doc.node.start.frame;
1743 UI.session.save(ndoc);
1744 var slice = new Slice(UI.session, ndoc);
1745 slice.x = 64;
1746 slice.y = 36;
1747 UI.bucket.appendChild(slice.element);
1748 UI.sequence.do_reorder();
1749 },
1750
1738 first: function() {1751 first: function() {
1739 var element = $(UI.selected);1752 var element = $(UI.selected);
1740 if (element && element.parentNode) {1753 if (element && element.parentNode) {
@@ -1850,6 +1863,9 @@
1850 UI.player.hold_and_resume();1863 UI.player.hold_and_resume();
1851 }1864 }
1852 },1865 },
1866 'U+0044': function(event) {
1867 UI.duplicate_selected(event);
1868 },
18531869
1854 // The David Fulde key1870 // The David Fulde key
1855 // aka Backspace aka Big Delete on a mac keyboard1871 // aka Backspace aka Big Delete on a mac keyboard
18561872
=== modified file 'ui/projects.html'
--- ui/projects.html 2012-03-06 18:12:44 +0000
+++ ui/projects.html 2012-06-19 17:00:25 +0000
@@ -9,16 +9,109 @@
9 <script src="/_apps/dmedia/common.js"></script>9 <script src="/_apps/dmedia/common.js"></script>
10 <script src="novacut.js"></script>10 <script src="novacut.js"></script>
11 <script src="projects.js"></script>11 <script src="projects.js"></script>
12 <script>
13 function dragstart(ev){
14 ev.dataTransfer.setData("Text", ev.target.id);
15 ev.dataTransfer.effectAllowed = 'move';
16 }
17 function enter(ev){
18 ev.target.setAttribute("style","background-color: rgba(255,255,255,0.15); height: 2000px;width = 2000px;");
19 return false;
20 }
21 function leave(ev){
22 ev.target.setAttribute("style","height: 2000px;width = 2000px");
23 return false;
24 }
25 function d(ev){
26 ev.preventDefault();
27 ev.target.setAttribute("style","height: 2000px;width = 2000px;");
28 var data=ev.dataTransfer.getData("Text");
29 Hub.send('sos_project', data);
30 element = document.getElementById(data);
31 element.parentNode.removeChild(element);
32 var doc = novacut.get_sync(data)
33 UI.add_item(data,doc.title,doc.time,countFiles(data));
34 return false;
35 }
36 function over(ev){
37 ev.preventDefault();
38 }
39 </script>
40 <style>
41 .el{
42 cursor: move;
43 }
44#menu{
45 float: right;
46 padding: 3px 8px 0 0;
47 list-style: none;
48 cursor: default;
49}
50
51#menu li{
52 float: left;
53 padding: 0 0 10px 0;
54 position: relative;
55}
56
57#menu li:hover > a{
58 color: #fafafa;
59}
60#menu li:hover > ul{
61 display: block;
62}
63
64#menu ul{ /*container*/
65 min-width: 320px;
66 min-height: 26px;
67 list-style: none;
68 margin: 0px -269px;
69 padding: 4px;
70 display: none;
71 position: absolute;
72 top: 35px;
73 left: 0;
74 z-index: 99999;
75 background: #444;
76 border-radius: 10px;
77 box-shadow: 1px 1px 10px rgba(0,0,0,0.5);
78}
79#menu ul li{ /* projects*/
80 float: none;
81 margin: 10px;
82 padding: 0;
83 display: block;
84 cursor: move;
85}
86#menu ul:after{
87 content: '';
88 position: absolute;
89 left: 284px;
90 top: -15px;
91 width: 0;
92 height: 0;
93 border-left: 10px solid transparent;
94 border-right: 10px solid transparent;
95 border-bottom: 15px solid;
96}
97
98#menu ul:after{
99 border-bottom-color: #444;
100}
101
102 </style>
12 </head>103 </head>
13 <body>104 <body>
14 <form id="new_project" class="head">105 <form id="new_project" class="head">
15 <div class="grid_row">106 <div class="grid_row">
16 <input placeholder="New project name" type="text" class="grid_4" autofocus>107 <input placeholder="New project name" type="text" class="grid_4" autofocus>
17 <button class="grid_4" disabled>Create Project</button>108 <button class="grid_4" disabled>Create Project</button>
109 <ul id="menu"><li>
110 <a>History</a>
111 <ul id="list"></ul>
112 </li></ul>
18 </div>113 </div>
19 </form>114 </form>
20115<ul style="height: 200px;width = 200px;" id="projects" ondragenter="enter(event)" ondragleave="leave(event)" ondrop="d(event)" ondragover="over(event);"></ul>
21 <ul id="projects"></ul>
22
23 </body>116 </body>
24</html>117</html>
25118
=== modified file 'ui/projects.js'
--- ui/projects.js 2012-06-08 16:59:15 +0000
+++ ui/projects.js 2012-06-19 17:00:25 +0000
@@ -5,22 +5,35 @@
5 window.location.assign('cutter.html#' + project_id); 5 window.location.assign('cutter.html#' + project_id);
6}6}
77
8function countFiles(project_id){
9 var pdb = new couch.Database("novacut-0-" + project_id.toLowerCase());
10 try{
11 var filecount = pdb.view_sync('doc', 'type', {key: 'dmedia/file'}).rows[0].value;
12 }
13 catch(e){
14 var filecount = 0;
15 }
16 return filecount;
17}
818
9var UI = {19var UI = {
10 init: function() {20 init: function() {
11 UI.form = $('new_project');21 UI.form = $('new_project');
12 UI.input = UI.form.getElementsByTagName('input')[0];22 UI.input = UI.form.getElementsByTagName('input')[0];
13 UI.button = UI.form.getElementsByTagName('button')[0];23 UI.button = UI.form.getElementsByTagName('button')[0];
14 UI.project = new Project(novacut);24 //UI.project = new Project(novacut);
15 UI.items = new Items('projects');25 //UI.items = new Items('projects');
16 26
17 UI.form.onsubmit = UI.on_submit;27 UI.form.onsubmit = UI.on_submit;
18 UI.input.oninput = UI.on_input;28 UI.input.oninput = UI.on_input;
19 29
30 UI.hist = document.getElementById('list');
31 UI.proj = document.getElementById('projects');
20 UI.load_items();32 UI.load_items();
21 },33 },
2234
23 load_items: function() {35 load_items: function() {
36 //UI.add_history("qwe","nome",3333,3);
24 console.log('load_items');37 console.log('load_items');
25 novacut.view(UI.on_items, 'project', 'title');38 novacut.view(UI.on_items, 'project', 'title');
26 },39 },
@@ -28,28 +41,58 @@
28 on_items: function(req) {41 on_items: function(req) {
29 var rows = req.read().rows;42 var rows = req.read().rows;
30 console.log(rows.length);43 console.log(rows.length);
31 UI.items.replace(rows,44 for(var b in rows){
32 function(row, items) {45 var a = rows[b]
33 var pdb = new couch.Database("novacut-0-" + row.id.toLowerCase());46 var pdb = new couch.Database("novacut-0-" + a.id.toLowerCase());
34 try{47 try{
35 var filecount = pdb.view_sync('doc', 'type', {key: 'dmedia/file'}).rows[0].value;48 var filecount = pdb.view_sync('doc', 'type', {key: 'dmedia/file'}).rows[0].value;
36 }49 }
37 catch(e){50 catch(e){
38 var filecount = 0;51 var filecount = 0;
39 }52 }
40 53 var doc = novacut.get_sync(a.id)
41 var li = $el('li', {'class': 'project', 'id': row.id});54 if(!doc.isdeleted) UI.add_item(a.id,a.key,a.value,filecount);
4255 else UI.add_history(a.id,a.key,a.value,filecount);
43 var thumb = $el('div', {'class': 'thumbnail'});56 }
44 thumb.style.backgroundImage = "url(/_apps/dmedia/novacut-avatar-192.png)";//novacut.att_css_url(row.id);57 },
4558
46 var info = $el('div', {'class': 'info'});59 add_history: function(id,name,date,filecount){
47 info.appendChild(60 var li = $el('li', {'class': 'project', 'id': id});
48 $el('p', {'textContent': row.key, 'class': 'title'})61 li.setAttribute('draggable', 'true');
49 );62 li.setAttribute('ondragstart', 'dragstart(event)');
5063 var thumb = $el('div', {'class': 'thumbnail'});
51 info.appendChild(64 thumb.style.backgroundImage = "url(/_apps/dmedia/novacut-avatar-192.png)";//novacut.att_css_url(row.id);
52 $el('p', {'textContent': format_date(row.value)})65
66 var info = $el('div', {'class': 'info'});
67 info.appendChild(
68 $el('p', {'textContent': name, 'class': 'title'})
69 );
70
71 info.appendChild(
72 $el('p', {'textContent': format_date(date)})
73 );
74
75 info.appendChild(
76 $el('p', {'textContent': filecount + ' files'})
77 );
78
79 li.appendChild(thumb);
80 li.appendChild(info);
81 UI.hist.appendChild(li);
82 },
83
84 add_item: function(id,name,date,filecount) {
85 var li = $el('li', {'class': 'project', 'id': id});
86 var thumb = $el('div', {'class': 'thumbnail'});
87 thumb.style.backgroundImage = "url(/_apps/dmedia/novacut-avatar-192.png)";//novacut.att_css_url(row.id);
88
89 var info = $el('div', {'class': 'info'});
90 info.appendChild(
91 $el('p', {'textContent': name, 'class': 'title'})
92 );
93
94 info.appendChild(
95 $el('p', {'textContent': format_date(date)})
53 );96 );
5497
55 info.appendChild(98 info.appendChild(
@@ -62,21 +105,19 @@
62 del.setAttribute('src', 'delete.png');105 del.setAttribute('src', 'delete.png');
63 del.setAttribute('align', 'right');106 del.setAttribute('align', 'right');
64 del.onclick = function(){107 del.onclick = function(){
65 this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);108 this.parentNode.parentNode.removeChild(this.parentNode);
66 Hub.send('delete_project', row.id)109 Hub.send('delete_project', id)
110 var doc = novacut.get_sync(id)
111 UI.add_history(id,doc.title,doc.time,countFiles(id));
67 }112 }
68 li.appendChild(del);113 li.appendChild(del);
69 thumb.onclick = function() {114 thumb.onclick = function() {
70 Hub.send('load_project', row.id)115 Hub.send('load_project', id)
71 }116 }
72 info.onclick = function() {117 info.onclick = function() {
73 Hub.send('load_project', row.id)118 Hub.send('load_project', id)
74 }119 }
75120 UI.proj.appendChild(li);
76 return li;
77 }
78 );
79 UI.items.select(UI.project.id);
80 },121 },
81122
82 on_input: function(event) {123 on_input: function(event) {

Subscribers

People subscribed via source and target branches

to all changes:
to status/vote changes: