Search

User Manual

Getting Started


Modules and Platform


Appendix


Tutorials & Helpful Tricks


Glossary


Strategic Partner Links

Sepasoft - MES Modules
Cirrus Link - MQTT Modules

Resources

Inductive University
Ignition Demo Project
Knowledge Base Articles
Forum
IA Support
SDK Documentation
SDK Examples

All Manual Versions

Ignition 8
Ignition 7.9
Ignition 7.8

Deprecated Pages

Skip to end of metadata
Go to start of metadata
General

Component Palette Icon:



IULocgo


Comments Panel

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. It expects three tables in the database, and that they are queried properly on the data property.

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

Behavior Description
Three-Table (Default) Configuration
 Three-Table (Default) Configuration

The following section assumes the default configuration: all Extension Functions on the component are disabled.

Required Database Tables

The default behavior of the component expects three database tables be present under the same database connection, and each table needs to have certain columns with specific names.

Table: Notes

Stores all of the notes across the board.

Column NameDescriptionData Type
idAn auto-incrementing integer that is the primary key. This maps to the ID field in the dataset.Integer
whoIDA mapping to the Username field in the datasetInteger
tStampA mapping to the Timestamp field in the datasetDate or Datetime
noteA mapping to the NoteText field in the datasetVarchar
filenameA mapping to the AttachmentFilename in the datasetVarchar
stickyA mapping to the Sticky field in the datasetBoolean or Integer
attachmentA column to hold the attachment data. LongBlobs do not exist in MSSQL, so a varbinary type must be usedLongBlob or Varbinary (depending on database)

Table: ItemNotes

Used to associate notes with other things. This allows you to have different sets of notes for different screens/objects.

Column NameDescriptionData Type
accountId  An automatically generated UUID for the Comment Panel instance. You can use the accountId in a WHERE clause on the data property so that the component only shows notes from a particular Comments Panel in the project.Varchar
noteIdAn integer that maps to the ID column on the Notes tableInteger

Tables: Users

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.

Column NameDescriptionData Type
idAn integer that is inserted into the whoID column on the Notes tableInteger
username  The username of the user that created the noteVarchar

Configuring the Component

This component expects that its data property is populated with the following columns. The dataset in the Data property is very specific , and expects certain datatypes at precise positions. The order of expected column positions is listed below. Should the order of datatypes in the dataset differ from the order below, the names of the columns must match the column names below. Aliasing can be used to modify the names of the columns in the dataset.

The names do need to be exact, but different names can be used as long as the query that builds the dataset uses aliases. The data type for each column in your notes table must match the table below.

Column NameDescriptionData TypeExpected Column Position
idan integer that should be the primary key for the notes table. Used for deleting and looking up attachmentsinteger0
usernamethe user who added the notestring/varchar1
timestampwhen the note was addeddateTime2
notetextThe text of the note itselfstring/varchar3
attachmentnamefilename for a file attached to the notestring/varchar4
issticky0 or 1 indicating whether or not the note is "sticky", which means it gets highlighted and put at the topboolean or integer5

Example

The following query returns note data from the above tables, and displays the data on a Comments Panel component. This query should be placed in a SQL Query binding on the Data property

 SELECT 
	notes.id,
	users.username as whoid, 
	notes.tstamp, 
	notes.note, 
	notes.filename, 
	notes.sticky
	
FROM 
	notes
	JOIN users
	ON notes.whoid = users.id
	
ORDER BY
	notes.tstamp DESC

By default, users can remove their own comments, and comments can have files attached.

Custom Configuration

Enabling the Extension Functions on the component will 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

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. Options are: No border, Etched (Lowered), Etched (Raised), Bevel (Lowered), Bevel (Raised), Bevel (Double), Button Border, Field Border, Line Border, and Other Border.

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

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. Can be chosen from color wheel, chosen from color palette, or entered as RGB or HSL value. See Color Selector.

Color

.foreground

Appearance

Header Color

The background color of the header notes. See Color Selector.

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. See Color Selector.

Color

.noteColor

Appearance

Padding

The amount of padding between the notes.

int

.padding

Appearance

Quality

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

QualityCode

.quality

Data

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. See Color Selector.

Color

.stickyHeaderColor

Appearance

Sticky Note Color

The background color for sticky notes. See Color Selector.

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

Deprecated Properties

Data Quality

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

int

.dataQuality

Deprecated

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.

.sourceThe component that fired this event
.buttonThe code for the button that caused this event to fire.
.clickCountThe number of mouse clicks associated with this event.
.xThe x-coordinate (with respect to the source component) of this mouse event.
.yThe y-coordinate (with respect to the source component) of this mouse event.
.popupTriggerReturns 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.
.altDownTrue (1) if the Alt key was held down during this event, false (0) otherwise.
.controlDownTrue (1) if the Control key was held down during this event, false (0) otherwise.
.shiftDownTrue (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.

.sourceThe component that fired this event.
.buttonThe code for the button that caused this event to fire.
.clickCountThe number of mouse clicks associated with this event.
.xThe x-coordinate (with respect to the source component) of this mouse event.
.yThe y-coordinate (with respect to the source component) of this mouse event.
.popupTriggerReturns 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.
.altDownTrue (1) if the Alt key was held down during this event, false (0) otherwise.
.controlDownTrue (1) if the Control key was held down during this event, false (0) otherwise.
.shiftDownTrue (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.

.sourceThe component that fired this event.
.buttonThe code for the button that caused this event to fire.
.clickCountThe number of mouse clicks associated with this event.
.xThe x-coordinate (with respect to the source component) of this mouse event.
.yThe y-coordinate (with respect to the source component) of this mouse event.
.popupTriggerReturns 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.
.altDownTrue (1) if the Alt key was held down during this event, false (0) otherwise.
.controlDownTrue (1) if the Control key was held down during this event, false (0) otherwise.
.shiftDownTrue (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.

.sourceThe component that fired this event.
.buttonThe code for the button that caused this event to fire.
.clickCountThe number of mouse clicks associated with this event.
.xThe x-coordinate (with respect to the source component) of this mouse event.
.yThe y-coordinate (with respect to the source component) of this mouse event.
.popupTriggerReturns 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.
.altDownTrue (1) if the Alt key was held down during this event, false (0) otherwise.
.controlDownTrue (1) if the Control key was held down during this event, false (0) otherwise.
.shiftDownTrue (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.

.sourceThe component that fired this event.
.buttonThe code for the button that caused this event to fire.
.clickCountThe number of mouse clicks associated with this event.
.xThe x-coordinate (with respect to the source component) of this mouse event.
.yThe y-coordinate (with respect to the source component) of this mouse event.
.popupTriggerReturns 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.
.altDownTrue (1) if the Alt key was held down during this event, false (0) otherwise.
.controlDownTrue (1) if the Control key was held down during this event, false (0) otherwise.
.shiftDownTrue (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.

.sourceThe component that fired this event.
.buttonThe code for the button that caused this event to fire.
.clickCountThe number of mouse clicks associated with this event.
.xThe x-coordinate (with respect to the source component) of this mouse event.
.yThe y-coordinate (with respect to the source component) of this mouse event.
.popupTriggerReturns 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.
.altDownTrue (1) if the Alt key was held down during this event, false (0) otherwise.
.controlDownTrue (1) if the Control key was held down during this event, false (0) otherwise.
.shiftDownTrue (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.

.sourceThe component that fired this event.
.buttonThe code for the button that caused this event to fire.
.clickCountThe number of mouse clicks associated with this event.
.xThe x-coordinate (with respect to the source component) of this mouse event.
.yThe y-coordinate (with respect to the source component) of this mouse event.
.popupTriggerReturns 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.
.altDownTrue (1) if the Alt key was held down during this event, false (0) otherwise.
.controlDownTrue (1) if the Control key was held down during this event, false (0) otherwise.
.shiftDownTrue (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.

.sourceThe component that fired this event.
.newValueThe new value that this property changed to.
.oldValueThe 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.

Remember to always filter out these events for the property that you are looking for! Components often have many properties that change.

Examples

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

These examples are written for a MySQL database connection. If you are using a different database, some things may need to be changed. For example, using MS SQL Server requires:

  • the python value None may not be used when inserting into a byte array. NULL must be used in its place.
  • binary data must be converted to a varbinary type when inserting. See the examples below
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 two since it's an escape character
	pathAndFile = filename.rsplit('\\', 1)
	filename = pathAndFile[1]
 
# build the query
#MySQL query
query = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?)"
#MSSQL Server query
# We're converting the binary data into a VARBINARY datatype, and checking for a NULL in the attachment query.
#if attachmentBytes == None:
#	query = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, NULL, ?, ?)" 
#else:
#	query = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, CONVERT(VARBINARY(MAX),?), ?, ?)" 


# Set arguments and run the query
arguments = [note, user, attachmentBytes, filename, sticky]
insertId = system.db.runPrepUpdate(query, arguments, getKey=1))

# insert a row onto the itemNotes table 
# replace 'MYID' with the proper code - this is based on how you are dividing the notes. 
# this ID could be an area, page, or machine code, or anything else that you may want to organize on.
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]
        
# build the query
#MySQL query
query = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?)"
#MSSQL Server query
#We're converting the binary data into a VARBINARY datatype, and checking for a NULL in the attachment query.
#if attachmentBytes == None:
#	query = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, NULL, ?, ?)" 
#else:
#	query = "INSERT INTO Notes (note, whoid, tstamp, attachment, filename, sticky) VALUES (?, ?, CURRENT_TIMESTAMP, CONVERT(VARBINARY(MAX),?), ?, ?)" 

# Set arguments and run the query
arguments = [note, user, attachmentBytes, filename, sticky]
system.db.runPrepUpdate(query, arguments)

 

 

  • No labels