<div dir="ltr">Hi Thai,<div><br></div><div>From your example, option 1 seems closer to the *current pattern* not option 2. :) Where the user define a list of action separately from the table presentation (HTML template) rather than embedding it in the HTML.  And if the user wants to extend it, they just add it to the list of columns/actions on the table class.</div><div><br></div><div>Option 1 seems better to me due to I find it closer to the current pattern. As long as we can reduce the duplicate code (not having to write 9 files to create one table), I'm good with that. :)</div><div><br></div><div>My main concern is really to polish first the initial table implementation before folks jump into implementing the tables in all other panels.  So we can avoid re-work, don't want another cycle of clean-up/refactor. :)<br></div><div><br></div><div>I think we already have 2 angular tables out, should be enough data to figure out what duplicate code can be abstracted out based from those two implementation.<br></div><div><br></div><div>-Lin</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Aug 20, 2015 at 4:36 PM, Doug Fish <span dir="ltr"><<a href="mailto:the.doug.fish@gmail.com" target="_blank">the.doug.fish@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div>It appears to me that option 1 would be better prepared to be extensible ... That is if a plugin needed to add an action or a column, we could make that happen with pattern 1 (possibly after adding in a service) I'm not sure how plugins ever add these things with pattern 2. <br></div><div><div class="h5"><div><br>On Aug 20, 2015, at 1:41 PM, "Thai Q Tran" <<a href="mailto:tqtran@us.ibm.com" target="_blank">tqtran@us.ibm.com</a>> wrote:<br><br></div><blockquote type="cite"><div><font face="Default Sans Serif,Verdana,Arial,Helvetica,sans-serif" size="2"><font face="Verdana, Arial, Helvetica, sans-serif">Hi Lin,</font><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">Let me draw on some examples to help clarify what I mean.</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><b>Option 1:</b></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">table.controller.js</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">--------------------</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">ctrl.headers = {</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  gettext('column 1'),</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  gettext('column 2')</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">};</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">ctrl.noItemMessage = gettext('You no longer have any items in your table. You either lack the sufficient priveledges or your search criteria is not valid');</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">ctrl.batchActionList = [</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">  { name: 'create', onclick: somefunction, etc.... }</span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  { name: 'delete', onclick: somefunction, etc.... }</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">];</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">ctrl.rowActionList = [</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">  { name: 'edit', onclick: somefunction, etc.... }</span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">  { name: 'delete', onclick: somefunction, etc.... }</span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">];</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">table.html</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">-----------</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><div <span style="font-size:12.8000001907349px">ng-controller="table.controller.js as ctrl"></span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  <horizon-table</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">    headers="ctrl.headers"</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">    batch-actions="ctrl.batchActionList"</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">    row-actions="ctrl.rowActionList"></span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">  </</span><span style="font-size:12.8000001907349px">horizon</span><span style="font-size:12.8000001907349px">-table></span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px"></div></span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">So now your controller is polluted with presentation and translation logic. In addition, <span style="font-size:12.8000001907349px">we will have to live with long gettext messages and add eslint ignore rules just to pass it. </span><span style="font-size:12.8000001907349px">The flip side is that you do have a simple directive that points to a common template sitting somewhere. </span><span style="font-size:12.8000001907349px">It is not that much "easier" to the example below. What we're really doing is defining the same presentation logic, but in the HTML instead. Lastly, </span><span style="font-size:12.8000001907349px">I'll bring up the customization again because many products are going to want to customize their tables. They maybe the minority but that doesn't mean we shouldn't support them.</span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><b>Option 2:</b></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">table.html</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">------------</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><table ng-controller="table.controller.js as ctrl"></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><thead></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  <tr></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">    <action-list></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">      <action callback="someFunc" translate>Create</action></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">      <action callback="someFunc" translate>Delete</action></span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">    </action-list></span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  </tr></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  <tr></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">    <th translate>Column 1</th></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">    <th translate>Column 2</th></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  </tr></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"></thead></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><tbody></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  <tr ng-repeat="items in ctrl.items"></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">    <td>....</td></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">    <td><action-list></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">      <action callback="someFunc" translate>Edit</action></span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><span style="font-size:12.8000001907349px">      <action callback="someFunc" translate>Delete</action></span></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">    </action-list></td></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">  </tr></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"></tbody></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"></table></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">Here, your table.controller.js worries ONLY about data and data manipulation. The presentation logic all resides in the HTML. If I want to add icons in the table header, I can do that easily. Remember that this is plain HTML, this is a lot easier for someone new to come in and learn this than our special horizon-table directive. It is definitely easier to USE, but I would argue that it is harder to learn.</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">--------------</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">If you compare the two options above, you'll see that all we've really done is move presentation logic from the controller into the HTML. You have to define that logic somewhere, why not in the HTML? This makes it easier to read and know what you're going to see in the browser (something HTML5 spec is evangelizing), and you get the bonus benefit of customization.</div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif">I'd like to point out that we aren't getting rid of directives, we're still using directives them (like <action-list>, <action>, <magic-search>, etc..) in our tables. The pattern is, you build your panels using smaller components instead of having one giant component that encapsulates everything. Of course, there isn't a right or wrong answer, in fact there are <span style="font-size:12.8000001907349px">two very different implementations of a table directive out there right now:</span></div><div><font face="Verdana, Arial, Helvetica, sans-serif"><br></font></div><div><font face="Verdana, Arial, Helvetica, sans-serif"><a href="http://ng-table.com" target="_blank">http://ng-table.com</a> (more inline with option 1)</font></div><div><font face="Verdana, Arial, Helvetica, sans-serif"><a href="http://lorenzofox3.github.io/smart-table-website/" target="_blank">http://lorenzofox3.github.io/smart-table-website/</a> (more inline with option 2)</font></div><div><font face="Verdana, Arial, Helvetica, sans-serif"><br></font></div><div><font face="Verdana, Arial, Helvetica, sans-serif">Basically, what I'm trying to say is: let's build something simple and easy to understand first (small components that we work), then we can build something more complex on top of it so that it easier to use. I don't think there is a right or wrong answer, just two very different ways of thinking and implementation. But if we start with smaller components first, we get the goods of both world. The guys that want to customize will have a way to do it by bypassing the horizon-table directive, and the guys that just want a simple table can use the more complex directive.</font></div><div style="font-family:Verdana,Arial,Helvetica,sans-serif"><br><font color="#990099">-----Lin Hua Cheng <<a href="mailto:os.lcheng@gmail.com" target="_blank">os.lcheng@gmail.com</a>> wrote: -----</font><div style="padding-left:5px"><div style="padding-right:0px;padding-left:5px;border-left:solid black 2px">To: "OpenStack Development Mailing List (not for usage questions)" <<a href="mailto:openstack-dev@lists.openstack.org" target="_blank">openstack-dev@lists.openstack.org</a>><br>From: Lin Hua Cheng <<a href="mailto:os.lcheng@gmail.com" target="_blank">os.lcheng@gmail.com</a>><br>Date: 08/19/2015 05:15PM<br>Subject: Re: [openstack-dev] [Horizon] Update on Angular Identity work<br><br><div dir="ltr">Hi Thai,<div><br></div><div>Thanks for investigating the two options.<br><div><br></div><div>Option 2 might be better. Folks have to learn the new pattern of writing multiple files, so I think the learning curve for a new table directive is not that much of a difference.</div><div><br></div><div>I think option 2 is going to be easier to maintain, since we have a layer of abstraction. It might even also increase adoptability since it would be easier to use.  It might be harder to customize, but that would probably not be done often.  The table directive would be used as is most of the time. </div><div><br></div><div>My thought is design the code to be easy to use for the use case that will be used most of the time rather than the customization case  which maybe harder to do. Which leads me to preferring option 2.</div><div><br></div><div>Thanks,</div><div>Lin</div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Aug 19, 2015 at 12:16 PM, Thai Q Tran <span dir="ltr"><<a href="mailto:tqtran@us.ibm.com" target="_blank">tqtran@us.ibm.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><font face="Default Sans Serif,Verdana,Arial,Helvetica,sans-serif" size="2"><div>Hi Lin,</div><div><br></div><div>I agree with you and Eric that we have a lot of HTML fragments. Some of them I think make sense as directives:</div><div>The table footer is a good example of something we can convert into a directive: <a href="https://review.openstack.org/#/c/207631/" target="_blank">https://review.openstack.org/#/c/207631/</a></div><div>The table header on the other hand is something more specific to your table: <a href="https://github.com/openstack/horizon/blob/master/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/table/table-header.html" target="_blank">https://github.com/openstack/horizon/blob/master/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/table/table-header.html</a></div><div><br></div><div>So there are two approaches we can take here:</div><div>1. Keep some of the presentation related data in the HTML: mainly things like table headers, column definitions, translated texts, etc... I like this approach a bit more because it allow us to read the HTML and know exactly what we are expecting to see. This table.html is compose of smaller directives like hz-table-footer and regular html tags like <th> and <td> etc... I think as we have more of these smaller directives available, we can combine the fragments into one file.</div><div><br></div><div>2. We could create a more general table directive with a common template. This is more inline with what we have currently for legacy. BUT the presentation logic like translations, definitions would now have to reside in the table controller AND we lose the semantic readability part. Doing it this way could potentially introduce more complexity as it now requires people to learn the table directive, which could be very complex if it does not use smaller directives. Another common problem we encountered with this pattern was a lack of customization. In legacy, it was pretty hard to add an icon into a table cell. If we go down this route, I believe we might start to encounter the same issues.</div><div><br></div><div>In summary, we are working on addressing the HTML fragments, but I think we as a community should go with option 1 and stay away from option 2.</div><br><font color="#990099">-----Lin Hua Cheng <<a href="mailto:os.lcheng@gmail.com" target="_blank">os.lcheng@gmail.com</a>> wrote: -----</font><div style="padding-left:5px"><div style="padding-right:0px;padding-left:5px;border-left:solid black 2px">To: "OpenStack Development Mailing List (not for usage questions)" <<a href="mailto:openstack-dev@lists.openstack.org" target="_blank">openstack-dev@lists.openstack.org</a>><br>From: Lin Hua Cheng <<a href="mailto:os.lcheng@gmail.com" target="_blank">os.lcheng@gmail.com</a>><br>Date: 08/18/2015 02:36PM<br>Cc: Vince Brunssen/Austin/IBM@IBMUS<br>Subject: Re: [openstack-dev] [Horizon] Update on Angular Identity work<div><div><br><br><div dir="ltr"><div>I think the table setup pattern have some opportunity for reducing code duplication before it gets re-used by other panels..  <br></div><div><br></div><div>We used to just need to write one file to define a table, now we have to write 9 files [1].  Can we have a table directive to reduce the duplicated code before moving forward to other panels?</div><div><br></div><div>-Lin</div><div><br></div><div>[1] <a href="https://github.com/openstack/horizon/tree/master/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/table" target="_blank">https://github.com/openstack/horizon/tree/master/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/table</a><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Aug 18, 2015 at 11:49 AM, Thai Q Tran <span dir="ltr"><<a href="mailto:tqtran@us.ibm.com" target="_blank">tqtran@us.ibm.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><font face="Default Sans Serif,Verdana,Arial,Helvetica,sans-serif" size="2">Hi everyone,<div><br></div><div>Just wanted to keep everyone up to date on the angular panels work. The goal was to set a pattern that others can follow, to that end, there were a few requirements:</div><div>1. reusable and possibly pluggable</div><div>2. easy to understand</div><div>3. reduce code duplication</div><div><br></div><div>These requirements don't always go hand-in-hand, and that is the primary reason why it is taking a bit longer. I believe we are nearing the end of it, here are some items remaining that I believe is crucial to finishing up this work.</div><div><br></div><div>a. i18n was completed, so we need help moving gettext blobs to HTML templates (example patch: <a href="https://review.openstack.org/#/c/210366/" target="_blank">https://review.openstack.org/#/c/210366/</a> ) volunteers are welcomed! We want others to use the translate directive as the main way to translate text blobs, this was why we went down this road using babel and angular_extractor plugin.</div><div><br></div><div>b. transfer table supports clone feature ( <a href="https://review.openstack.org/#/c/211345/" target="_blank">https://review.openstack.org/#/c/211345/</a> ). There were a lot of template duplications, this clone feature reduces the HTML by a considerable amount. Since this is something we use quite often, it made sense to invest time into improving it. We have had complaints that there was too much HTML fragments, this will address a bit of that. One of the challenge was to get it working with existing launch-instance, so I spent about 2 weeks making sure it worked well with the old code while allowing the new clone feature.</div><div><br></div><div>c. I believe we have a pretty good pattern setup for tables. The final piece of the puzzle was the patterns for various actions. We have wizard (create user), form (edit user), confirmation dialog (delete user), and actions with no modal dialog (enable user). We wanted a general pattern that would address the requirements mentioned above. There were some discussions around extensibility at the midcycle that I think will fit well here as well ( <a href="https://blueprints.launchpad.net/horizon/+spec/angular-workflow-plugin" target="_blank">https://blueprints.launchpad.net/horizon/+spec/angular-workflow-plugin</a> ). The actions can follow a similar pattern to workflow. I believe this pattern would address #1 and #3 but making it easy to understand is a bit challenging - I think this is where documentation could help. </div><div><br></div><div><a href="https://review.openstack.org/#/c/202315/" target="_blank">https://review.openstack.org/#/c/202315/</a> and a few other patches are going to be ready for review soon (sometime end of this week)! <span style="font-size:12.8000001907349px">Item #c is the most important piece, it is going to be the general pattern that people will use to build their angular panels with, so the more eyes we can get on it, the better. </span><span style="font-size:12.8000001907349px">My aim is to get it in before the feature freeze and I think that is entirely possible with your help. So please help review even if you are not a core!</span></div><div><span style="font-size:12.8000001907349px"><br></span></div><div><span style="font-size:12.8000001907349px">Thanks</span></div><div><br></div><div><br></div></font><br>
<br>__________________________________________________________________________<br>OpenStack Development Mailing List (not for usage questions)<br>Unsubscribe: <a href="http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe" rel="noreferrer" target="_blank">OpenStack-dev-request@lists.openstack.org?subject:unsubscribe</a><br><a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" rel="noreferrer" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a><br><br></blockquote></div><br></div><div><font face="Courier New,Courier,monospace" size="3">__________________________________________________________________________<br>OpenStack Development Mailing List (not for usage questions)<br>Unsubscribe: <a href="mailto:OpenStack-dev-request@lists.openstack.org?subject" target="_blank">OpenStack-dev-request@lists.openstack.org?subject</a>:unsubscribe<br><a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a><br></font></div></div></div></div></div></font><br>

<br>__________________________________________________________________________<br>OpenStack Development Mailing List (not for usage questions)<br>Unsubscribe: <a href="http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe" rel="noreferrer" target="_blank">OpenStack-dev-request@lists.openstack.org?subject:unsubscribe</a><br><a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" rel="noreferrer" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a><br><br></blockquote></div><br></div><div><font face="Courier New,Courier,monospace" size="3">__________________________________________________________________________<br>OpenStack Development Mailing List (not for usage questions)<br>Unsubscribe: <a href="mailto:OpenStack-dev-request@lists.openstack.org?subject" target="_blank">OpenStack-dev-request@lists.openstack.org?subject</a>:unsubscribe<br><a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a><br></font></div></div></div></div></font><br>


</div></blockquote><blockquote type="cite"><div><span>__________________________________________________________________________</span><br><span>OpenStack Development Mailing List (not for usage questions)</span><br><span>Unsubscribe: <a href="mailto:OpenStack-dev-request@lists.openstack.org" target="_blank">OpenStack-dev-request@lists.openstack.org</a>?subject:unsubscribe</span><br><span><a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a></span><br></div></blockquote></div></div></div><br>__________________________________________________________________________<br>
OpenStack Development Mailing List (not for usage questions)<br>
Unsubscribe: <a href="http://OpenStack-dev-request@lists.openstack.org?subject:unsubscribe" rel="noreferrer" target="_blank">OpenStack-dev-request@lists.openstack.org?subject:unsubscribe</a><br>
<a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev" rel="noreferrer" target="_blank">http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</a><br>
<br></blockquote></div><br></div>