Tags:
not added yet
Dashboard Widgets
Table of Contents
Dashboards are similar to Wiki pages, but whereas Wiki pages mostly contain static content, Dashboards mostly contain dynamic content, that is provided by Widgets.
Widget Developer's GuideQuickstart GuideCheck the Widget Development and Deployment Quickstart Guide first to see a working Widget project. Custom Widget ImplementationWidget framework introduced in codeBeamer 8.0 aims to simplify the development of new widgets and at the same time offer as much freedom as possible for Widget developers. The following 5 classes define a Widget in the system:
Please note that the implementation examples use Spring dependency injection mechanism. It is mandatory to annotate the Widget, WidgetInformation and WidgetFactory implementations with @Component, otherwise the Widget framework will not pick the custom Widget up. The following sections show how to implement these interfaces through annotated code examples. BasicsWidgetInformation interfaceLet's look at the WidgetInformation interface at first. This class is going to represent the Widget in the Widget catalog. (So this is the one, which directly affects what is displayed in the Widget Browser popup.) package com.intland.codebeamer.dashboard.component.widgets.wiki; import org.springframework.stereotype.Component; import com.intland.codebeamer.dashboard.component.common.interfaces.WidgetInformation; import com.intland.codebeamer.dashboard.component.widgets.common.WidgetCategory; // Annotation required to make it available in the system. @Component public class WikiMarkupWidgetInformation implements WidgetInformation { // Defines the category, which affects on which tab in Widget popup it appears. //Possible values: ALL, CHART, PROJECT, AGILE, TEST, PERSONAL_CONTENT, OTHER @Override public String getCategory() { return WidgetCategory.OTHER.getName(); } // Custom icon for the Widget. @Override public String getImagePreviewUrl() { return "/images/newskin/dashboard/thumbnails/icon_wiki_markup.png"; } // Knowledgebase url on codebeamer.com, reserved for built-in widgets. @Override public String getKnowledgeBaseUrl() { return ""; } // Vendor information. @Override public String getVendor() { return "Intland"; } // Key in ApplicationResources.properties, which defines the short name of the Widget. @Override public String getName() { return "dashboard.wiki.markup.widget.name"; } // Key in ApplicationProperties.properties, which contains the description for the Widget. @Override public String getShortDescription() { return "dashboard.wiki.markup.widget.short.description"; } // Reserved for future use. @Override public WikiMarkupWidgetFactory getFactory() { return null; } // Type name of the related Widget class. @Override public String getType() { return WikiMarkupWidget.class.getCanonicalName(); } } Widget InterfaceImplementation of this interface is the hearth of any Widget. It represents the Widget in the persistence layer of the framework, and also contains the logic, which renders the content and editor. Direct implementation is not recommended, instead inherit from the AbstractWidget class, which already has the implementation for common features. Let's look at the interfaces first: package com.intland.codebeamer.dashboard.component.common.interfaces; import com.intland.codebeamer.dashboard.component.common.RenderingContext; public interface LayoutComponent { // Unique identifier of the component String getId(); // Renders the component as HTML fragment (not a standalone HTML page) String renderToHtml(RenderingContext renderingContext); } package com.intland.codebeamer.dashboard.component.common.interfaces; import java.util.Map; import com.intland.codebeamer.dashboard.component.common.RenderingContext; import com.intland.codebeamer.dashboard.component.serializer.JacksonSerializableObject; import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute; public interface Widget extends LayoutComponent, JacksonSerializableObject { // Renders the editor for the Widget as HTML fragment (not a standalone HTML page) String renderEditorToHtml(RenderingContext renderingContext); // Attributes of the widget. These are typed values, which might represent just a simple text or more complex entities like a list of projects. Map<String, WidgetAttribute> getAttributes(); // Setter for the title of the Widget. void setTitle(String title); // Reserved for future use. void setFullWidth(boolean isFullWidth); // Reserved for future use. boolean isFullWidth(); // Sets the color of the Widget header. void setColor(String color); // Reserved for future use. void setHeaderHidden(boolean headerHidden); // Returns a key from ApplicationResources.properties, which defines the default title for the Widget. String getDefaultTitleKey(); } And continue with the AbstractWidget class: package com.intland.codebeamer.dashboard.component.widgets.common; import java.util.Map; import org.apache.commons.lang3.Validate; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.intland.codebeamer.dashboard.component.common.interfaces.Widget; import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute; // Important to have these annotations to ensure that the persistance layer saves the Widget properly @JsonIgnoreProperties(ignoreUnknown = true) @JsonPropertyOrder(alphabetic = true) public abstract class AbstractWidget implements Widget { protected static final String NULL_MESSAGE_FORMAT = "The value %s must not be null."; // Identifier of the Widget protected final String id; // CURRENT attributes of the widget protected final Map<String, WidgetAttribute> attributes; // Title of the widget protected String title; // Reserved for future use protected boolean isFullWidth; // Color of the header protected String color; // Reserved for future use. protected boolean headerHidden; public AbstractWidget(String id, Map<String, WidgetAttribute> attributes) { Validate.notBlank(id, NULL_MESSAGE_FORMAT, "id"); Validate.notNull(attributes, NULL_MESSAGE_FORMAT, "attributes"); this.id = id; this.attributes = attributes; } // Getters and setter omitted. } Finally have a look at a real example: package com.intland.codebeamer.dashboard.component.widgets.wiki; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.Validate; import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.intland.codebeamer.dashboard.component.common.RenderingContext; import com.intland.codebeamer.dashboard.component.common.interfaces.Renderer; import com.intland.codebeamer.dashboard.component.widgets.common.AbstractWidget; import com.intland.codebeamer.dashboard.component.widgets.common.attribute.TextAttribute; import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute; @JsonIgnoreProperties(ignoreUnknown = true) @JsonPropertyOrder(alphabetic=true) public class WikiMarkupWidget extends AbstractWidget { public static final String MARKUP_ATTRIBUTE_NAME = "markup"; public static final WidgetAttribute<String> DEFAULT_MARKUP_ATTRIBUTE = new TextAttribute("", true, false); // Preferred method to define default attributes public static Map<String, WidgetAttribute> getDescriptor() { final Map<String, WidgetAttribute> result = new HashMap<String, WidgetAttribute>(); result.put(MARKUP_ATTRIBUTE_NAME, DEFAULT_MARKUP_ATTRIBUTE); return result; } // Renderer instance, which can create the content of the Widget private final Renderer<WikiMarkupWidget> htmlRenderer; // Renderer instance, which can create the editor form for the Widget private final Renderer<WikiMarkupWidget> editorRenderer; // Annotated constructor used by the persistance layer. Please don"t forget to add these annotations!" public WikiMarkupWidget(@JsonProperty("id") final String id, @JsonProperty("attributes") final Map<String, WidgetAttribute> attributes, @JacksonInject("wikiMarkupWidgetHtmlRenderer") final Renderer<WikiMarkupWidget> htmlRenderer, @JacksonInject("wikiMarkupWidgetEditorRenderer") final Renderer<WikiMarkupWidget> editorRenderer) { super(id, attributes); Validate.notNull(htmlRenderer, NULL_MESSAGE_FORMAT, "htmlRenderer"); Validate.notNull(editorRenderer, NULL_MESSAGE_FORMAT, "editorRenderer"); this.htmlRenderer = htmlRenderer; this.editorRenderer = editorRenderer; } @Override public String getTypeName() { return WikiMarkupWidget.class.getCanonicalName(); } // Recommended way to render the content of the Widget. @Override public String renderToHtml(final RenderingContext renderingContext) { return htmlRenderer.render(renderingContext, this); } // Recommended way to render the editor for of the Widget. @Override public String renderEditorToHtml(final RenderingContext renderingContext) { return editorRenderer.render(renderingContext, this); } @Override public String getDefaultTitleKey() { return "dashboard.wiki.markup.widget.name"; } } This example shows how a Widget can be implemented from scratch. We recommend however to extend the AbstractRendererWidget class, which already implements this pattern and contains important error handling code as well. Supporting classesWidgetAttribute subtypesSubtypes of this generic class represent the different data types, which can be used as parameter of Widgets. All the built-in subtypes have their own renderer, which coupled with some other supporting classes makes it possible to automatically generate the editor forms for each Widget. See the the following section about this possibility. But now, let's have a look at the class itself: package com.intland.codebeamer.dashboard.component.widgets.common.attribute; import java.util.Map; import org.apache.commons.lang3.Validate; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonTypeInfo; // Important annotations, which fine the persistance mechanism. @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="typeName") @JsonIgnoreProperties(ignoreUnknown = true) @JsonPropertyOrder(alphabetic=true) public abstract class WidgetAttribute<T> { protected static final String NULL_MESSAGE_FORMAT = "The value %s must not be null."; // CURRRENT value of the attribute. @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.WRAPPER_OBJECT, property="valueTypeName") T value; // Shows whether this attribute has to be filled on the editor form. protected final boolean required; // Shows whether this attribute has to be validated using additional validation logic. protected final boolean validationRequired; public WidgetAttribute(final T value, final boolean required, final boolean validationRequired) { Validate.notNull(value, NULL_MESSAGE_FORMAT, "value"); this.value = value; this.required = required; this.validationRequired = validationRequired; } // Getters and setters ommited. // Important method, all atrributes has to provide a way to parse values from a String representation. public abstract WidgetAttribute<T> convert(final String newValue); // If the attribute is affected by export / import mechanism (like using project ids), then the identifiers will be mapped by calling this method during the import. public void replaceIdsAfterImport(Map<Integer, Map<Integer, Integer>> ids) { } protected void setValue(T value) { this.value = value; } } Simple subtypes:
Subtypes representing codeBeamer entities:
Renderer interface and implementationsProviding content through Renderer instances is the preferred way in Widget framework. As you can see in the last example code, it allows to write a clean and straightforward Widget class by moving the potentially complex tasks of rendering the Widget content and editor forms to a standalone class. import com.intland.codebeamer.dashboard.component.common.RenderingContext; public interface Renderer<T> { String render(RenderingContext renderingContext, T object); } The render method basically creates a String value based on the current RenderingContext and given object. The interface by design does not enforce any technical solution to create the String representation of the object. The developers can use either a template-based or programmatic rendering depending on their preference or specifications. HTML content renderer has one restriction, the custom code must be wrapped in DIV element, which contains the identifier of the Widget like in this Velocity template: <div id="${id}"> ${html} </div> Now continue with a concrete implementation: package com.intland.codebeamer.dashboard.component.widgets.wiki; // Imports removed @Component @Qualifier("wikiMarkupWidgetHtmlRenderer") public class WikiMarkupWidgetHtmlRenderer implements Renderer<WikiMarkupWidget> { private static final String TEMPLATE = "wikimarkup-widget.vm"; @Autowired private WikiPageManager wikiPageManager; @Autowired private WikiMarkupProcessor wikiMarkupProcessor; @Override public String render(final RenderingContext renderingContext, final WikiMarkupWidget object) { // Initialization and argument checks (ommitted) // Use the arguments to retrieve the information required to render the wiki markup to html. final String id = object.getId(); final Map<String, WidgetAttribute> attributes = object.getAttributes(); final WidgetAttribute wikiMarkupAttribute = attributes.get(WikiMarkupWidget.MARKUP_ATTRIBUTE_NAME); final String markup = wikiMarkupAttribute.getValue() != null ? (String) wikiMarkupAttribute.getValue() : ""; // Transforming Wiki markup to HTML (omitted) // Add data to Velocity context velocityContext.put("id", id); velocityContext.put("html", html); final TemplateRenderer templateRenderer = TemplateRenderer.getInstance(); // Render Velocity template return templateRenderer.renderTemplateOnPath(TEMPLATE, velocityContext, new Parameters(renderingContext.getRequest().getLocale(), false)); } // Helper methods (omitted) } Rendering the content of the editor form can be simplified by using a support classes. These classes render the editor based on the Widget's attributes and the standard renderer, which creates the proper form element for each attribute. (All built-in WidgetAttribute types has their specific render.) At the time of writing we have an implementation, which is based on Velocity template, so using Velocity is mandatory in this type of Renderer implementations. package com.intland.codebeamer.dashboard.component.widgets.wiki; import org.apache.commons.lang3.Validate; import org.apache.velocity.VelocityContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.intland.codebeamer.dashboard.component.common.RenderingContext; import com.intland.codebeamer.dashboard.component.common.interfaces.Renderer; import com.intland.codebeamer.dashboard.component.widgets.common.ModelPopulator; import com.intland.codebeamer.utils.TemplateRenderer; import com.intland.codebeamer.utils.TemplateRenderer.Parameters; @Component @Qualifier("wikiMarkupWidgetEditorRenderer") public class WikiMarkupWidgetEditorRenderer implements Renderer<WikiMarkupWidget> { private static final String NULL_MESSAGE_FORMAT = "The value %s must not be null."; private static final String EDITOR_TEMPLATE = "wikimarkup-widget-editor.vm"; // This is the required helper class, which will generate the editor form elements private final ModelPopulator<VelocityContext> modelPopulator; private final TemplateRenderer templateRenderer; @Autowired public WikiMarkupWidgetEditorRenderer(final ModelPopulator<VelocityContext> modelPopulator, final TemplateRenderer templateRenderer) { Validate.notNull(modelPopulator, NULL_MESSAGE_FORMAT, "modelPopulator"); Validate.notNull(templateRenderer, NULL_MESSAGE_FORMAT, "templateRenderer"); this.modelPopulator = modelPopulator; this.templateRenderer = templateRenderer; } @Override public String render(final RenderingContext renderingContext, final WikiMarkupWidget wikiMarkupWidget) { Validate.notNull(renderingContext, NULL_MESSAGE_FORMAT, "renderingContext"); Validate.notNull(wikiMarkupWidget, NULL_MESSAGE_FORMAT, "wikiMarkupWidget"); // Create the Velocity context final VelocityContext velocityContext = new VelocityContext(); // Let the populator create the right HTML fragments for each attribute modelPopulator.populateAttributes(renderingContext, wikiMarkupWidget, WikiMarkupWidget.getDescriptor(), velocityContext); // Return the rendererd template return templateRenderer.renderTemplateOnPath(EDITOR_TEMPLATE, velocityContext, new Parameters(renderingContext.getRequest().getLocale(), false)); } } There is only one convention, which you must know here. The ModelPopulator adds each form element to the VelocityContext with the name defined by the Widget's descriptor. (WikiMarkupWidget.getDescriptor() in this case) So the template looks like: ${markup} <br/> Note: Although the form elements are generated, you can still add your own content through this template! RenderingContext implementationRenderingContext instance holds data, which might be useful when rendering HTML content. // Imports omitted public class RenderingContext { // The current user, who is viewing or editing the dashboard. private final UserDto user; // The current request instance. private final HttpServletRequest request; // WikiPageDto representing the actual Dashboard. private final WikiPageDto dashboard; // Utility class, which can be used to translate keys from ApplicationResources.properties to text private final LocalizedTextRetriever localizedTextRetriever; // Constructor, getters omitted } WidgetFactory interfaceAnother center piece in the Widget framework, implementations of this interface are used to create new instances of Widgets while loading a dashboard form the persistence layer and while creating or editing Widgets. package com.intland.codebeamer.dashboard.component.serializer; import com.fasterxml.jackson.databind.InjectableValues; public interface JacksonObjectDeserializeContext<T> { // Class of the Widget Class<T> getType(); // Full class name of the Widget String getTypeName(); // All the properties, which must be injected through dependncy injection into Widgets. (See the Jackson annotation on the example Widget constructor.) InjectableValues getInjectableValues(); } package com.intland.codebeamer.dashboard.component.common.interfaces; import com.intland.codebeamer.dashboard.component.serializer.JacksonObjectDeserializeContext; // Marker interface public interface LayoutComponentFactory<T extends LayoutComponent> extends JacksonObjectDeserializeContext<T> { } package com.intland.codebeamer.dashboard.component.common.interfaces; import java.util.Map; public interface WidgetFactory<T extends Widget> extends LayoutComponentFactory<T> { // Create an instance with the given attributes T createInstance(String id, Map<String, String> attributes); // Create an instance with the given attributes, run validations T createInstance(String id, Map<String, String> attributes, boolean validate); // Create an instance with default attribute values T createInstance(); } And finally an implementation example: package com.intland.codebeamer.dashboard.component.widgets.wiki; import java.util.Map; import java.util.UUID; import org.apache.commons.lang3.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.InjectableValues; import com.intland.codebeamer.dashboard.component.common.interfaces.Renderer; import com.intland.codebeamer.dashboard.component.common.interfaces.WidgetFactory; import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute; import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttributeMapper; @Component public class WikiMarkupWidgetFactory implements WidgetFactory<WikiMarkupWidget> { private static final String NULL_MESSAGE_FORMAT = "The value %s must not be null."; // The HMTL renderer private final Renderer<WikiMarkupWidget> htmlRenderer; // The editor form renderer private final Renderer<WikiMarkupWidget> editorRenderer; private final WidgetAttributeMapper widgetAttributeMapper; // Qualifiers are important here! @Autowired public WikiMarkupWidgetFactory(@Qualifier("wikiMarkupWidgetHtmlRenderer") final Renderer<WikiMarkupWidget> htmlRenderer, @Qualifier("wikiMarkupWidgetEditorRenderer") final Renderer<WikiMarkupWidget> editorRenderer, final WidgetAttributeMapper widgetAttributeMapper) { Validate.notNull(htmlRenderer, NULL_MESSAGE_FORMAT, "htmlRenderer"); Validate.notNull(editorRenderer, NULL_MESSAGE_FORMAT, "editorRenderer"); Validate.notNull(widgetAttributeMapper, NULL_MESSAGE_FORMAT, "widgetAttributeMapper"); this.htmlRenderer = htmlRenderer; this.editorRenderer = editorRenderer; this.widgetAttributeMapper = widgetAttributeMapper; } @Override public WikiMarkupWidget createInstance(String id, Map<String, String> attributes) { return createInstance(id, attributes, true); } @Override public WikiMarkupWidget createInstance(String id, Map<String, String> attributes, boolean validate) { Validate.notBlank(id, NULL_MESSAGE_FORMAT, "id"); Validate.notNull(attributes, NULL_MESSAGE_FORMAT, "attributes"); final Map<String, WidgetAttribute> widgetAttributes = widgetAttributeMapper.map(attributes, WikiMarkupWidget.getDescriptor(), validate); return new WikiMarkupWidget(id, widgetAttributes, htmlRenderer, editorRenderer); } // The Widget's default attributes are accessed via a static method' @Override public WikiMarkupWidget createInstance() { return new WikiMarkupWidget(UUID.randomUUID().toString(), WikiMarkupWidget.getDescriptor(), htmlRenderer, editorRenderer); } @Override public Class<WikiMarkupWidget> getType() { return WikiMarkupWidget.class; } @Override public String getTypeName() { return WikiMarkupWidget.class.getCanonicalName(); } // Add all the constructor attributes of the Widget class, which needs to be injected via dependency injection. Please make sure that the value's name here matches the Jackson annotation on the Widget itself! ("wikiMarkupWidgetHtmlRenderer" for example)' @Override public InjectableValues getInjectableValues() { final InjectableValues inject = new InjectableValues.Std() .addValue("wikiMarkupWidgetHtmlRenderer", htmlRenderer) .addValue("wikiMarkupWidgetEditorRenderer",editorRenderer); return inject; } } Wrapping existing Wiki plugins as WidgetsIf you have already written some Wiki plugins, then it is easy to reuse them as Widgets. There is no big difference between plugin-based Widgets and standalone Widgets, you need to create exactly the same classes. As you intend to use the Wiki plugin for the HTML representation, you need to pass the actual parameters of the Widget as arguments to the plugin and call its execute method to generate the HTML. Fortunately the framework offers a Renderer implementation, which simplfies this process. The AbstractDefaultWidgetHtmlRenderer defines a few important methods: import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import com.intland.codebeamer.dashboard.component.common.interfaces.Widget; import com.intland.codebeamer.dashboard.component.widgets.common.DefaultWidgetHtmlRenderer; import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute; import com.intland.codebeamer.dashboard.component.widgets.provider.WidgetAttributeValueProvider; import com.intland.codebeamer.wiki.plugins.base.AbstractCodeBeamerWikiPlugin; public abstract class AbstractDefaultWidgetHtmlRenderer<U extends Widget, Z extends AbstractCodeBeamerWikiPlugin> extends DefaultWidgetHtmlRenderer<U, Z>{ @Autowired public AbstractDefaultWidgetHtmlRenderer(ObjectFactory<Z> factory) { super(factory); } protected Map<String, String> createPluginParameters(Map<String, WidgetAttribute> attributes) { final Map<String, String> parameters = new HashMap<String, String>(); // Generates the parameters of the plugin using the WidgetAttributeValueProviders, code omitted createAdditionalParameters(attributes, parameters); return parameters; } // You can add any parameter here, which is not generated by a WidgetAttributeValueProvider instance protected void createAdditionalParameters(final Map<String, WidgetAttribute> attributes, final Map<String, String> parameters) { } // Returns the WidgetAttributes defined in the Widget itself protected abstract WidgetAttributeWrapper[] getWidgetAttributes(); // A list of WidgetAttributeValueProvider instances. These can map a WidgetAttribute to a Wiki plugin parameter. protected Map<WidgetAttributeWrapper, WidgetAttributeValueProvider> getValueProviders() { return Collections.emptyMap(); } } The WidgetAttributeValueProvider instances convert WidgetAttributes to String parameters according to the interface of the Wiki plugin. import java.util.Map; import com.intland.codebeamer.dashboard.component.widgets.common.WidgetAttributeWrapper; import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute; public interface WidgetAttributeValueProvider { String obtainValue(WidgetAttributeWrapper attribute, Map<String, WidgetAttribute> attributes); } A simple example can be converting an Integer: import com.intland.codebeamer.dashboard.component.widgets.common.attribute.WidgetAttribute; public abstract class AbstractIntegerValueProvider extends AbstractWidgetAttributeValueProvider<WidgetAttribute<Integer>> { @Override protected String convertWidgetAttributeToString(final WidgetAttribute<Integer> widgetAttribute) { return widgetAttribute.getValue().toString(); } } AbstractWidgetAttributeValueProvider class has the default implementation for obtainValue method, so subclasses only have to define the convertWidgetAttributeToString and getWidgetAttributeKey method. The latter should return the name of Wiki plugin parameter, like for example this class: import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @Qualifier("widthIntegerValueProvider") @Component public class WidthIntegerValueProvider extends AbstractIntegerValueProvider { public static final String WIDTH = "width"; @Override public String getWidgetAttributeKey() { return WIDTH; } } Now it is easy to wrap the plugin rendering within a custom Renderer: package com.intland.codebeamer.dashboard.component.widgets.project; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.Validate; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.intland.codebeamer.dashboard.component.widgets.common.AbstractDefaultWidgetHtmlRenderer; import com.intland.codebeamer.dashboard.component.widgets.common.WidgetAttributeWrapper; import com.intland.codebeamer.dashboard.component.widgets.provider.WidgetAttributeValueProvider; import com.intland.codebeamer.wiki.plugins.releaseganttchart.ReleaseGanttChartPlugin; @Component @Qualifier("releaseGanttChartWidgetHtmlRenderer") public class ReleaseGanttChartWidgetHtmlRenderer extends AbstractDefaultWidgetHtmlRenderer<ReleaseGanttChartWidget, ReleaseGanttChartPlugin> { private static final String NULL_MESSAGE_FORMAT = "The value %s must not be null."; private final WidgetAttributeValueProvider releaseListAttributeValueProvider; private final WidgetAttributeValueProvider heightAttributeValueProvider; @Autowired public ReleaseGanttChartWidgetHtmlRenderer(ObjectFactory<ReleaseGanttChartPlugin> objectFactory, @Qualifier("ganttReleaseListAttributeValueProvider") final WidgetAttributeValueProvider releaseListAttributeValueProvider, @Qualifier("ganttHeightAttributeProvider") final WidgetAttributeValueProvider heightAttributeValueProvider) { super(objectFactory); Validate.notNull(releaseListAttributeValueProvider, NULL_MESSAGE_FORMAT, "releaseListAttributeValueProvider"); Validate.notNull(heightAttributeValueProvider, NULL_MESSAGE_FORMAT, "heightAttributeValueProvider"); this.releaseListAttributeValueProvider = releaseListAttributeValueProvider; this.heightAttributeValueProvider = heightAttributeValueProvider; } @Override protected WidgetAttributeWrapper[] getWidgetAttributes() { return ReleaseGanttChartWidget.Attribute.values(); } @Override protected Map<WidgetAttributeWrapper, WidgetAttributeValueProvider> getValueProviders() { final Map<WidgetAttributeWrapper, WidgetAttributeValueProvider> valueProviders = new HashMap<WidgetAttributeWrapper, WidgetAttributeValueProvider>(); valueProviders.put(ReleaseGanttChartWidget.Attribute.RELEASE_IDS, releaseListAttributeValueProvider); valueProviders.put(ReleaseGanttChartWidget.Attribute.HEIGHT, heightAttributeValueProvider); return valueProviders; } }
See also:Widgets ,Widget Development and Deployment Quickstart Guide |
Fast Links
codebeamer Overview codebeamer Knowledge Base Services by Intland Software |
This website stores cookies on your computer. These cookies are used to improve your browsing experience, constantly optimize the functionality and content of our website, furthermore helps us to understand your interests and provide more personalized services to you, both on this website and through other media. With your permission we and our partners may use precise geolocation data and identification through device scanning. You may click accept to consent to our and our partners’ processing as described above. Please be aware that some processing of your personal data may not require your consent, but you have a right to object to such processing. By using our website, you acknowledge this notice of our cookie practices. By accepting and continuing to browse this site, you agree to this use. For more information about the cookies we use, please visit our Privacy Policy.Your preferences will apply to this website only.
Note that user-behavior analytics are being captured on this server for the purpose of improving the Codebeamer user experience.