Comments Panel

General

images/download/attachments/6044978/commentspanel0.PNG

Component Palette Icon:

images/download/attachments/6044978/commentspanel1.PNG


Additional information on the Comments Panel can be found on the Comments Panel Example page.

Looking for documentation on the legacy Comments Panel component? Please see the Legacy Comments Panel page.

Not sure which version you are looking at? The Legacy version of this component has several properties that the new one does not: "Insert Query 1", " Insert Query 2", "Delete Query", "Unstick Query", and "Download Attachment Query".

Description

The comments panel is used to power a blog-style comments system within your project. This can be useful for ad-hoc collaboration and communication between shifts, remote users, etc. This component is driven by a dataset that should be bound to a SQL query. Unlike most components, this component has built-in functionality to alter an external database. This is how the default Add Note functionality works. You have the opportunity to alter the queries that the components uses by enabling Extension Functions.

The schema that typically drives this component involves up to three tables:

  • The first table (by default: Notes) stores all of the notes across the board.

  • The second table (by default, ItemNotes) is used to associate notes with other things. This allows you to have different sets of notes for different screens/objects. Typically you'd bind the data to a query that joined these tables together restricting the second identifier in the ItemNotes table to the value appropriate for the window you're on.

  • The third table (by default: users) is a user mapping table that assigns an ID to each user on the table. This is easiest to do if a database authentication profile is used as the _users table automatically creates the required columns, but non-database authentication profiles can be used as long as the table is manually created and maintained.

You can opt out of this three-table system by simply making use of the Extension Functions on the component. See below for more details.

By default, users can remove their own comments, and comments can have files attached. To allow attachments, make sure you have a BLOB field in your notes table.

Behavior Description: Three-Table Configuration vs Custom

The following is a list of the default behaviors when all Extension Functions are disabled

Behavior

Description

Adding a note

Runs a SELECT query against the users table to retrieve the ID value for the user that added the note. Then stores this ID into the Notes table along with the rest of the note data

Deleting a note

Deletes a row from the Notes table. Uses the ID value from the Notes table to determine which row should be deleted. Does not delete a row from the ItemNotes table

Unsticking a note

Updates the sticky column for the note on the Notes table. Sets the value to 0 based on the ID of the note

Download an attachment from a note

Returns the binary data from the Attachment column on the Notes table.

Ability for users to delete notes

Users may not delete notes from other users, but are allowed to delete their own notes.

Enabling the Extension Functions on the component allow for custom functionality on the component. Some examples are:

  • Store all note data on a single database table - simply modify each Extension Function to run queries against a single database table

  • Save the attachment to a shared drive instead of a database column - modify insertNote to save the attachment to a hard drive.

  • Allow users to delete all notes by role - check the role of the user in canDelete and return True if the user has a specific role

Properties

Name

Description

Property Type

Scripting

Category

Add Note Text

The word(s) used for the "Add Note" button

String

.addNoteText

Appearance

Antialias

Enabled antialiasing when drawing the component

boolean

.antialias

Appearance

Attach File Text

The word(s) used for the "Attach File" link.

String

.attachText

Appearance

Attachments Enabled

Controls whether or not files can be attached to notes.

boolean

.attachmentsEnabled

Behavior

Border

The border surrounding this component. NOTE that the border is unaffected by rotation.

border

.border

Common

Cancel Text

The word(s) used for the "Cancel" button

String

.cancelText

Appearance

Data

Fill this DataSet in with the notes for the desired entity. Columns are: ID, Username, Timestamp, Note, Filename, IsSticky

Dataset

.data

Data

Data Quality

The data quality code for any tag bindings on this component.

int

.dataQuality

Data

Database Connection

Name of the database connection to run the queries against. Leave blank to use project's default connection

String

.datasource

Behavior

Date Format

The format string to use for the date of the note.

String

.dateFormat

Appearance

Display Mode

Horizontal display mode will layout so that the comment header will be positioned to the left of the comment. Vertical display mode will have the comment header above the comment.

int

.displayMode

Behavior

Enabled

If disabled, a component cannot be used.

boolean

.componentEnabled

Common

Font

Font of text on this component.

Font

.font

Appearance

Foreground Color

The foreground color of the component.

Color

.foreground

Appearance

Header Color

The background color of the header notes.

Color

.headersColor

Appearance

Maximum Attachment Size

The maximum attachment size in bytes that will be accepted. A value of 0 means no limit.

long

.maxAttachmentSize

Behavior

Mouseover Text

The text that is displayed in the tooltip which pops up on mouseover of this component.

String

.toolTipText

Common

Name

The name of this component.

String

.name

Common

Note Color

The background color for notes.

Color

.noteColor

Appearance

Padding

The amount of padding between the notes.

int

.padding

Appearance

Skip Audit

If true, update queries originating from this component will skip the audit system. Can be important when attachments are turned on.

boolean

.skipAudit

Behavior

Sticky Header Color

The background color of the header for sticky notes.

Color

.stickyHeaderColor

Appearance

Sticky Note Color

The background color for sticky notes.

Color

.stickyNoteColor

Appearance

Sticky Text

The word(s) used for the "Sticky" checkbox.

String

.stickyText

Appearance

Touchscreen Mode

Controls when this input component responds if touchscreen mode is enabled.

int

.touchscreenMode

Behavior

Visible

If disabled, the component will be hidden.

boolean

.visible

Common

Scripting
Scripting Functions

This component does not have scripting functions associated with it.

Extension Functions

insertNote

  • Description

Called when a note is added.

  • Parameters

component self - A reference to the component that is invoking this function

string note - The text contents of the note

string filename - The full filepath to the the attachment

string sticky - A boolean indicating whether this note should be flagged as stickied

  • Return

Nothing

  • Scope

Client

deleteNote

  • Description

Called when a user clicks the 'delete' link on a note.

  • Parameters

component self - A reference to the component that is invoking this function

integer id - The id of the note

  • Return

Nothing

  • Scope

Client

unstickNote

  • Description

Called when a user clicks the 'unstick' link on a note.

  • Parameters

component self - A reference to the component that is invoking this function

integer id - The id of the note

  • Return

Nothing

  • Scope

Client

downloadAttachment

  • Description

Called when a user attempts to download an attachment from a note.

  • Parameters

component self - A reference to the component that is invoking this function

integer id - The id of the note

  • Return

Nothing

  • Scope

Client

canDelete

  • Description

Returns whether or not a note with the given id can be deleted. Notes that return True will show a 'delete' link.

  • Parameters

component self - A reference to the component that is invoking this function

integer id - The id of the note

  • Return

boolean - Notes with a True return can be deleted by the user, False return can not be deleted.

  • Scope

Client

Event Handlers

mouse

mouseClicked

This event signifies a mouse click on the source component. A mouse click the combination of a mouse press and a mouse release, both of which must have occurred over the source component. Note that this event fires after the pressed and released events have fired.

.source

The component that fired this event

.button

The code for the button that caused this event to fire.

.clickCount

The number of mouse clicks associated with this event.

.x

The x-coordinate (with respect to the source component) of this mouse event.

.y

The y-coordinate (with respect to the source component) of this mouse event.

.popupTrigger

Returns True (1) if this mouse event is a popup trigger. What constitutes a popup trigger is operating system dependent, which is why this abstraction exists.

.altDown

True (1) if the Alt key was held down during this event, false (0) otherwise.

.controlDown

True (1) if the Control key was held down during this event, false (0) otherwise.

.shiftDown

True (1) if the Shift key was held down during this event, false (0) otherwise.

mouseEntered

This event fires when the mouse enters the space over the source component.

.source

The component that fired this event

.button

The code for the button that caused this event to fire.

.clickCount

The number of mouse clicks associated with this event.

.x

The x-coordinate (with respect to the source component) of this mouse event.

.y

The y-coordinate (with respect to the source component) of this mouse event.

.popupTrigger

Returns True (1) if this mouse event is a popup trigger. What constitutes a popup trigger is operating system dependent, which is why this abstraction exists.

.altDown

True (1) if the Alt key was held down during this event, false (0) otherwise.

.controlDown

True (1) if the Control key was held down during this event, false (0) otherwise.

.shiftDown

True (1) if the Shift key was held down during this event, false (0) otherwise.

mouseExited

This event fires when the mouse leaves the space over the source component.

.source

The component that fired this event

.button

The code for the button that caused this event to fire.

.clickCount

The number of mouse clicks associated with this event.

.x

The x-coordinate (with respect to the source component) of this mouse event.

.y

The y-coordinate (with respect to the source component) of this mouse event.

.popupTrigger

Returns True (1) if this mouse event is a popup trigger. What constitutes a popup trigger is operating system dependent, which is why this abstraction exists.

.altDown

True (1) if the Alt key was held down during this event, false (0) otherwise.

.controlDown

True (1) if the Control key was held down during this event, false (0) otherwise.

.shiftDown

True (1) if the Shift key was held down during this event, false (0) otherwise.

mousePressed

This event fires when a mouse button is pressed down on the source component.

.source

The component that fired this event

.button

The code for the button that caused this event to fire.

.clickCount

The number of mouse clicks associated with this event.

.x

The x-coordinate (with respect to the source component) of this mouse event.

.y

The y-coordinate (with respect to the source component) of this mouse event.

.popupTrigger

Returns True (1) if this mouse event is a popup trigger. What constitutes a popup trigger is operating system dependent, which is why this abstraction exists.

.altDown

True (1) if the Alt key was held down during this event, false (0) otherwise.

.controlDown

True (1) if the Control key was held down during this event, false (0) otherwise.

.shiftDown

True (1) if the Shift key was held down during this event, false (0) otherwise.

mouseReleased

This event fires when a mouse button is released, if that mouse button's press happened over this component.

.source

The component that fired this event

.button

The code for the button that caused this event to fire.

.clickCount

The number of mouse clicks associated with this event.

.x

The x-coordinate (with respect to the source component) of this mouse event.

.y

The y-coordinate (with respect to the source component) of this mouse event.

.popupTrigger

Returns True (1) if this mouse event is a popup trigger. What constitutes a popup trigger is operating system dependent, which is why this abstraction exists.

.altDown

True (1) if the Alt key was held down during this event, false (0) otherwise.

.controlDown

True (1) if the Control key was held down during this event, false (0) otherwise.

.shiftDown

True (1) if the Shift key was held down during this event, false (0) otherwise.

mouseMotion

mouseDragged

Fires when the mouse moves over a component after a button has been pushed.

.source

The component that fired this event

.button

The code for the button that caused this event to fire.

.clickCount

The number of mouse clicks associated with this event.

.x

The x-coordinate (with respect to the source component) of this mouse event.

.y

The y-coordinate (with respect to the source component) of this mouse event.

.popupTrigger

Returns True (1) if this mouse event is a popup trigger. What constitutes a popup trigger is operating system dependent, which is why this abstraction exists.

.altDown

True (1) if the Alt key was held down during this event, false (0) otherwise.

.controlDown

True (1) if the Control key was held down during this event, false (0) otherwise.

.shiftDown

True (1) if the Shift key was held down during this event, false (0) otherwise.

mouseMoved

Fires when the mouse moves over a component, but no buttons are pushed.

.source

The component that fired this event

.button

The code for the button that caused this event to fire.

.clickCount

The number of mouse clicks associated with this event.

.x

The x-coordinate (with respect to the source component) of this mouse event.

.y

The y-coordinate (with respect to the source component) of this mouse event.

.popupTrigger

Returns True (1) if this mouse event is a popup trigger. What constitutes a popup trigger is operating system dependent, which is why this abstraction exists.

.altDown

True (1) if the Alt key was held down during this event, false (0) otherwise.

.controlDown

True (1) if the Control key was held down during this event, false (0) otherwise.

.shiftDown

True (1) if the Shift key was held down during this event, false (0) otherwise.

propertyChange

propertyChange

Fires whenever a bindable property of the source component changes. This works for standard and custom (dynamic) properties.

.source

The component that fired this event

.newValue

The new value that this property changed to.

.oldValue

The value that this property was before it changed. Note that not all components include an accurate oldValue in their events.

.propertyName

The name of the property that changed. NOTE: remember to always filter out these events for the property that you are looking for! Components often have many properties that change.

Customizers
Examples

The following examples may need to be modifed to match the table and column names in your database.

insertNote: using default table configuration
# Inserts a note using the three default tables: notes, users, and itemNotes. 
# Also stores only the file name in the database instead of the full path to the file
# Assumes a User ID is used in the notes table
 
# determine the ID for the logged in user
user = system.db.runScalarPrepQuery("SELECT id from users where username = ?", [system.security.getUsername()])
 
# determine if a file is being attached
if filename is None:
# a file was not attached, provide a blank for the bytes
attachmentBytes = None
else:
# get the bytes of the file at the path the user selects
attachmentBytes = system.file.readFileAsBytes(filename)
# splits the file name from the file path. This way we can show just the file name on the component
# Using '\' as a delimiter, but python requires 2 since it's an escape character
pathAndFile = filename.rsplit('\\', 1)
filename = pathAndFile[1]
# build the query and the arguments
query = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?)"
arguments = [note, user, attachmentBytes, filename, sticky]
# insert the note
insertId = system.db.runPrepUpdate(query, arguments)
 
# insert a row onto the itemNotes table 
# replace 'MYID' with the proper code to fetch your id
myId = 'MYID'
system.db.runPrepUpdate("INSERT INTO ItemNotes (AccountId, NoteId) VALUES (?, ?)", [myId, insertId])
insertNote: using a single table
# Similar to the above example, but only a single database table is required.
# Assumes a User Name is used in the notes table
 
# determine the name for the logged in user
user = system.security.getUsername()
 
# determine if a file is being attached
if filename is None:
# a file was not attached, provide a blank for the bytes
attachmentBytes = None
else:
# get the bytes of the file at the path the user selects
attachmentBytes = system.file.readFileAsBytes(filename)
# splits the file name from the file path. This way we can show just the file name on the component
# Using '\' as a delimiter, but python requires 2 since it's an escape character
pathAndFile = filename.rsplit('\\', 1)
filename = pathAndFile[1]
# insert the note
query = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?)"
#if the note will be stored in SQL Server, then the attachment will need to be converted into a VarBinary. Use the following query instead
#query = = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, ?, CONVERT(VARBINARY(MAX),?), ?)"
arguments = [note, user, attachmentBytes, filename, sticky]
system.db.runPrepUpdate(query, arguments)