Alfrescian

Alfresco from a developers point of view
RSS icon Email icon Home icon
  • Monitoring Alfresco with New Relic

    Posted on January 27th, 2012 jan No comments

    I came across New Relic a few days ago & decided after a few minutes that I HAVE to try out that cool.

    1. Step – the Basics

    My first step, adding a New relic agent to a tomcat server that runs Alfresco was pretty easy:

    1. SignUp to New Relic
    2. Download New Relics jar-Files
    3. Deploy them as described here: http://newrelic.com/docs/java/new-relic-for-java

    After some minutes I was able to use the New Relic WebClient & try out some basic application monitoring features like:

    • HTTP Response Times
    • SQL Response Times
    • JVM Monitoring (CPU, Heap, GC etc.)
    • Transaction Traces etc

    2. Step – Real User Monitoring

    But the most impressive feature is their “real user monitoring” – They monitor the end user browser performance by automatically adding a small JS snippet to each HTML page. If you’ve JSPs that may be done automatically, but iId like to monitor an Alfresco Share application.

    Hands-on:

    1st: A custom Freemarker TemplateMethod to be used within Share (or any other SURF webapp):

    package org.springframework.extensions.webscripts;
    public class NewRelicMethod extends org.springframework.extensions.webscripts.processor.BaseProcessorExtension
    {
    
        public String getBrowserTimingHeader(){
        	return com.newrelic.api.agent.NewRelic.getBrowserTimingHeader();
    	}
    
     	public String getBrowserTimingFooter(){
    		return com.newrelic.api.agent.NewRelic.getBrowserTimingFooter();
    
    	}
    }
    

    2nd: Spring Bean definition web-extension/custom-newrelic-context.xml:

    <![CDATA[
    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
    <beans>
       <bean id="newrelicTemplateExtension" parent="baseTemplateExtension" class="org.springframework.extensions.webscripts.NewRelicMethod">
           <property name="extensionName">
               <value>newrelic</value>
           </property>
       </bean>
    </beans>]]>
    

    3rd: Add ${newrelic.browserTimingHeader} & ${newrelic.browserTimingFooter} alfresco/templates/org/alfresco/include/alfresco-template.ftl

    <#import "../import/alfresco-common.ftl" as common />
    
    <#-- Global flags retrieved from share-config (or share-config-custom) -->
    <#assign DEBUG=(common.globalConfig("client-debug", "false") = "true")>
    <#assign AUTOLOGGING=(common.globalConfig("client-debug-autologging", "false") = "true")>
    <#-- allow theme to be specified in url args - helps debugging themes -->
    <#assign theme = (page.url.args.theme!theme)?html />
    <#-- Portlet container detection -->
    <#assign PORTLET=(context.attributes.portletHost!false)>
    
    <#-- Look up page title from message bundles where possible -->
    <#assign pageTitle = page.title />
    <#if page.titleId??>
       <#assign pageTitle = (msg(page.titleId))!page.title>
    </#if>
    <#if context.properties["page-titleId"]??>
       <#assign pageTitle = msg(context.properties["page-titleId"])>
    </#if>
    
    <#--
       JavaScript minimisation via YUI Compressor.
    -->
    <#macro script type src>
       <script type="${type}" src="${DEBUG?string(src, src?replace(".js", "-min.js"))}"></script>
    </#macro>
    <#--
       Stylesheets gathered and rendered using @import to workaround IEBug KB262161
    -->
    <#assign templateStylesheets = []>
    <#macro link rel type href>
       <#assign templateStylesheets = templateStylesheets + [href]>
    </#macro>
    <#macro renderStylesheets>
       <style type="text/css" media="screen">
       <#list templateStylesheets as href>
          @import "${href}";
       </#list>
       </style>
    </#macro>
    
    <#--
       Template "templateHeader" macro.
       Includes preloaded YUI assets and essential site-wide libraries.
    -->
    <#macro templateHeader doctype="strict">
    <#if !PORTLET>
       <#if doctype = "strict">
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
       <#else>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       </#if>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
       <title>${msg("page.title", pageTitle)}</title>
       <meta http-equiv="X-UA-Compatible" content="Edge" />
    </#if>
        <#if !context.requestContext.passiveMode>
    		${newrelic.browserTimingHeader}
        </#if>
    
    <!-- Shortcut Icons -->
       <link rel="shortcut icon" href="${url.context}/res/favicon.ico" type="image/vnd.microsoft.icon" />
       <link rel="icon" href="${url.context}/res/favicon.ico" type="image/vnd.microsoft.icon" />
    
    <!-- Site-wide YUI Assets -->
       <@link rel="stylesheet" type="text/css" href="${url.context}/res/css/yui-fonts-grids.css" />
       <#if theme = 'default'>
          <@link rel="stylesheet" type="text/css" href="${url.context}/res/yui/assets/skins/default/skin.css" />
       <#else>
          <@link rel="stylesheet" type="text/css" href="${url.context}/res/themes/${theme}/yui/assets/skin.css" />
       </#if>
    <#-- Selected components preloaded here for better UI experience. -->
    <#if DEBUG>
       <script type="text/javascript" src="${url.context}/res/js/log4javascript.v1.4.1.js"></script>
    <!-- Common YUI components: DEBUG -->
       <script type="text/javascript" src="${url.context}/res/yui/yahoo/yahoo-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/event/event-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/dom/dom-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/dragdrop/dragdrop-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/animation/animation-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/logger/logger-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/connection/connection-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/element/element-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/get/get-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/yuiloader/yuiloader-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/button/button-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/container/container-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/menu/menu-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/json/json-debug.js"></script>
       <script type="text/javascript" src="${url.context}/res/yui/selector/selector-debug.js"></script>
    <!-- YUI Patches -->
       <script type="text/javascript" src="${url.context}/res/yui/yui-patch.js"></script>
       <script type="text/javascript">//<![CDATA[
          YAHOO.util.Event.throwErrors = true;
       //]]></script>
    <#else>
    <!-- Common YUI components: RELEASE concatenated -->
       <script type="text/javascript" src="${url.context}/res/js/yui-common.js"></script>
    </#if>
    
    <!-- Site-wide Common Assets -->
    <#if PORTLET>
       <@link rel="stylesheet" type="text/css" href="${url.context}/res/css/portlet.css" />
    </#if>
       <@link rel="stylesheet" type="text/css" href="${url.context}/res/css/base.css" />
       <@link rel="stylesheet" type="text/css" href="${url.context}/res/css/yui-layout.css" />
       <@link rel="stylesheet" type="text/css" href="${url.context}/res/themes/${theme}/presentation.css" />
       <@script type="text/javascript" src="${url.context}/res/js/bubbling.v2.1.js"></@script>
       <script type="text/javascript">//<![CDATA[
          YAHOO.Bubbling.unsubscribe = function(layer, handler)
          {
             this.bubble[layer].unsubscribe(handler);
          }
       //]]></script>
       <@script type="text/javascript" src="${url.context}/res/js/flash/AC_OETags.js"></@script>
       <#-- NOTE: Do not attempt to load -min.js version of messages.js -->
       <script type="text/javascript" src="${url.context}/service/messages.js?locale=${locale}"></script>
       <script type="text/javascript">//<![CDATA[
          Alfresco.constants = Alfresco.constants || {};
          Alfresco.constants.DEBUG = ${DEBUG?string};
          Alfresco.constants.AUTOLOGGING = ${AUTOLOGGING?string};
          Alfresco.constants.PROXY_URI = window.location.protocol + "//" + window.location.host + "${url.context}/proxy/alfresco/";
          Alfresco.constants.PROXY_URI_RELATIVE = "${url.context}/proxy/alfresco/";
          Alfresco.constants.PROXY_FEED_URI = window.location.protocol + "//" + window.location.host + "${url.context}/proxy/alfresco-feed/";
          Alfresco.constants.THEME = "${theme}";
          Alfresco.constants.URL_CONTEXT = "${url.context}/";
          Alfresco.constants.URL_RESCONTEXT = "${url.context}/res/";
          Alfresco.constants.URL_PAGECONTEXT = "${url.context}/page/";
          Alfresco.constants.URL_SERVICECONTEXT = "${url.context}/service/";
          Alfresco.constants.URL_FEEDSERVICECONTEXT = "${url.context}/feedservice/";
          Alfresco.constants.USERNAME = "${user.name!""}";
          Alfresco.constants.SITE = "${(page.url.templateArgs.site!"")?js_string}";
          Alfresco.constants.PAGEID = "${(page.url.templateArgs.pageid!"")?js_string}";
          Alfresco.constants.PORTLET = ${(context.attributes.portletHost!false)?string};
          Alfresco.constants.PORTLET_URL = unescape("${(context.attributes.portletUrl!"")?js_string}");
          Alfresco.constants.JS_LOCALE = "${locale}";
       <#if PORTLET>
          document.cookie = "JSESSIONID=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${url.context}";
       </#if>
       //]]></script>
       <@script type="text/javascript" src="${url.context}/res/js/alfresco.js"></@script>
       <@script type="text/javascript" src="${url.context}/res/js/forms-runtime.js"></@script>
       <@script type="text/javascript" src="${url.context}/res/js/share.js"></@script>
       <@common.uriTemplates />
       <@common.helpPages />
       <@common.htmlEditor htmlEditor="tinyMCE"/>
    
       <!-- Share Preference keys -->
       <script type="text/javascript">//<![CDATA[
          Alfresco.service.Preferences.FAVOURITE_DOCUMENTS = "org.alfresco.share.documents.favourites";
          Alfresco.service.Preferences.FAVOURITE_FOLDERS = "org.alfresco.share.folders.favourites";
          Alfresco.service.Preferences.FAVOURITE_SITES = "org.alfresco.share.sites.favourites";
          Alfresco.service.Preferences.IMAP_FAVOURITE_SITES = "org.alfresco.share.sites.imapFavourites";
          Alfresco.service.Preferences.COLLAPSED_TWISTERS = "org.alfresco.share.twisters.collapsed";
          Alfresco.service.Preferences.RULE_PROPERTY_SETTINGS = "org.alfresco.share.rule.properties";
       //]]></script>
    
    <!-- Template Assets -->
    <#nested>
    <@renderStylesheets />
    
    <!-- Component Assets -->
    ${head}
    
    <!-- MSIE CSS fix overrides -->
       <!--[if lt IE 7]><link rel="stylesheet" type="text/css" href="${url.context}/res/css/ie6.css" /><![endif]-->
       <!--[if IE 7]><link rel="stylesheet" type="text/css" href="${url.context}/res/css/ie7.css" /><![endif]-->
    <#if !PORTLET>
    </head>
    </#if>
    </#macro>
    
    <#--
       Template "templateHtmlEditorAssets" macro.
       Loads wrappers for Rich Text editors.
    -->
    <#macro templateHtmlEditorAssets>
    <!-- HTML Editor Assets -->
       <script type="text/javascript" src="${page.url.context}/res/modules/editors/tiny_mce/tiny_mce${DEBUG?string("_src", "")}.js"></script>
       <@script type="text/javascript" src="${page.url.context}/res/modules/editors/tiny_mce.js"></@script>
       <@script type="text/javascript" src="${page.url.context}/res/modules/editors/yui_editor.js"></@script>
    </#macro>
    
    <#--
       Template "templateBody" macro.
       Pulls in main template body.
    -->
    <#macro templateBody>
    <#if !PORTLET>
    <body id="Share" class="yui-skin-${theme} alfresco-share">
    </#if>
       <div class="sticky-wrapper">
          <div id="doc3">
    <#-- Template-specific body markup -->
    <#nested>
          </div>
          <div class="sticky-push"></div>
       </div>
    </#macro>
    
    <#--
       Template "templateFooter" macro.
       Pulls in template footer.
    -->
    <#macro templateFooter>
       <div class="sticky-footer">
    <#-- Template-specific footer markup -->
    <#nested>
       </div>
    <#-- This function call MUST come after all other component includes. -->
       <div id="alfresco-yuiloader"></div>
       <#-- In portlet mode, Share doesn't own the <body> tag -->
       <script type="text/javascript">//<![CDATA[
          Alfresco.util.YUILoaderHelper.loadComponents(true);
          if (Alfresco.constants.PORTLET)
          {
             YUIDom.addClass(document.body, "yui-skin-${theme} alfresco-share");
          }
       //]]></script>
     <#if !context.requestContext.passiveMode>
    	${newrelic.browserTimingFooter}
     </#if>
    <#if !PORTLET>
    </body>
    </html>
    </#if>
    </#macro>
    

    –> You’ll get some nice charts like these:

  • Alfresco Share datalist extensions – now Open Source!

    Posted on January 16th, 2012 jan 1 comment

    I’ve developed some extensions to the default Alfresco Share datalists some months ago. My former blog post (http://blog.alfrescian.com/?p=95) gained a lot of interests at Alfresco & also in the Alfresco Community.

    As part of my discussions with fme’s customer and Alfresco regarding a contribution of this extensions one of Alfresco’s Solution Engineers did a code review and was very satisfied with it: https://twitter.com/#!/rjmfernandes/status/136437605981097985

    Finally fme’s customer agreed to make this extensions available under Open Source (Apache License) here: http://code.google.com/p/fme-alfresco-extensions/wiki/DatalistExtension

    This gives the whole Alfresco community the opportunity to use & improve the extensions we made. So, please feel free to contact me if you like to contribute back some additional features or if you like to sponsor the further development (e.g. an upgrade to 4.0).

  • Alfresco Share Cluster – tweaks

    Posted on January 9th, 2012 jan 9 comments

    I recently faced an upgrade from a single node Alfresco into a high available (HA) configuration (1 Load-Balancer, 2 Alfresco Nodes, 2 Share Nodes) using Alfresco Enterprise 3.4.2 (including kerberos SSO etc.).

    The Basic steps (@see Kevs blog post http://blogs.alfresco.com/wp/kevinr/2011/07/28/using-apache-to-load-balance-alfresco-share-with-an-alfresco-repository-cluster-and-clustering-alfresco-share/) went well & my new system performed well. But then I realized that changes to a Share dashboard weren’t visible on the other Share instance. I forget to add the following configuration (“custom-slingshot-application-context.xml”):

    <bean id="webframework.slingshot.persister.remote" class="org.springframework.extensions.surf.persister.PathStoreObjectPersister" parent="webframework.sitedata.persister.abstract">
          <property name="store" ref="webframework.webapp.store.remote" />
          <property name="pathPrefix"><value>alfresco/site-data/${objectTypeIds}</value></property>
          <property name="noncachableObjectTypes">
             <set>
                <value>page</value>
                <value>component</value>
             </set>
          </property>
       </bean>
    

    But now my Share instances were very slow (dashboard layout changes weren’t visible on the other Share instance either). Loading a dashboard in the browser took up to 8s – without that cache disabling ~2s. Thus I made some tests with a vanilla 3.4.2 & 3.4.6 system and observed the same behavior (not as slow because I didn’t created a few hundred sites & >2000 users in my local system).

    First of all I backported the 4.0.c org.springframework.extensions.webscripts.RequestCachingConnector that improved the whole Share performance a little bit. Afterwards I thought about the situations when a cached SURF object must be invalidated and reloaded via its remote store. AFAIK the only moment is when a dashboard configuration is changed on another Share instance. As my configuration only incorporates 2 Share instances I developed the follwing simple tweak to notify the other Share instance if a dashboard config is changed & the Surf object cache should be invalidated:

      re-enable caching for component & pages

    1. add a new HTTP endpoint (used to notify the other Share instance via HTTP if the SURF caches should be invalidated):
      <config evaluator="string-compare" condition="Remote">
      	  <remote>
      
      		<!-- Connector instance -->
      		<connector>
      			<id>share-cluster</id>
      			<name>Share Cluster Connector</name>
      			<description>HTTP Connector used to notify other share cluster nodes if surf object cache should be invalidated</description>
      			<class>org.springframework.extensions.webscripts.connector.HttpConnector</class>
      		</connector>
      
      		<!-- Endpoint -->
      	    <endpoint>
      	      <id>share-cluster</id>
      	      <name>Share Cluster Remote API</name>
      	      <connector-id>share-cluster</connector-id>
      	      <endpoint-url>http://[other-node]:8080/share/service</endpoint-url>
      	      <identity>none</identity>
      	    </endpoint>
      
      	  </remote>
      	</config>
      
    2. append the following lines to site-webscripts\org\alfresco\components\dashboard\customise-dashboard.post.json.js:
      try{
      	var shareClusterConnector = remote.connect("share-cluster");
      	shareClusterConnector.post("/api/fme/cache", clientRequest, "application/json");
      }catch (exception){
      	//nothing to do
      }
      
    3. added a new Java-backed webscript (Share) mapped to URI api/fme/cache with following executeImpl():
      protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
          {
                  RequestContext rc = ThreadLocalRequestContext.getRequestContext();
                  CacheUtil.invalidateModelObjectServiceCache(rc);
      
                  // we must reset the SpringMVC view resolvers - as they maintain a reference to View
                  // object which could themselves reference pages or templates by ID
                  Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                          applicationContext, ViewResolver.class, true, false);
                  for (ViewResolver resolver : matchingBeans.values())
                  {
                      if (resolver instanceof AbstractCachingViewResolver)
                      {
                          logger.info("cleared AbstractCachingViewResolver " +resolver);
                          ((AbstractCachingViewResolver)resolver).clearCache();
                      }
                  }
              ...
          }
      

    The following things should be kept in mind:

    • this scenario only works with 2 Share instances & has to be enhanced if you’ve more than 2 nodes
    • api/fme/cache is not secured via an authenticator …

    I’ll fill (& link) a detailed jira issue shortly.

  • My Alfresco devcon panel discussion questions

    Posted on November 10th, 2011 jan 2 comments

    My Panel Discussion questions

    Search:
    - when will faceted search be supported in share (repo basics are already done…)
    - what about Solr & hit highlighting (searchservice & share UI)
    - will share search ui in 4.0 enterprise use solr paging capabilities

  • Alfresco Share 4.x feature wishlist

    Posted on October 11th, 2011 jan 7 comments

    Linton Baddeley (UX Designer at Alfresco) asked (tweet)

    What features would you like to see in the next version of #Alfresco Share

    here is my wishlist:

    • Enhanced Wiki component: TOC generation, embed document previews, add documents as attachment
    • Enhanced datalist component (http://blog.alfrescian.com/?p=95): versioning, comments as thread, upload&attach, XLS/PDF-Export/Import
    • datalist items assigned to a user or group should be shown in my task
    • Doclib: Link to Action, Export folder as zip, export selected documents as zip
    • doclib: optional grid view (configurable per site if standard or gridview should be used in doclib)
    • bidirectional Share calendar & MS Exchange integration ;-)
    • also copy & link as drag&drop operations
    • Yammer integration: publish document to yammer (link/attachment)
    • configurable documentlist dashlet: documents per tag, category, +Aspect, +Type…or simply a cmis/fts query
    • search: support solr highlighting, synonyms & facets OTB (configurable via *config.xml)
  • Adding a synonym list to SOLR in Alfresco 4.0

    Posted on October 3rd, 2011 jan 4 comments

    If you missed it: Alfresco Community 4.0.a is out: 
    http://wiki.alfresco.com/wiki/Alfresco_Community_4.0.a
    (and my category manager is part of the new feature list ;-) )

    One of my favorite new features is the new Apache Solr based Search Service. I’ve done an Alfresco-Solr integration project two years ago. I was very impressed by the power of Solr & mainly by the combination of Alfresco & Solr. Thus my first deeper look into Alfresco 4.0 was about to understand the new Solr based search service & how the “whole stuff” is working.

    After some hours browsing the current svn HEAD & researching Alfresco’s tracking, model & query addons to solr I tried to tweak Alfresco’s schema.xml:

    Task: Add basic support of synonyms

    Steps-to-do:

    1. Open alf_data/solr/workspace-SpacesStore/conf/schema.xml & add a new filter org.apache.solr.analysis.SynonymFilterFactory:
      <schema name="alfresco" version="1.0">
         <types>
            <fieldType name="alfrescoDataType" class="org.alfresco.solr.AlfrescoDataType">
               <analyzer>
                  <tokenizer class="org.apache.solr.analysis.WhitespaceTokenizerFactory" />
                  <filter class="org.apache.solr.analysis.WordDelimiterFilterFactory"
                      generateWordParts="1"
                      generateNumberParts="1"
                      catenateWords="1"
                      catenateNumbers="1"
                      catenateAll="1"
                      splitOnCaseChange="1"
                      splitOnNumerics="1"
                      preserveOriginal="1"
                     stemEnglishPossessive="1" />
                  <filter class="org.apache.solr.analysis.LowerCaseFilterFactory" />
                  <filter class="org.apache.solr.analysis.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true" />
               </analyzer>
            </fieldType>
         </types>
         <fields>
            <field name="ID" type="alfrescoDataType" indexed="true" omitNorms="true" stored="true" multiValued="true"></field>
            <dynamicField name="*" type="alfrescoDataType" indexed="true" omitNorms="true" stored="true" multiValued="true"></dynamicField>
         </fields>
         <uniqueKey>ID</uniqueKey>
         <defaultSearchField>ID</defaultSearchField>
      </schema>
      
    2. Stop your
    3. Delete your Solr workspaceSpacesStore data dir: alf_data/solr/workspace
    4. Start your tomcat
    5. login to Alfresco Share a create a new txt file containing “television” and “GB”
    6. wait a few seconds (solr indexing is done async!) & execute search for “TV” –> you doc should be in the result set, because “TV” is a synonym for television (alf_data/solr/workspace-SpacesStore/conf/synonyms.txt)
    7. execute search for “gigabyte” –> you doc should be in the result set, because “gigabyte” is a synonym for “GB”

    welcome to the new shiny Alfresco-SOLR world ;-)

    Ok…it’s quick hack because the synonyms will be used for every property/field, but it is a good starting point :-)

  • Alfresco Share datalist extensions

    Posted on July 22nd, 2011 jan 20 comments

    A customer of my company (www.fme.de) asked me to develop some extensions for Alfresco Share datalist:

    ID generation:

    automatic generation of an ID for each item. These IDs are generated using a separate ID sequence on each datalist.

    Read-only/view dialog

    Double clicking an item display a view-mode form via FormService.

     

    Auto versioning

    Aspect cm:versionable with auto-version on property changes is applied to each item. A custom policy triggers versioning if an association was modified  - e.g. dl:assignee.

    To display version history a new FormService control was implemented. Via show version link the selected version will be display in another view-mode dialog.

    Comments (fm:discussable)

    Alfresco only supports a simple comment field, but you often like to have  a discussion thread as you have in doclib. Hence I added support of fm:discussable aspect to datalist items.

    Ellipsis for long text

    Per default the whole text of a property is displayed in the datagrid. If you’ve longer text – e.g. in cm:description – your datagrid layout will be suboptimal.

    So, I added an ellipsis feature for text longer than 40 chars. The whole text will be displayed as tooltip on mouse over.

     

    Upload & Attach

    To allow attaching a file to a datalist item that isn’t already stored in the repo an upload&attach action was added to cm:attachment-control.

    After you’ve choosen the upload destination directory (reused global-folder.js here) you’ll get the normal upload dialog.

    Unable to display content. Adobe Flash is required.

    XLS-Export

    Nick Burch had already developed a basic XLS-export WebScript. I resused that one & added support for fm:discussable comment threads.

    XLS-Export button is displayed in the datalist toolbar.

    Unable to display content. Adobe Flash is required.

     

    Form-based filters

    my last step was to provide form based filters for each datalist. Hence I configured a filter-form for each datalist-type & extended the filter logic of datagrid.js via JS/YUI augment/extend mechanism.

    These form based filters support browser history & URL addressability and are collapsable via Alfresco.util.Twister.


    Unable to display content. Adobe Flash is required.

     

    I made another screencast that demonstrates most of the features in common:

    Unable to display content. Adobe Flash is required.

     

    I guess some of them are useful for every Alfresco Share installations. Thus me, fme and our client are willing to contribute these extensions.

  • a worldwide project swift launch codeCamp

    Posted on July 19th, 2011 jan 4 comments

    I had a short chat with Jeff Potts & Bernard Werner (both Alfresco) regarding the Alfresco community a few days ago.

    Besides some discussion especially regarding Alfresco’s community in D A CH,  I made the following proposal that I’d like to propagate here:

    Currently Alfresco is developing the next “big” Alfresco version with code name swift – I bet it will be Alfresco 4.0. What I proposed to Jeff is to organize a worldwide – but local – Alfresco CodeCamp when 4.0 is launched. I mean a worldwide series of local Alfresco CodeCamps regarding new stuff in 4.0 (Solr, Social enhancements etc.) (nearly) simultaneous.

    I guess that will be a big distributed event… & yes, of course John Newton should make an online Key Note ;-)

    What do you think?

  • Alfresco Share Category Manager – Finished

    Posted on April 18th, 2011 jan 11 comments

    I’ve started to develop a Category Manager as Alfresco Share admin console plugin as few days ago: http://blog.alfrescian.com/?p=65

    It’s now complete – edit, add & delete are implemented:

    Unable to display content. Adobe Flash is required.

    I’ve still to clean up the code & do some testing with Alfresco 3.4 & 3.3. I’m expecting to backport some Alfresco.widget.InsituEditor…

    I’ll contribute the Category Manager once this “additional work” is done.

  • Alfresco Share Category Manager

    Posted on April 16th, 2011 jan 8 comments

    I took a look into current Alfresco HEAD a few days ago and recognized that a lot of new stuff is coming.

    One thing I was still missing is a Category Management tool. Thus, I started to implement such a Category Manager a few hours ago.

    That’s the current result:

    • I take the category tree component of the repo doclib
    • created a new admin console component
    • connected the new InsituEditor widget (Alfresco.util) with my category tree
    • wrote a new Repository-Webscript to save the changed category name (had a little fight with ALF-1788)

    So, change a category name is working, next step is to implement add/delete Category.

     

    Here is a screencast of the current result:

    Unable to display content. Adobe Flash is required.