From cb2572c529e74e418ff9addc6f4fd2f2fe2d94f4 Mon Sep 17 00:00:00 2001 From: Chandra Date: Mon, 19 Aug 2019 17:00:54 +0530 Subject: [PATCH 01/96] Create plangrid.rb --- custom_connectors/oauth2/plangrid.rb | 2767 ++++++++++++++++++++++++++ 1 file changed, 2767 insertions(+) create mode 100644 custom_connectors/oauth2/plangrid.rb diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb new file mode 100644 index 00000000..f218284f --- /dev/null +++ b/custom_connectors/oauth2/plangrid.rb @@ -0,0 +1,2767 @@ +{ + title: 'Plangrid', + connection: { + fields: [ + { + name: 'client_id', + label: 'Client ID', + optional: false, + hint: 'To create client id, you need to register an application' \ + ' under Admin Console => Project => Oauth => Create Oauth app' + }, + { + name: 'client_secret', + label: 'Client secret', + control_type: 'password', + optional: false, + hint: 'To create client id, you need to register an application' \ + ' under Admin Console => Project => Oauth => Create Oauth app' + } + ], + authorization: { + type: 'oauth2', + authorization_url: lambda do |connection| + 'https://io.plangrid.com/oauth/authorize?response_type=' \ + "code&client_id=#{connection['client_id']}&" \ + 'scope=write:projects%20read:profile' + end, + acquire: lambda do |connection, auth_code, redirect_uri| + response = post('https://io.plangrid.com/oauth/token'). + payload(client_id: connection['client_id'], + client_secret: connection['client_secret'], + grant_type: 'authorization_code', + code: auth_code, + redirect_uri: redirect_uri). + request_format_www_form_urlencoded + [response, nil, nil] + end, + refresh_on: [401, 403], + refresh: lambda do |_connection, refresh_token| + post('https://io.plangrid.com/oauth/token'). + payload(grant_type: 'refresh_token', + refresh_token: refresh_token). + request_format_www_form_urlencoded + end, + apply: lambda do |_connection, access_token| + if current_url.include?('https://io.plangrid.com') + headers(Authorization: "Bearer #{access_token}", + Accept: 'application/vnd.plangrid+json; version=1') + end + end + }, + base_uri: lambda do |_connection| + 'https://io.plangrid.com' + end + }, + test: ->(_connection) { get('/me') }, + object_definitions: { + project: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'name', label: 'Project name', sticky: true }, + { name: 'custom_id', label: 'Project code', sticky: true }, + { name: 'organization_id' }, + { name: 'type', control_type: 'select', + label: 'Project type', sticky: true, + pick_list: 'project_types', + toggle_hint: 'Select project type', + toggle_field: { + name: 'type', + label: 'Project type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Project type with possible values of general,' \ + ' manufacturing, power, water-sewer-waste, industrial-' \ + 'petroleum, transportation, hazardous-waste, telecom, ' \ + 'education-k-12, education-higher, gov-federal, ' \ + 'gov-state-local, or other' + } }, + { name: 'status', label: 'Project status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project owner' }, + { name: 'start_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project start date', + hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'end_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project end date', + hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'street_1', sticky: true, + label: 'Street line 1' }, + { name: 'street_2', sticky: true, label: 'Street line 2' }, + { name: 'city', sticky: true, label: 'Town or city' }, + { name: 'region', sticky: true, label: 'State, province, or region' }, + { name: 'postal_code', sticky: true, label: 'Zip or postal code' }, + { name: 'country', + sticky: true, + hint: 'Project address country in 2-letter ISO 3166 code.' }, + { name: 'latitude' }, + { name: 'longitude' }, + { name: 'updated_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion', + label: 'Updated at' } + ] + end + }, + document: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'Document ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'name', label: 'Document name' }, + { name: 'folder' }, + { name: 'url' }, + { name: 'created_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'deleted', type: 'boolean' }, + { name: 'updated_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' } + ] + end + }, + task: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'Task ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'assignees', type: 'array', of: 'object', properties: [ + { name: 'assignee' } + ] }, + { name: 'closed_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] }, + { name: 'cost_impact', type: 'number' }, + { name: 'has_cost_impact', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'cost_impact', + label: 'Cost impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + { name: 'currency_code', + hint: 'The ISO-4217 currency code of the cost_impact,' \ + ' Currently only supports USD. maybe null if cost_impact is ' \ + 'not specified' }, + { name: 'current_annotation', type: 'object', properties: [ + { name: 'uid' }, + { name: 'color' }, + { name: 'stamp' }, + { name: 'visibility' }, + { name: 'deleted', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + { name: 'sheet', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ] } + ] }, + { name: 'deleted', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + { name: 'description' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'followers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' } + ] }, + { name: 'issue_list', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ] }, + { name: 'number', type: 'number' }, + { name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] }, + { name: 'room' }, + { name: 'schedule_impact', type: 'integer' }, + { name: 'has_schedule_impact', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_schedule_impact', + label: 'Has schedule impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + { name: 'start_date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, + { name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending",' \ + ' "closed".' + } }, + { name: 'string', + hint: 'One to two character stamp associated with task.' }, + { name: 'title' }, + { name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work",' \ + ' "other".' + } }, + { name: 'updated_at', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion', + type: 'date_time' }, + { name: 'updated_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] } + + ] + end + }, + file_upload: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid' }, + { name: 'aws_post_form_arguments', type: 'object', + properties: [ + { name: 'action' }, + { name: 'fields', type: 'array', of: 'object', properties: [ + { name: 'name' }, + { name: 'value' } + ] } + ] }, + { name: 'webhook_url' } + ] + end + }, + annotation: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'Unique Identifier' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'color' }, + { name: 'stamp' }, + { name: 'visibility' }, + { name: 'deleted', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + { name: 'sheet', type: 'object', properties: [ + { name: 'uid' }, + { name: 'label' }, + { name: 'color' } + ] } + ] + end + }, + snapshot: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'Snapshot ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'title' }, + { name: 'url' }, + { name: 'created_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'sheet', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ] }, + { name: 'deleted', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } + ] + end + }, + photo: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'Photo ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'title' }, + { name: 'url' }, + { name: 'created_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'deleted', type: 'boolean', control_type: 'checkbox', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } + ] + end + }, + field_report: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'File report ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'title' }, + { name: 'description' }, + { name: 'report_date', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'field_report_type', type: 'object', properties: [ + { name: 'name' }, + { name: 'project_uid' }, + { name: 'status' }, + { name: 'uid' } + ] }, + { name: 'pdf_url' }, + { name: 'pdf_form_values', type: 'array', of: 'object', + properties: [ + { name: 'name' }, + { name: 'value' } + ] }, + { name: 'pg_form_values', type: 'array', of: 'object', properties: [ + { name: 'pg_equipment_entries', type: 'array', of: 'object', + properties: [ + { name: 'uid' }, + { name: 'timespan' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, + { name: 'description' }, + { name: 'deleted', type: 'boolean', + control_type: 'checkbox', + toggle_hint: 'Select from options list', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } + ] }, + { name: 'pg_materials_entries', type: 'array', of: 'object', + properties: [ + { name: 'uid' }, + { name: 'unit', type: 'integer' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, + { name: 'description' }, + { name: 'deleted' } + ] }, + { name: 'pg_worklog_entries', type: 'array', of: 'object', + properties: [ + { name: 'uid' }, + { name: 'trade' }, + { name: 'timespan' }, + { name: 'headcount', type: 'integer' }, + { name: 'description' }, + { name: 'deleted', type: 'boolean', + control_type: 'checkbox', + toggle_hint: 'Select from options list', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } + ] } + ] }, + { name: 'attachments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] }, + { name: 'created_by', type: 'object', properties: [ + { name: 'email' }, + { name: 'uid' }, + { name: 'url' } + ] }, + { name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'report_date', type: 'date' }, + { name: 'snapshots', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] }, + { name: 'status' }, + { name: 'updated_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'weather', type: 'object', properties: [ + { name: 'humidity', type: 'number' }, + { name: 'precipitation_accumulation', type: 'number' }, + { name: 'precipitation_accumulation_unit' }, + { name: 'speed_unit' }, + { name: 'summary_key' }, + { name: 'temperature_max', type: 'integer' }, + { name: 'temperature_min' }, + { name: 'temperature_unit' }, + { name: 'wind_bearing', type: 'integer' }, + { name: 'wind_gust', type: 'number' }, + { name: 'wind_speed', type: 'number' } + ] } + ] + end + }, + rfi: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'RFI ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'number', type: 'integer' }, + { name: 'status', type: 'object', properties: [ + { name: 'uid' }, + { name: 'label' }, + { name: 'color' } + ] }, + { name: 'locked', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'locked', + label: 'Locked', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + { name: 'title' }, + { name: 'question' }, + { name: 'answer' }, + { name: 'sent_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { name: 'due_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'assigned_to_uids', + hint: 'Array of unique identifiers of users who ' \ + 'are RFI assignees.' }, + { name: 'assigned_to', type: 'array', of: 'object', + properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'updated_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { name: 'updated_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'created_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] }, + { name: 'attachments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] }, + { name: 'snapshots', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] }, + { name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] } + ] + end + }, + rfi_status: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'RFI status ID' }, + { name: 'label' }, + { name: 'color' } + ] + end + }, + user: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'User ID' }, + { name: 'email' }, + { name: 'first_name' }, + { name: 'last_name' }, + { name: 'language' }, + { name: 'role', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ] }, + { name: 'removed' } + ] + end + }, + sheet: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'Sheet ID' }, + { name: 'name' }, + { name: 'version_name' }, + { name: 'description' }, + { name: 'tags', hint: 'An array of strings representing the' \ + ' tags added to this sheet.' }, + { name: 'published_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'published_at', type: 'date_time', + render_input: 'parse_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'UTC date and time in ISO-8601 format.' }, + { name: 'deleted', type: 'boolean', + control_type: 'checkbox', + toggle_hint: 'Select from options list', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + { name: 'uploaded_file_name' } + ] + end + }, + sheet_packet: { + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'Sheet packet ID' }, + { name: 'file_url' }, + { name: 'resource', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ] }, + { name: 'status' } + ] + end + }, + custom_action_input: { + fields: lambda do |_connection, config_fields| + input_schema = parse_json(config_fields.dig('input', 'schema') || '[]') + + [ + { + name: 'path', + optional: false, + hint: 'Base URI is https://io.plangrid.com' \ + ' - path will be appended to this URI. ' \ + 'Use absolute URI to override this base URI.' + }, + ( + if %w[get delete].include?(config_fields['verb']) + { + name: 'input', + type: 'object', + control_type: 'form-schema-builder', + sticky: input_schema.blank?, + label: 'URL parameters', + add_field_label: 'Add URL parameter', + properties: [ + { + name: 'schema', + extends_schema: true, + sticky: input_schema.blank? + }, + ( + if input_schema.present? + { + name: 'data', + type: 'object', + properties: call('make_schema_builder_fields_sticky', + input_schema) + } + end + ) + ].compact + } + else + { + name: 'input', + type: 'object', + properties: [ + { + name: 'schema', + extends_schema: true, + schema_neutral: true, + control_type: 'schema-designer', + sample_data_type: 'json_input', + sticky: input_schema.blank?, + label: 'Request body parameters', + add_field_label: 'Add request body parameter' + }, + ( + if input_schema.present? + { + name: 'data', + type: 'object', + properties: call('make_schema_builder_fields_sticky', + input_schema) + } + end + ) + ].compact + } + end + ), + { + name: 'output', + control_type: 'schema-designer', + sample_data_type: 'json_http', + extends_schema: true, + schema_neutral: true, + sticky: true + } + ] + end + }, + custom_action_output: { + fields: lambda do |_connection, config_fields| + parse_json(config_fields['output'] || '[]') + end + } + }, + actions: { + custom_action: { + description: "Custom action " \ + "in Plangrid", + help: { + body: 'Build your own Plangrid action for any Plangrid ' \ + 'REST endpoint.', + learn_more_url: 'https://developer.plangrid.com/docs/', + learn_more_text: 'The Plangrid API documentation' + }, + config_fields: [{ + name: 'verb', + label: 'Request type', + hint: 'Select HTTP method of the request', + optional: false, + control_type: 'select', + pick_list: %w[get post patch delete].map { |verb| [verb.upcase, verb] } + }], + + input_fields: lambda do |object_definitions| + object_definitions['custom_action_input'] + end, + + execute: lambda do |_connection, input| + verb = input['verb'] + error("#{verb} not supported") if %w[get post put delete].exclude?(verb) + data = input.dig('input', 'data').presence || {} + case verb + when 'get' + response = + get(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + + if response.is_a?(Array) + array_name = parse_json(input['output'] || '[]'). + dig(0, 'name') || 'array' + { array_name.to_s => response } + elsif response.is_a?(Hash) + response + else + error('API response is not a JSON') + end + when 'post' + post(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + when 'patch' + patch(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + when 'delete' + delete(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + end + end, + output_fields: lambda do |object_definitions| + object_definitions['custom_action_output'] + end + }, + create_project: { + title: 'Create project', + description: 'Create project in'\ + ' Plangrid', + help: { + body: 'Create project action uses the' \ + " Create Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/create-project', + learn_more_text: 'Create Project' + }, + input_fields: lambda do |object_definitions| + object_definitions['project']. + ignored('uid', 'updated_at', 'latitude', 'longitude', + 'organization_id'). + required('name') + end, + execute: lambda do |_connection, input| + post('projects').payload(input). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end, + output_fields: lambda do |object_definitions| + object_definitions['project'] + end, + sample_output: lambda do |_connection, _input| + get('/projects')&.dig('data', 0) || {} + end + }, + update_project: { + title: 'Update project', + description: 'Update project in'\ + ' Plangrid', + help: { + body: 'Update project action uses the' \ + " Update Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/update-project', + learn_more_text: 'Update a Project' + }, + input_fields: lambda do |object_definitions| + object_definitions['project'].required('uid'). + ignored('updated_at', 'latitude', 'longitude', 'organization_id') + end, + execute: lambda do |_connection, input| + patch("/projects/#{input.delete('uid')}").payload(input). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end, + output_fields: lambda do |object_definitions| + object_definitions['project'] + end, + sample_output: lambda do |_connection, _input| + get('/projects')&.dig('data', 0) || {} + end + }, + get_project_details: { + title: 'Get project info. by ID', + description: 'Get project info.'\ + ' by ID in Plangrid', + help: { + body: 'Get project info. by ID action uses the' \ + " Retrieve a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-a-project', + learn_more_text: 'Retrieve a Project' + }, + input_fields: lambda do |object_definitions| + object_definitions['project'].only('uid').required('uid') + end, + execute: lambda do |_connection, input| + get("/projects/#{input['uid']}") + end, + output_fields: lambda do |object_definitions| + object_definitions['project'] + end, + sample_output: lambda do |_connection, _input| + get('/projects')&.dig('data', 0) || {} + end + }, + upload_document: { + title: 'Upload document to a project', + description: 'Upload document to a project'\ + ' in Plangrid', + help: { + body: 'Upload document to a project action uses the' \ + " Upload Document to Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/upload-' \ + 'attachment-to-project', + learn_more_text: 'Upload Document to Project API' + }, + summarize_input: %w[file_content], + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'content_type', + hint: 'Content type of the document\'s file. e.g. for pdf' \ + ' application/pdf', optional: false }, + { name: 'file_content', optional: false }, + { name: 'name', optional: false, + label: 'Document name', + hint: 'Name of the document.' }, + { name: 'folder', label: 'Folder', sticky: true, + control_type: 'select', + pick_list: 'project_folders', + pick_list_params: { project_uid: 'project_uid' }, + toggle_hint: 'Select folder', + hint: 'Folder shows in select options only if at least one file' \ + ' exist in the folder', + toggle_field: { + name: 'folder', + label: 'Project folder', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Folder in project to place the document ' \ + '(case-sensitive). Leave blank to select root folder' + } }, + { name: 'auto_version', type: 'boolean', + control_type: 'checkbox', + toggle_hint: 'Select from options list', + toggle_field: { + name: 'auto_version', + type: 'boolean', + control_type: 'text', + label: 'Auto version', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } + ] + end, + execute: lambda do |_connection, input| + file_content = input.delete('file_content') + project_uid = input['project_uid'] + file_upload_info = post("/projects/#{project_uid}/" \ + 'attachments/uploads'). + headers('Content-type': 'application/json'). + payload(input) + url = file_upload_info&.dig('aws_post_form_arguments', 'action') + fields = file_upload_info&.dig('aws_post_form_arguments', 'fields') + # webhook_url = file_upload_info. + # dig('aws_post_form_arguments', 'webhook_url') + headers = fields.map { |o| { o['name'] => o['value'] } }.inject(:merge) + status = + post(url). + payload(key: headers['key'], + policy: headers['policy'], + signature: headers['signature'], + AWSAccessKeyId: headers['AWSAccessKeyId'], + 'content-type': headers['Content-Type'], + 'success_action_redirect': headers['success_action_redirect'], + 'x-amz-server-side-encryption': + headers['x-amz-server-side-encryption'], + 'x-amz-storage-class': headers['x-amz-storage-class'], + file: file_content). + request_format_multipart_form. + after_response do |_code, response, _response_headers| + response + end + status.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['document'] + end, + sample_output: lambda do |_connection, _input| + { + uid: '147a420e-a182-4312-8fa5-4d10064d2f1a', + name: 'Bender', + folder: 'Specifications', + url: 'https://attachment-assets.plangrid.com/147a420e-a182-' \ + '4312-8fa5-4d10064d2f1a.pdf', + created_at: '2013-05-17T02:30:22+00:00', + created_by: { + uid: null, + url: null, + email: 'nick@subcontractor.com' + }, + deleted: false + } + end + + }, + create_rfi: { + title: 'Create RFI in a project', + description: 'Create RFI in'\ + ' a Plangrid project ', + help: { + body: 'Create RFI in project action uses the ' \ + "Create RFI in Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/create-rfi-' \ + 'in-a-project', + learn_more_text: 'Create RFI in a Project' + }, + input_fields: lambda do |object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'status', label: 'Status', + hint: 'Use this for create and update rfi status' } + ].concat(object_definitions['rfi']. + only('locked', 'title', 'question', 'answer', 'sent_at', + 'due_at', 'assigned_to_uids'). + required('title')) + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + payload = input&.map do |key, val| + if %w[due_at sent_at].include?(key) + { key => val.to_time.utc.iso8601 } + else + { key => val } + end + end&.inject(:merge) + post("/projects/#{project_uid}/rfis").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['rfi'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/rfis")&.dig('data', 0) || {} + end + }, + update_rfi: { + title: 'Update RFI in a project', + description: 'Update RFI in'\ + ' a Plangrid project', + help: { + body: 'Update RFI in Project action uses the ' \ + "patchUpdate RFI in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/update-' \ + 'rfi-in-a-project', + learn_more_text: 'Update RFI in a Project' + }, + input_fields: lambda do |object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'status', label: 'Status', + hint: 'Use this for create and update rfi status' } + ].concat(object_definitions['rfi']. + only('uid', 'locked', 'title', 'question', 'answer', 'sent_at', + 'due_at', 'assigned_to_uids'). + required('uid')) + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + rfi_id = input.delete('uid') + payload = input&.map do |key, val| + if %w[due_at sent_at].include?(key) + { key => val.to_time.utc.iso8601 } + else + { key => val } + end + end&.inject(:merge) + patch("/projects/#{project_uid}/rfis/#{rfi_id}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['rfi'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/rfis")&.dig('data', 0) || {} + end + }, + get_rfi_in_project: { + title: 'Get RFI in a project', + description: 'Get RFI by ID in'\ + ' Plangrid project', + help: { + body: 'Get RFI by ID in a project action uses the' \ + " Retrieve RFI in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/" \ + "retrieve-rfis-in-a-project', + learn_more_text: 'Retrieve RFI in a Project' + }, + input_fields: lambda do |object_definitions| + object_definitions['rfi'].only('project_uid', 'uid'). + required('project_uid', 'uid') + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + get("/projects/#{project_uid}/rfis/#{input['uid']}")&. + merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['rfi'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/rfis")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + create_task: { + title: 'Create task in a project', + description: 'Create task in'\ + ' Plangrid project', + help: { + body: 'Create task in Project action uses the ' \ + "Create task in Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/create-task-in-' \ + 'a-project', + learn_more_text: 'Create Task in a Project' + }, + input_fields: lambda do |object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } } + ].concat(object_definitions['task']. + only('assigned_to_uids', 'cost_impact', 'description', 'due_at', + 'has_cost_impact', 'has_schedule_impact', + 'issue_list_uid', 'room', 'schedule_impact', 'start_date', + 'status', 'title', 'type')) + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + payload = input&.map do |key, val| + if %w[due_at].include?(key) + { key => val.to_time.utc.iso8601 } + else + { key => val } + end + end&.inject(:merge) + post("/projects/#{project_uid}/issues").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['task'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/issues")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + update_task: { + title: 'Update task in a Project', + description: 'Update task in'\ + ' Plangrid project', + help: { + body: 'Update task in Project action uses the ' \ + "Create task in Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/create-project', + learn_more_text: 'Update Task in a Project' + }, + input_fields: lambda do |object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g.' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } } + ].concat(object_definitions['task']. + only('uid', 'assigned_to_uids', 'cost_impact', 'description', + 'due_at', 'has_cost_impact', 'has_schedule_impact', + 'issue_list_uid', 'room', 'schedule_impact', 'start_date', + 'status', 'title', 'type').required('uid')) + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + patch("/projects/#{project_uid}/issues/" \ + "#{input.delete('uid')}").payload(input). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['task'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/issues")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + get_task: { + title: 'Get task in a project', + description: 'Get task in'\ + ' in a Plangrid project', + help: { + body: 'Get task in a project action uses the ' \ + "Retrieve Task in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'issues-in-a-project', + learn_more_text: 'Retrieve Task in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'issue_uid', label: 'Issue ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + get("/projects/#{project_uid}/issues/" \ + "#{input['issue_uid']}"). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['task'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/issues")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + invite_user_to_project: { + title: 'Invite a user to a project', + description: 'Invite user to'\ + ' project team Plangrid', + help: { + body: 'Invite user to a project action uses the ' \ + "Invite user in Project team API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'invite-user-to-project-team', + learn_more_text: 'Invite User to Project Team' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'email', optional: false }, + { name: 'role_uid', label: 'Role ID', + hint: 'Unique identifier of role to assign user on project team' } + ] + end, + execute: lambda do |_connection, input| + post("/projects/#{input.delete('project_uid')}/users/invites"). + payload(input). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end, + output_fields: lambda do |object_definitions| + object_definitions['user'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/users")&.dig('data', 0) || {} + end + }, + get_user_in_project: { + title: 'Get user in project', + description: 'Get user in'\ + ' Plangrid project', + help: { + body: 'Get user in project action uses the ' \ + "Retrieve User on a Project Team.", + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'users-on-a-project-team', + learn_more_text: 'Retrieve User on a Project Team' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'user_uid', label: 'User ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + get("/projects/#{input['project_uid']}/users/" \ + "#{input['user_uid']}") + end, + output_fields: lambda do |object_definitions| + object_definitions['user'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/users")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + get_snapshot_in_project: { + title: 'Get snapshot in a project', + description: 'Get snapshot in'\ + ' a Plangrid project', + help: { + body: 'Get snapshot in a project action uses the ' \ + "Retrieve Snapshot in a Project.", + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'snapshot-in-a-project', + learn_more_text: 'Retrieve Snapshot in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'snapshot_uid', label: 'Snapshot ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + get("/projects/#{input['project_uid']}/snapshots/" \ + "#{input['snapshot_uid']}") + end, + output_fields: lambda do |object_definitions| + object_definitions['snapshot'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/snapshots")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + get_rfi_statuses_in_project: { + title: 'Get RFI statuses in project', + description: 'Get rfi statuses in'\ + ' Plangrid project', + help: { + body: 'Get rfi statuses in project action uses the ' \ + "Retrieve RFI Statuses in a Project.", + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'rfi-statuses-in-a-project', + learn_more_text: 'Retrieve RFI Statuses in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'limit', type: 'integer', + hint: 'Number of RFI statuses to retrieve. Maximum value of 50.' }, + { name: 'skip', type: 'integer', + hint: 'Number of RFI statuses to skip in the set of results.' } + ] + end, + execute: lambda do |_connection, input| + { statuses: + get("/projects/#{input['project_uid']}/rfis/statuses")['data'] } + end, + output_fields: lambda do |object_definitions| + [ + { name: 'statuses', type: 'array', of: 'object', + properties: object_definitions['rfi_status'] } + ] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/rfis/statuses")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + get_roles_on_project: { + title: 'Get roles on a project', + description: 'Get roles on '\ + ' Plangrid project', + help: { + body: 'Get role on a project action uses the ' \ + "Retrieve Role on a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-role-on-a-project', + learn_more_text: 'Retrieve Role on a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'limit', type: 'integer', + hint: 'Number of roles to retrieve. Maximum value of 50.' }, + { name: 'skip', type: 'integer', + hint: 'Number of roles to skip in the set of results.' } + ] + end, + execute: lambda do |_connection, input| + { roles: get("/projects/#{input.delete('project_uid')}/roles", input) } + end, + output_fields: lambda do |_object_definitions| + [ + { name: 'roles', type: 'array', of: 'object', properties: [ + { name: 'uid' }, + { name: 'label' } + ] }, + { name: 'total_count' }, + { name: 'next_page_url' } + ] + end, + sample_output: lambda do |_connection, _input| + { 'roles' => { 'uid' => '9d139e64-cac9-4f23-b4d5-9fd3688b498e', + 'label' => 'Admin' } } + end + }, + get_sheets_in_project: { + title: 'Get sheets in project', + description: 'Get sheets in'\ + ' Plangrid project', + help: { + body: 'Get sheets in project action uses the ' \ + "Retrieve Sheets in a Project.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-sheets-in-a-project', + learn_more_text: 'Retrieve Sheets in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'limit', type: 'integer', + hint: 'Number of sheets to retrieve. Maximum value of 50.' }, + { name: 'skip', type: 'integer', + hint: 'Number of sheets to skip in the set of results' }, + { name: 'updated_after', type: 'date_time', + hint: 'Only retrieve sheets created/updated after ' \ + 'specified UTC date and time.' } + ] + end, + execute: lambda do |_connection, input| + { sheets: get("/projects/#{input.delete('project_uid')}/sheets", + input)['data'] } + end, + output_fields: lambda do |object_definitions| + [{ name: 'sheets', type: 'array', of: 'object', + properties: object_definitions['sheet'] }] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + { + sheets: get("/projects/#{id}/sheets?limit=1")&.dig('data', 0)&. + merge('project_uid' => id) || {} + } + end + }, + get_sheet_in_project: { + title: 'Get sheet by ID in project', + description: 'Get sheet in'\ + ' Plangrid project', + help: { + body: 'Get project sheet details action uses the ' \ + "Retrieve Sheets in a Project.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-a-sheet', + learn_more_text: 'Retrieve Sheet in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'sheet_uid', type: 'Sheet ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + get("/projects/#{input['project_uid']}/sheets/#{input['sheet_uid']}") + end, + output_fields: lambda do |object_definitions| + object_definitions['sheet'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/sheets?limit=1")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + get_project_sheet_packet: { + title: 'Get project sheet packet', + description: 'Get project sheet packet in'\ + ' packet in Plangrid', + help: { + body: 'Get project sheet packet action uses the ' \ + "Retrieve Sheet Packet API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-sheet-packet', + learn_more_text: 'Retrieve Sheet Packet' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'packet_uid', type: 'Packet ID' } + ] + end, + execute: lambda do |_connection, input| + get("/projects/#{input['project_uid']}/sheets/packets/" \ + "#{input['packet_uid']}") + end, + output_fields: lambda do |object_definitions| + object_definitions['sheet_packet'] + end + }, + get_field_reports_in_project: { + title: 'Get fields reports in project', + description: 'Get field reports in'\ + ' in Plangrid project', + help: { + body: 'Get fields reports in project action uses the ' \ + "Retrieve Field Reports in a" \ + ' Project API.', + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'field-reports-in-a-project', + learn_more_text: 'Retrieve Field Reports in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'updated_after', type: 'date_time', + hint: 'Only retrieve field reports created/updated after ' \ + 'specified UTC date and time.' }, + { name: 'report_date_min', type: 'date_time', + label: 'Report start date', + hint: 'Only retrieve field reports between a date range ' \ + 'starting with this date in UTC format.' }, + { name: 'report_date_max', type: 'date_time', + label: 'Report end date', + hint: 'Only retrieve field reports between a date range ' \ + 'starting with this date in UTC format.' }, + { name: 'sort_by', control_type: 'select', + pick_list: + %w[report_date updated_at]&.map { |e| [e.labelize, e] }, + toggle_hint: 'Select sort by column', + toggle_field: { + name: 'sort_by', type: 'string', control_type: 'text', + hint: 'Allowed values report_date or updated_at' + } } + ] + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + query_params = '' + input&.map do |key, val| + if %w[updated_after report_date_min report_date_max].include?(key) + query_params = query_params + "#{key}=#{val.to_time.utc.iso8601}" + else + query_params = query_params + "#{key}=#{val}" + end + end + { field_reports: get("/projects/#{project_uid}/field_reports?" \ + "#{query_params}")['data'] } + end, + output_fields: lambda do |object_definitions| + { name: 'field_reports', type: 'array', of: 'object', + properties: object_definitions['field_report'] } + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + { field_reports: + get("/projects/#{id}/rfis/field_reports")&. + merge('project_uid' => id) || {} } + end + }, + upload_photo: { + title: 'Uplod photo to project', + description: 'Upload photo to '\ + ' project in Plangrid', + help: { + body: 'Upload photo to a project action uses the' \ + " Upload Photo to Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/upload-photo' \ + '-to-project', + learn_more_text: 'Upload Photo to Project' + }, + summarize_input: %w[file_content], + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'content_type', optional: false, + hint: "Content type of the photo's file" }, + { name: 'file_content', optional: false }, + { name: 'title', optional: false, label: 'Photo title' } + ] + end, + execute: lambda do |_connection, input| + file_content = input.delete('file_content') + file_upload_info = post("/projects/#{input.delete('project_uid')}/" \ + 'photos/uploads'). + headers('Content-type': 'application/json'). + payload(input) + url = file_upload_info&.dig('aws_post_form_arguments', 'action') + fields = file_upload_info&.dig('aws_post_form_arguments', 'fields') + # webhook_url = file_upload_info. + # dig('aws_post_form_arguments', 'webhook_url') + headers = fields.map { |o| { o['name'] => o['value'] } }.inject(:merge) + post(url). + payload(key: headers['key'], + policy: headers['policy'], + signature: headers['signature'], + AWSAccessKeyId: headers['AWSAccessKeyId'], + 'content-type': headers['Content-Type'], + 'success_action_redirect': headers['success_action_redirect'], + 'x-amz-server-side-encryption': + headers['x-amz-server-side-encryption'], + 'x-amz-storage-class': headers['x-amz-storage-class'], + file: file_content). + request_format_multipart_form. + after_response do |_code, response, _response_headers| + response + end + end, + output_fields: lambda do |object_definitions| + object_definitions['photo'] + end, + sample_output: lambda do |_connection, _input| + { + uid: '147a420e-a182-4312-8fa5-4d10064d2f1a', + title: 'Bongo Drums', + url: 'https://attachment-assets.plangrid.com/147a420e-a182-' \ + '4312-8fa5-4d10064d2f1a.pdf', + created_at: '2013-05-17T02:30:22+00:00', + created_by: { + uid: null, + url: null, + email: 'nick@subcontractor.com' + }, + deleted: false + } + end + }, + update_photo_metadata: { + title: 'Update photo metadata', + description: 'Update photo metadata to '\ + ' Project in Plangrid', + help: { + body: 'Update photo metadata action uses the' \ + " Update Document to Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/update-photo-' \ + 'in-a-project', + learn_more_text: 'Update photo to Project API' + }, + summarize_input: %w[file_content], + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'photo_uid', type: 'Photo ID', optional: false }, + { name: 'title', label: 'Photo title', + hint: 'New title of the photo' } + ] + end, + execute: lambda do |_connection, input| + patch("/projects/#{input.delete('project_uid')}/photos/" \ + "#{input.delete('photo_uid')}"). + headers('Content-type': 'application/json'). + payload(input). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end, + output_fields: lambda do |object_definitions| + object_definitions['photo'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/photos")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + get_photo_details: { + title: 'Get photo by ID', + description: 'Get photo in'\ + ' a Plangrid project', + help: { + body: 'Get photo details action uses the ' \ + "Retrieve Photo in Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-a-sheet', + learn_more_text: 'Retrieve Photo in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'photo_uid', type: 'Photo ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + get("/projects/#{input['project_uid']}/photos/" \ + "#{input['photo_uid']}") + end, + output_fields: lambda do |object_definitions| + object_definitions['photo'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/photos")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + }, + get_document_details: { + title: 'Get document by ID', + description: 'Get document in'\ + ' in Plangrid project', + help: { + body: 'Get document details action uses the ' \ + "Retrieve Document in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-a-sheet', + learn_more_text: 'Retrieve Document in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'attachment_uid', type: 'Document ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + get("/projects/#{input['project_uid']}/attachments/" \ + "#{input['attachment_uid']}") + end, + output_fields: lambda do |object_definitions| + object_definitions['document'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/attachments")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end + } + }, + triggers: { + new_updated_project: { + title: 'New/updated project', + description: 'New/updated project in'\ + ' Plangrid', + help: { + body: 'New/updated project trigger uses the' \ + " List all Projects API.", + learn_more_url: 'https://developer.plangrid.com/docs/list-all-projects', + learn_more_text: 'List All Projects API' + }, + input_fields: lambda do |_object_definitions| + [ + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 20 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get('/projects'). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'updated_after' => now.to_time.utc.iso8601 } + end + { + events: response['data'] || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |project| + "#{project['uid']}@#{project['updated_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['project'] + end, + sample_output: lambda do |_connection, _input| + get('/projects')&.dig('data', 0) || {} + end + }, + new_updated_documents: { + title: 'New/updated documents in a project', + description: 'New/updated document in '\ + 'Project Plangrid', + help: { + body: 'New/updated documents in Project trigger uses the' \ + " Retrieve Documents in a Project" \ + ' API.', + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'attachments-in-a-project', + learn_more_text: 'Retrieve Documents in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 5 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{project_uid}/attachments"). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + documents = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: documents || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |document| + "#{document['uid']}@#{document['created_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['document'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/attachments")&.dig('data', 0) || {} + end + }, + new_updated_task: { + title: 'New/updated task in a Project', + description: 'New/updated task in a '\ + 'Project Plangrid', + help: { + body: 'New/updated task in a Project trigger uses the' \ + " Retrieve Tasks " \ + ' in a Project API.', + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-issues-in-a-project', + learn_more_text: 'Retrieve Tasks in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 10 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{input.delete('project_uid')}/" \ + 'issues'). + params(limit: limit, + skip: skip, + include_annotationless: true, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + tasks = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: tasks || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |task| + "#{task['uid']}@#{task['updated_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['task'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/issues")&. + dig('data', 0) || {} + end + }, + new_updated_annotations: { + title: 'New/updated annotations in Project', + description: 'New/updated annotations '\ + 'in Project Plangrid', + help: { + body: 'New/updated annotations in Project trigger uses the' \ + " Retrieve " \ + ' annotations in a Project API.', + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-annotations-in-a-project', + learn_more_text: 'Retrieve Annotations in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 10 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{input.delete('project_uid')}/" \ + 'annotations'). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + annotations = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: annotations || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |annotation| + "#{annotation['uid']}@#{annotation['updated_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['annotation'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/annotations")&. + dig('data', 0) || {} + end + }, + new_updated_photos: { + title: 'New/updated photos in Project', + description: 'New/updated photos '\ + 'in Plangrid Project', + help: { + body: 'New/updated photos in Project trigger uses the' \ + " Retrieve " \ + ' photos in a Project API.', + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-photos-in-a-project', + learn_more_text: 'Retrieve photos in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 10 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{input.delete('project_uid')}/" \ + 'photos'). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + photos = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: photos || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |photo| + "#{photo['uid']}@#{photo['updated_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['photo'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/photos")&. + dig('data', 0) || {} + end + }, + new_updated_snapshot: { + title: 'New/updated snapshot in a Project', + description: 'New/updated snapshot '\ + 'in a Project Plangrid', + help: { + body: 'New/updated snapshot in a Project trigger uses the' \ + " Retrieve " \ + ' Snapshots in a Project API.', + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'remove-snapshot-reference-in-rfi', + learn_more_text: 'Retrieve Snapshots in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 10 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{input.delete('project_uid')}/" \ + 'snapshots'). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + snapshots = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: snapshots || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |annotation| + "#{annotation['uid']}@#{annotation['updated_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['snapshot'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/snapshots")&. + dig('data', 0) || {} + end + }, + new_updated_field_report: { + title: 'New/updated field report in a Project', + description: 'New/updated field report '\ + 'in Plangrid Project', + help: { + body: 'New/updated field report in Project trigger uses the' \ + " Retrieve " \ + 'field reports in a Project API.', + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-field-reports-in-a-project', + learn_more_text: 'Retrieve field reports in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 10 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{input.delete('project_uid')}/" \ + 'field_reports'). + params(limit: limit, + skip: skip, + updated_after: updated_after, + sort_by: 'updated_at', + sort_order: 'asc') + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + field_reports = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: field_reports || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |field_report| + "#{field_report['uid']}@#{field_report['updated_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['field_report'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/field_reports")&. + dig('data', 0) || {} + end + }, + new_updated_rfi: { + title: 'New/updated RFI in a Project', + description: 'New/updated RFI '\ + 'in a Plangrid Project', + help: { + body: 'New/updated RFI in a Project trigger uses the' \ + " Retrieve " \ + ' RFIs in a Project API.', + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-rfis-in-a-project', + learn_more_text: 'Retrieve RFIs in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 10 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{input.delete('project_uid')}/" \ + 'rfis'). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + rfis = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: rfis || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |rfi| + "#{rfi['uid']}@#{rfi['updated_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['rfi'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/rfis")&. + dig('data', 0) || {} + end + } + }, + pick_lists: { + project_list: lambda do |_connection| + get('projects')&.[]('data')&.pluck('name', 'uid') + end, + project_types: lambda do |_connection| + ['general', 'manufacturing', 'power', 'water-sewer-waste', + 'industrial-petroleum', 'transportation', 'hazardous-waste', + 'telecom', 'education-k-12', 'education-higher', 'gov-federal', + 'gov-state-local', 'other'].map { |type| [type.labelize, type] } + end, + project_folders: lambda do |_connection, project_uid:| + folders = get("/projects/#{project_uid}/attachments")['data']&. + pluck('folder')&.uniq + if folders.size > 0 + folders&.map { |folder| [folder || 'Root', folder || ''] } + else + [['Root', '']] + end + end + } +} From 73983af64c8cb7282c1c05e1f9f605ad7bf11db5 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Tue, 20 Aug 2019 15:49:53 -0400 Subject: [PATCH 02/96] change title to `PlanGrid` with capital `G` --- custom_connectors/oauth2/plangrid.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index f218284f..c00417a9 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1,5 +1,5 @@ { - title: 'Plangrid', + title: 'PlanGrid', connection: { fields: [ { From 08c66a7f6cfcf09c037bd295293a4bb88ed5b0e7 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 12:57:21 -0400 Subject: [PATCH 03/96] update `document` object definition --- custom_connectors/oauth2/plangrid.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index c00417a9..eda14fb4 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -132,7 +132,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -145,14 +145,14 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'name', label: 'Document name' }, + { name: 'name', label: 'Document Name' }, { name: 'folder' }, { name: 'url' }, { name: 'created_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, From b864213a1be4762e9d52ab08467255dc6174194d Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 12:57:55 -0400 Subject: [PATCH 04/96] update title and description for `New document...` trigger --- custom_connectors/oauth2/plangrid.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index eda14fb4..48c39b30 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2169,11 +2169,11 @@ end }, new_updated_documents: { - title: 'New/updated documents in a project', - description: 'New/updated document in '\ - 'Project Plangrid', + title: 'New or updated document in a project', + description: 'New or updated document in '\ + 'a PlanGrid project', help: { - body: 'New/updated documents in Project trigger uses the' \ + body: 'New or updated document in a project trigger uses the' \ " Retrieve Documents in a Project" \ ' API.', From 8d30006c5677467f2c023ead279508a391d96691 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 12:58:51 -0400 Subject: [PATCH 05/96] update `Get document...` action, append `project_uid` to result --- custom_connectors/oauth2/plangrid.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 48c39b30..dbb2934f 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2061,11 +2061,11 @@ end }, get_document_details: { - title: 'Get document by ID', - description: 'Get document in'\ - ' in Plangrid project', + title: 'Get document in a project', + description: 'Get document'\ + ' in a PlanGrid project', help: { - body: 'Get document details action uses the ' \ + body: 'Get document in a project action uses the ' \ "Retrieve Document in a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -2090,12 +2090,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'attachment_uid', type: 'Document ID', optional: false } + { name: 'attachment_uid', label: 'Document ID', optional: false } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/attachments/" \ - "#{input['attachment_uid']}") + "#{input['attachment_uid']}")&.merge('project_uid' => input.delete('project_uid')) end, output_fields: lambda do |object_definitions| object_definitions['document'] From 715fdd9a7e9c5a500dbd33cac2f843aadf0e6c76 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 12:59:58 -0400 Subject: [PATCH 06/96] pull down `project_folders` pick list only if UID is present --- custom_connectors/oauth2/plangrid.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index dbb2934f..e6ab64cb 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2755,12 +2755,14 @@ 'gov-state-local', 'other'].map { |type| [type.labelize, type] } end, project_folders: lambda do |_connection, project_uid:| - folders = get("/projects/#{project_uid}/attachments")['data']&. - pluck('folder')&.uniq - if folders.size > 0 - folders&.map { |folder| [folder || 'Root', folder || ''] } - else - [['Root', '']] + if project_uid.length === 36 + folders = get("/projects/#{project_uid}/attachments")['data']&. + pluck('folder')&.uniq + if folders.size > 0 + folders&.map { |folder| [folder || 'Root', folder || ''] } + else + [['Root', '']] + end end end } From cac9cd154735fdf60f6435d02f0cded81343db2a Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 13:07:47 -0400 Subject: [PATCH 07/96] update title and description for `Upload document...` action, fix 400 error due to `project_uid` being included in payload, make `auto_version` sticky --- custom_connectors/oauth2/plangrid.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index e6ab64cb..8ca4c49f 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -996,8 +996,8 @@ }, upload_document: { title: 'Upload document to a project', - description: 'Upload document to a project'\ - ' in Plangrid', + description: 'Upload document to a'\ + ' PlanGrid project', help: { body: 'Upload document to a project action uses the' \ " Date: Thu, 22 Aug 2019 13:08:11 -0400 Subject: [PATCH 08/96] add new `Update document...` action --- custom_connectors/oauth2/plangrid.rb | 54 +++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 8ca4c49f..f6a85186 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1108,7 +1108,59 @@ deleted: false } end - + }, + update_document: { + title: 'Update document in a project', + description: 'Update document in a'\ + ' PlanGrid project', + help: { + body: 'Update document in a project action uses the' \ + " Update Document to Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/update-attachment-' \ + 'in-a-project', + learn_more_text: 'Update Document in a Project API' + }, + summarize_input: %w[file_content], + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'attachment_uid', label: 'Document ID', optional: false }, + { name: 'name', label: 'Document Name', + hint: 'New name of the document', sticky: true }, + { name: 'folder', label: 'Folder', + hint: 'New folder of the document', sticky: true } + ] + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + patch("/projects/#{project_uid}/attachments/" \ + "#{input.delete('attachment_uid')}"). + headers('Content-type': 'application/json'). + payload(input). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['document'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/attachments")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end }, create_rfi: { title: 'Create RFI in a project', From e8ec1c00f04459ffe027a6391cedeee1e24d83d7 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 17:35:00 -0400 Subject: [PATCH 09/96] update `photo` object definition to resolve issue with output not showing up --- custom_connectors/oauth2/plangrid.rb | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index f6a85186..b116bc7e 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -434,7 +434,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -448,24 +448,16 @@ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, { name: 'title' }, - { name: 'url' }, + { name: 'url', label: 'URL' }, { name: 'created_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, - { name: 'deleted', type: 'boolean', control_type: 'checkbox', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } } + { name: 'deleted', type: 'boolean' } ] end }, From 65987ae632f02cc2256adcffcca629f17d4481da Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 17:35:21 -0400 Subject: [PATCH 10/96] update title and description for `New photo...` trigger --- custom_connectors/oauth2/plangrid.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index b116bc7e..579906a4 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2459,17 +2459,17 @@ end }, new_updated_photos: { - title: 'New/updated photos in Project', - description: 'New/updated photos '\ - 'in Plangrid Project', + title: 'New or updated photo in a project', + description: 'New or updated photo '\ + 'in a PlanGrid project', help: { - body: 'New/updated photos in Project trigger uses the' \ + body: 'New or updated photo in a project trigger uses the' \ " Retrieve " \ ' photos in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-photos-in-a-project', - learn_more_text: 'Retrieve photos in a Project' + learn_more_text: 'Retrieve Photos in a Project' }, input_fields: lambda do |_object_definitions| [ From 3a19f8a96dd203445c3566855358375ec519be6d Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 17:36:27 -0400 Subject: [PATCH 11/96] update title and description for `Get photo...` action, append `project_uid` to result --- custom_connectors/oauth2/plangrid.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 579906a4..a0f76576 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2060,11 +2060,11 @@ end }, get_photo_details: { - title: 'Get photo by ID', + title: 'Get photo in a project', description: 'Get photo in'\ - ' a Plangrid project', + ' a PlanGrid project', help: { - body: 'Get photo details action uses the ' \ + body: 'Get photo action uses the ' \ "Retrieve Photo in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -2089,12 +2089,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'photo_uid', type: 'Photo ID', optional: false } + { name: 'photo_uid', label: 'Photo ID', optional: false } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/photos/" \ - "#{input['photo_uid']}") + "#{input['photo_uid']}")&.merge('project_uid' => input.delete('project_uid')) end, output_fields: lambda do |object_definitions| object_definitions['photo'] From 407f8eb60b984644a2f3e5914da9ff7cec2f106e Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 17:37:01 -0400 Subject: [PATCH 12/96] update title and description for `Update photo...` action, append `project_uid` to result --- custom_connectors/oauth2/plangrid.rb | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index a0f76576..849f7da5 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2010,16 +2010,16 @@ end }, update_photo_metadata: { - title: 'Update photo metadata', - description: 'Update photo metadata to '\ - ' Project in Plangrid', + title: 'Update photo in a project', + description: 'Update photo in'\ + ' a PlanGrid project', help: { - body: 'Update photo metadata action uses the' \ + body: 'Update photo action uses the' \ " Update Document to Project API.", + "project' target='_blank'>Update Photo in a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-photo-' \ 'in-a-project', - learn_more_text: 'Update photo to Project API' + learn_more_text: 'Update Photo in a Project API' }, summarize_input: %w[file_content], input_fields: lambda do |_object_definitions| @@ -2036,19 +2036,20 @@ toggle_hint: 'Use project ID', hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'photo_uid', type: 'Photo ID', optional: false }, + { name: 'photo_uid', label: 'Photo ID', optional: false }, { name: 'title', label: 'Photo title', - hint: 'New title of the photo' } + hint: 'New title of the photo', sticky: true } ] end, execute: lambda do |_connection, input| - patch("/projects/#{input.delete('project_uid')}/photos/" \ + project_uid = input.delete('project_uid') + patch("/projects/#{project_uid}/photos/" \ "#{input.delete('photo_uid')}"). headers('Content-type': 'application/json'). payload(input). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") - end + end&.merge('project_uid' => project_uid) end, output_fields: lambda do |object_definitions| object_definitions['photo'] From 310b93d4a27a8dc69d851b68aea250d886118489 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 17:42:18 -0400 Subject: [PATCH 13/96] update title and description for `Upload photo..` action, append `project_uid` to result --- custom_connectors/oauth2/plangrid.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 849f7da5..f992bcef 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1931,9 +1931,9 @@ end }, upload_photo: { - title: 'Uplod photo to project', + title: 'Upload photo to a project', description: 'Upload photo to '\ - ' project in Plangrid', + ' a PlanGrid project', help: { body: 'Upload photo to a project action uses the' \ " project_uid) end, output_fields: lambda do |object_definitions| object_definitions['photo'] From 378af15170d287159d44cbc016eee1b576ed54f7 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 18:47:11 -0400 Subject: [PATCH 14/96] update `snapshot` object definition --- custom_connectors/oauth2/plangrid.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index f992bcef..c2662b3d 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -387,7 +387,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -406,12 +406,12 @@ render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' } ] }, { name: 'deleted', type: 'boolean', From 0f2695e8fa1563f1969559c9a3e0921ed44519d4 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 18:48:15 -0400 Subject: [PATCH 15/96] update title and description for `Get snapshot..` action, append `project_uid` to result --- custom_connectors/oauth2/plangrid.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index c2662b3d..e34f9442 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1564,7 +1564,7 @@ get_snapshot_in_project: { title: 'Get snapshot in a project', description: 'Get snapshot in'\ - ' a Plangrid project', + ' a PlanGrid project', help: { body: 'Get snapshot in a project action uses the ' \ " input['project_uid']) end, output_fields: lambda do |object_definitions| object_definitions['snapshot'] From 3165ec3fbb1ecab170f0555c1ab078ae0ed07a62 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 18:49:02 -0400 Subject: [PATCH 16/96] update title and description for `New or updated snapshot..` trigger --- custom_connectors/oauth2/plangrid.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index e34f9442..4e415ecf 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2544,16 +2544,16 @@ end }, new_updated_snapshot: { - title: 'New/updated snapshot in a Project', - description: 'New/updated snapshot '\ - 'in a Project Plangrid', + title: 'New or updated snapshot in a project', + description: 'New or updated snapshot '\ + 'in a PlanGrid project', help: { - body: 'New/updated snapshot in a Project trigger uses the' \ + body: 'New or updated snapshot in a project trigger uses the' \ " Retrieve " \ + "retrieve-snapshots-in-a-project' target='_blank'>Retrieve " \ ' Snapshots in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'remove-snapshot-reference-in-rfi', + 'retrieve-snapshots-in-a-project', learn_more_text: 'Retrieve Snapshots in a Project' }, input_fields: lambda do |_object_definitions| From da6e4bda7ebf809ca40bf71e50f7b80519b294cd Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 22:30:52 -0400 Subject: [PATCH 17/96] update `project` object definition --- custom_connectors/oauth2/plangrid.rb | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 4e415ecf..1d99a6e4 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -61,7 +61,7 @@ { name: 'uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -74,11 +74,11 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'name', label: 'Project name', sticky: true }, - { name: 'custom_id', label: 'Project code', sticky: true }, - { name: 'organization_id' }, + { name: 'name', label: 'Project Name', sticky: true }, + { name: 'custom_id', label: 'Project Code', sticky: true }, + { name: 'organization_id', label: 'Organization ID' }, { name: 'type', control_type: 'select', - label: 'Project type', sticky: true, + label: 'Project Type', sticky: true, pick_list: 'project_types', toggle_hint: 'Select project type', toggle_field: { @@ -93,26 +93,26 @@ 'education-k-12, education-higher, gov-federal, ' \ 'gov-state-local, or other' } }, - { name: 'status', label: 'Project status', sticky: true }, - { name: 'owner', sticky: true, label: 'Project owner' }, + { name: 'status', label: 'Project Status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project Owner' }, { name: 'start_date', type: 'date', sticky: true, render_input: 'date_conversion', parse_output: 'date_conversion', - label: 'Project start date', + label: 'Project Start Date', hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, { name: 'end_date', type: 'date', sticky: true, render_input: 'date_conversion', parse_output: 'date_conversion', - label: 'Project end date', + label: 'Project End Date', hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, { name: 'street_1', sticky: true, - label: 'Street line 1' }, + label: 'Street Line 1' }, { name: 'street_2', sticky: true, label: 'Street line 2' }, - { name: 'city', sticky: true, label: 'Town or city' }, - { name: 'region', sticky: true, label: 'State, province, or region' }, - { name: 'postal_code', sticky: true, label: 'Zip or postal code' }, + { name: 'city', sticky: true, label: 'Town or City' }, + { name: 'region', sticky: true, label: 'State, Province, or Region' }, + { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, { name: 'country', sticky: true, hint: 'Project address country in 2-letter ISO 3166 code.' }, From eddb8b4f8520b06af99f24e98b65d5390f8572b7 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 22:31:43 -0400 Subject: [PATCH 18/96] update title and description for `Create project` action, include `add_to_organization` parameter --- custom_connectors/oauth2/plangrid.rb | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 1d99a6e4..e6529695 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -907,7 +907,7 @@ create_project: { title: 'Create project', description: 'Create project in'\ - ' Plangrid', + ' PlanGrid', help: { body: 'Create project action uses the' \ " Date: Thu, 22 Aug 2019 22:32:43 -0400 Subject: [PATCH 19/96] update title and description for `Update project` action, handle empty/nil parameters --- custom_connectors/oauth2/plangrid.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index e6529695..27cb3edb 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -952,20 +952,23 @@ update_project: { title: 'Update project', description: 'Update project in'\ - ' Plangrid', + ' PlanGrid', help: { body: 'Update project action uses the' \ " Update Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-project', - learn_more_text: 'Update a Project' + learn_more_text: 'Update Project' }, input_fields: lambda do |object_definitions| object_definitions['project'].required('uid'). ignored('updated_at', 'latitude', 'longitude', 'organization_id') end, execute: lambda do |_connection, input| - patch("/projects/#{input.delete('uid')}").payload(input). + payload = input.each do |key, value| + input[key].present? || input[key] = nil + end + patch("/projects/#{input.delete('uid')}").payload(payload.except('uid')). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end From 81560c454368b9114356fe50dd8b8d1a1fce5a64 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 22:33:04 -0400 Subject: [PATCH 20/96] update title and description for `Get project` action --- custom_connectors/oauth2/plangrid.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 27cb3edb..bca6b3a6 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -981,11 +981,11 @@ end }, get_project_details: { - title: 'Get project info. by ID', - description: 'Get project info.'\ - ' by ID in Plangrid', + title: 'Get project', + description: 'Get project'\ + ' in PlanGrid', help: { - body: 'Get project info. by ID action uses the' \ + body: 'Get project action uses the' \ " Retrieve a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-a-project', From 9a274a11b36b65449e4181eadf8d9ead7a82a23d Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 22:49:16 -0400 Subject: [PATCH 21/96] update title and description for `New annotation..` --- custom_connectors/oauth2/plangrid.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index bca6b3a6..15e33c0c 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2398,14 +2398,14 @@ end }, new_updated_annotations: { - title: 'New/updated annotations in Project', - description: 'New/updated annotations '\ - 'in Project Plangrid', + title: 'New or updated annotation in a project', + description: 'New or updated annotation '\ + 'in a PlanGrid project', help: { - body: 'New/updated annotations in Project trigger uses the' \ + body: 'New or updated annotation in project trigger uses the' \ " Retrieve " \ - ' annotations in a Project API.', + ' Annotations in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-annotations-in-a-project', learn_more_text: 'Retrieve Annotations in a Project' From bd80e21fb6c754fe64ba8a370c572d3cc4551504 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 22:49:37 -0400 Subject: [PATCH 22/96] update `annotation` object definition --- custom_connectors/oauth2/plangrid.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 15e33c0c..bc7ada15 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -342,11 +342,11 @@ annotation: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'Unique Identifier' }, + { name: 'uid', label: 'Annotation ID' }, { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -373,9 +373,8 @@ hint: 'Allowed values are: true, false' } }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid' }, - { name: 'label' }, - { name: 'color' } + { name: 'uid', label: 'UID' }, + { name: 'url' } ] } ] end From 1444a9b664dd8649189b47b849313319fdb7757b Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 23:00:41 -0400 Subject: [PATCH 23/96] update `sheet` object definition --- custom_connectors/oauth2/plangrid.rb | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index bc7ada15..4f7875ff 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -711,13 +711,29 @@ fields: lambda do |_connection, _config_fields| [ { name: 'uid', label: 'Sheet ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project ID', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, { name: 'name' }, - { name: 'version_name' }, + { name: 'version_name', label: 'Version Name' }, { name: 'description' }, - { name: 'tags', hint: 'An array of strings representing the' \ + { name: 'tags', type: 'array', of: 'string', hint: 'An array of strings representing the' \ ' tags added to this sheet.' }, { name: 'published_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, @@ -736,7 +752,7 @@ toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'uploaded_file_name' } + { name: 'uploaded_file_name', label: 'Uploaded file name' } ] end }, From 9d9913c5c690c8ad06af960a8a7dfb6292e94125 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 23:01:24 -0400 Subject: [PATCH 24/96] update title and description for `Get sheet...` action, append `project_uid` to result --- custom_connectors/oauth2/plangrid.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 4f7875ff..c78e5d90 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1802,13 +1802,13 @@ end }, get_sheet_in_project: { - title: 'Get sheet by ID in project', - description: 'Get sheet in'\ - ' Plangrid project', + title: 'Get sheet in a project', + description: 'Get sheet in '\ + 'a PlanGrid project', help: { - body: 'Get project sheet details action uses the ' \ + body: 'Get sheet in a project action uses the ' \ "Retrieve Sheets in a Project.", + " target='_blank'>Retrieve Sheet in a Project.", learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-a-sheet', learn_more_text: 'Retrieve Sheet in a Project' @@ -1818,7 +1818,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1831,11 +1831,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'sheet_uid', type: 'Sheet ID', optional: false } + { name: 'sheet_uid', label: 'Sheet ID', optional: false } ] end, execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/sheets/#{input['sheet_uid']}") + get("/projects/#{input['project_uid']}/sheets/#{input['sheet_uid']}")&. + merge('project_uid' => input['project_uid']) end, output_fields: lambda do |object_definitions| object_definitions['sheet'] From 34ffbdd734cb5e45089ec6f15ed5dbd17124d5fd Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 23:16:13 -0400 Subject: [PATCH 25/96] add `New or updated sheet...` trigger --- custom_connectors/oauth2/plangrid.rb | 80 ++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index c78e5d90..f7fe9efe 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2250,6 +2250,86 @@ get('/projects')&.dig('data', 0) || {} end }, + new_updated_sheets: { + title: 'New or updated sheet in a project', + description: 'New or updated sheet in '\ + 'a PlanGrid project', + help: { + body: 'New or updated sheet in a project trigger uses the' \ + " Retrieve Sheets in a Project" \ + ' API.', + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'sheets-in-a-project', + learn_more_text: 'Retrieve Sheets in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 5 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{project_uid}/sheets"). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + sheets = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: sheets || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |sheet| + "#{sheet['uid']}@#{sheet['created_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['sheet'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/sheets")&.dig('data', 0) || {} + end + }, new_updated_documents: { title: 'New or updated document in a project', description: 'New or updated document in '\ From d56295d6ac12ac2dfb4a3a3b9117bb8aa0c33ab8 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 22 Aug 2019 23:53:46 -0400 Subject: [PATCH 26/96] update title and description for `New project` trigger --- custom_connectors/oauth2/plangrid.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index f7fe9efe..7fa44000 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2191,13 +2191,13 @@ }, triggers: { new_updated_project: { - title: 'New/updated project', - description: 'New/updated project in'\ - ' Plangrid', + title: 'New or updated project', + description: 'New or updated project in'\ + ' PlanGrid', help: { - body: 'New/updated project trigger uses the' \ + body: 'New or updated project trigger uses the' \ " List all Projects API.", + " target='_blank'>List All Projects API.", learn_more_url: 'https://developer.plangrid.com/docs/list-all-projects', learn_more_text: 'List All Projects API' }, From 6b8e05e991eae651582e0b2c97d05e8a6e689380 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 00:33:25 -0400 Subject: [PATCH 27/96] update `rfi` object definition --- custom_connectors/oauth2/plangrid.rb | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 7fa44000..c420f08f 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -592,7 +592,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -607,7 +607,7 @@ } }, { name: 'number', type: 'integer' }, { name: 'status', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'label' }, { name: 'color' } ] }, @@ -634,12 +634,9 @@ { name: 'due_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, - { name: 'assigned_to_uids', - hint: 'Array of unique identifiers of users who ' \ - 'are RFI assignees.' }, { name: 'assigned_to', type: 'array', of: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, @@ -651,7 +648,7 @@ "timestamps-and-timezones' target='_blank'>Timestamps and " \ 'Timezones for accepted date formats' }, { name: 'updated_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, @@ -659,7 +656,7 @@ render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, From a6e02305430b5b34feddc8fbeafabfbf7f48fe3a Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 00:33:44 -0400 Subject: [PATCH 28/96] update `rfi_status` object definition --- custom_connectors/oauth2/plangrid.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index c420f08f..7c59a10b 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -682,7 +682,7 @@ rfi_status: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'RFI status ID' }, + { name: 'uid', label: 'Status ID' }, { name: 'label' }, { name: 'color' } ] From 7aa0f0f58111136276bc2afa6c3bb37262375be0 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 00:34:05 -0400 Subject: [PATCH 29/96] update title and description for `Create RFI...` action --- custom_connectors/oauth2/plangrid.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 7c59a10b..d4bd45fe 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1187,9 +1187,9 @@ create_rfi: { title: 'Create RFI in a project', description: 'Create RFI in'\ - ' a Plangrid project ', + ' a PlanGrid project ', help: { - body: 'Create RFI in project action uses the ' \ + body: 'Create RFI in a project action uses the ' \ "Create RFI in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-rfi-' \ From af586b79c34092d574dec56d31643135cf4984e3 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 00:34:44 -0400 Subject: [PATCH 30/96] update title and description for `Update RFI..` action --- custom_connectors/oauth2/plangrid.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index d4bd45fe..e7929e12 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1246,11 +1246,11 @@ update_rfi: { title: 'Update RFI in a project', description: 'Update RFI in'\ - ' a Plangrid project', + ' a PlanGrid project', help: { - body: 'Update RFI in Project action uses the ' \ + body: 'Update RFI in a project action uses the ' \ "patchUpdate RFI in a Project API.", + "project' target='_blank'>Update RFI in a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-' \ 'rfi-in-a-project', learn_more_text: 'Update RFI in a Project' @@ -1273,8 +1273,7 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'status', label: 'Status', - hint: 'Use this for create and update rfi status' } + { name: 'status', label: 'Status UID' } ].concat(object_definitions['rfi']. only('uid', 'locked', 'title', 'question', 'answer', 'sent_at', 'due_at', 'assigned_to_uids'). From a5669a4097016efee99674d97ec558ed6f70a259 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 00:35:57 -0400 Subject: [PATCH 31/96] update title and description for `Get RFI..` action, include input fields without using object definition for RFI due to sorting issues (RFI ID came before Project) --- custom_connectors/oauth2/plangrid.rb | 29 ++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index e7929e12..94fd0e16 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1304,10 +1304,10 @@ }, get_rfi_in_project: { title: 'Get RFI in a project', - description: 'Get RFI by ID in'\ - ' Plangrid project', + description: 'Get RFI in '\ + 'a PlanGrid project', help: { - body: 'Get RFI by ID in a project action uses the' \ + body: 'Get RFI in a project action uses the' \ " Retrieve RFI in a Project API.", @@ -1316,12 +1316,29 @@ learn_more_text: 'Retrieve RFI in a Project' }, input_fields: lambda do |object_definitions| - object_definitions['rfi'].only('project_uid', 'uid'). - required('project_uid', 'uid') + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'rfi_uid', label: 'RFI ID', optional: false } + ] end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') - get("/projects/#{project_uid}/rfis/#{input['uid']}")&. + get("/projects/#{project_uid}/rfis/#{input['rfi_uid']}")&. merge('project_uid' => project_uid) end, output_fields: lambda do |object_definitions| From a057b4c5fd3e53fa473c342ba9c262532b8f6b3a Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 00:36:20 -0400 Subject: [PATCH 32/96] update title and description for `Get RFI statuses...` action --- custom_connectors/oauth2/plangrid.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 94fd0e16..1206943d 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1655,10 +1655,10 @@ }, get_rfi_statuses_in_project: { title: 'Get RFI statuses in project', - description: 'Get rfi statuses in'\ - ' Plangrid project', + description: 'Get RFI statuses in'\ + ' a PlanGrid project', help: { - body: 'Get rfi statuses in project action uses the ' \ + body: 'Get RFI statuses in project action uses the ' \ "Retrieve RFI Statuses in a Project.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ From e8e473d38457490ebd7c9a0a8bc260dc3776601f Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 00:36:46 -0400 Subject: [PATCH 33/96] update title and description for `New or updated RFI..` trigger --- custom_connectors/oauth2/plangrid.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 1206943d..7a9bb7cc 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2837,11 +2837,11 @@ end }, new_updated_rfi: { - title: 'New/updated RFI in a Project', - description: 'New/updated RFI '\ - 'in a Plangrid Project', + title: 'New or updated RFI in a project', + description: 'New or updated RFI '\ + 'in a PlanGrid project', help: { - body: 'New/updated RFI in a Project trigger uses the' \ + body: 'New or updated RFI in a project trigger uses the' \ " Retrieve " \ ' RFIs in a Project API.', From 0b134419809028d32696cd70aeedfa2e7b2a2f91 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 10:16:04 -0400 Subject: [PATCH 34/96] update `task` object definition --- custom_connectors/oauth2/plangrid.rb | 155 ++++++++++++++------------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 7a9bb7cc..a0b1fff5 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -170,7 +170,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -183,26 +183,64 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, + { name: 'number', type: 'number' }, + { name: 'title' }, + { name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending",' \ + ' "closed".' + } }, + { name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work",' \ + ' "other".' + } }, { name: 'assignees', type: 'array', of: 'object', properties: [ - { name: 'assignee' } + { name: 'uid', label: 'UID' }, + { name: 'type' } ] }, + { name: 'followers', label: 'Watchers', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'type' } + ] }, + { name: 'room', label: 'Location' }, + { name: 'start_date', label: 'Start Date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, { name: 'closed_at', type: 'date_time', render_input: 'date_time_conversion', parse_output: 'date_time_conversion' }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'created_by', type: 'object', properties: [ + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'string', label: 'Stamp', + hint: 'One to two character stamp associated with task.' }, + { name: 'issue_list', label: 'Issue List', type: 'object', properties: [ { name: 'uid' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'comments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'cost_impact', type: 'number' }, - { name: 'has_cost_impact', type: 'boolean', + { name: 'description' }, + { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, + { name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', control_type: 'checkbox', toggle_hint: 'Select from options list', toggle_field: { name: 'cost_impact', @@ -212,12 +250,23 @@ toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'currency_code', + { name: 'currency_code', label: 'Currency Code', hint: 'The ISO-4217 currency code of the cost_impact,' \ ' Currently only supports USD. maybe null if cost_impact is ' \ 'not specified' }, + { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, + { name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_schedule_impact', + label: 'Has schedule impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, { name: 'current_annotation', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'color' }, { name: 'stamp' }, { name: 'visibility' }, @@ -232,84 +281,36 @@ hint: 'Allowed values are: true, false' } }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' } ] } ] }, - { name: 'deleted', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'description' }, - { name: 'due_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'followers', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' } - ] }, - { name: 'issue_list', type: 'object', properties: [ - { name: 'uid' }, + { name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'number', type: 'number' }, { name: 'photos', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'room' }, - { name: 'schedule_impact', type: 'integer' }, - { name: 'has_schedule_impact', type: 'boolean', + { name: 'deleted', label: 'Deleted?', type: 'boolean', control_type: 'checkbox', toggle_hint: 'Select from options list', toggle_field: { - name: 'has_schedule_impact', - label: 'Has schedule impact', + name: 'deleted', + label: 'Deleted', type: 'string', control_type: 'text', toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'start_date', - type: 'date_time', - render_input: 'date_conversion', - parse_output: 'date_conversion' }, - { name: 'status', control_type: 'select', pick_list: - %w[open in_review pending closed].select { |op| [op.labelize, op] }, - toggle_hint: 'Select status', - toggle_field: { - name: 'status', - label: 'Status', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are : "open", "in_review", "pending",' \ - ' "closed".' - } }, - { name: 'string', - hint: 'One to two character stamp associated with task.' }, - { name: 'title' }, - { name: 'type', control_type: 'select', - pick_list: [ - %w[issue issue], - %w[Planned\ work planned_work], - %w[other other] - ], - toggle_hint: 'Select type', - toggle_field: { - name: 'type', - label: 'Type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: "issue", "planned_work",' \ - ' "other".' - } }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] }, { name: 'updated_at', render_input: 'date_time_conversion', parse_output: 'date_time_conversion', From 5b3d4211f86c1d28e1a19bb08a06b116471b028c Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 10:16:38 -0400 Subject: [PATCH 35/96] update title and description for `Create task..` action, re-order fields --- custom_connectors/oauth2/plangrid.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index a0b1fff5..db62e901 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1354,11 +1354,11 @@ create_task: { title: 'Create task in a project', description: 'Create task in'\ - ' Plangrid project', + ' a PlanGrid project', help: { - body: 'Create task in Project action uses the ' \ + body: 'Create task in a project action uses the ' \ "Create task in Project API.", + "project' target='_blank'>Create Task in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-task-in-' \ 'a-project', learn_more_text: 'Create Task in a Project' @@ -1382,10 +1382,11 @@ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } } ].concat(object_definitions['task']. - only('assigned_to_uids', 'cost_impact', 'description', 'due_at', - 'has_cost_impact', 'has_schedule_impact', - 'issue_list_uid', 'room', 'schedule_impact', 'start_date', - 'status', 'title', 'type')) + only('title', 'status', 'type', 'assigned_to_uids', + 'room', 'start_date', 'due_at', 'issue_list_uid', + 'description', 'has_cost_impact', 'cost_impact', + 'has_schedule_impact', 'schedule_impact' + )) end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') From ee2d2498d25a9b0b3520a609347580fa4209610c Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 10:17:35 -0400 Subject: [PATCH 36/96] update title and description for `Update task..` action, re-order fields, clear empty objects --- custom_connectors/oauth2/plangrid.rb | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index db62e901..6b679b4a 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1412,13 +1412,13 @@ end }, update_task: { - title: 'Update task in a Project', + title: 'Update task in a project', description: 'Update task in'\ - ' Plangrid project', + ' a PlanGrid project', help: { - body: 'Update task in Project action uses the ' \ + body: 'Update task in a project action uses the ' \ "Create task in Project API.", + "project' target='_blank'>Update Task in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-project', learn_more_text: 'Update Task in a Project' }, @@ -1439,17 +1439,22 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g.' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } } + } }, + { name: 'issue_uid', label: 'Task ID', optional: false } ].concat(object_definitions['task']. - only('uid', 'assigned_to_uids', 'cost_impact', 'description', - 'due_at', 'has_cost_impact', 'has_schedule_impact', - 'issue_list_uid', 'room', 'schedule_impact', 'start_date', - 'status', 'title', 'type').required('uid')) + only('title', 'status', 'type', 'assigned_to_uids', + 'room', 'start_date', 'due_at', 'issue_list_uid', + 'description', 'has_cost_impact', 'cost_impact', + 'has_schedule_impact', 'schedule_impact' + )) end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') + payload = input.each do |key, value| + input[key].present? || input[key] = nil + end patch("/projects/#{project_uid}/issues/" \ - "#{input.delete('uid')}").payload(input). + "#{input.delete('issue_uid')}").payload(payload). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end&.merge('project_uid' => project_uid) From 4812fd3d0a913cce3871c6f423e441018d07a256 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 10:18:07 -0400 Subject: [PATCH 37/96] update title and description for `Get task..` action, change field name to `Task ID` --- custom_connectors/oauth2/plangrid.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 6b679b4a..0c23a1d1 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1471,7 +1471,7 @@ get_task: { title: 'Get task in a project', description: 'Get task in'\ - ' in a Plangrid project', + ' a PlanGrid project', help: { body: 'Get task in a project action uses the ' \ " Date: Fri, 23 Aug 2019 10:18:30 -0400 Subject: [PATCH 38/96] update title and description for `New or updated task..` --- custom_connectors/oauth2/plangrid.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 0c23a1d1..ebb3970c 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2431,11 +2431,11 @@ end }, new_updated_task: { - title: 'New/updated task in a Project', - description: 'New/updated task in a '\ - 'Project Plangrid', + title: 'New or updated task in a project', + description: 'New or updated task in a '\ + ' PlanGrid project', help: { - body: 'New/updated task in a Project trigger uses the' \ + body: 'New or updated task in a project trigger uses the' \ " Retrieve Tasks " \ ' in a Project API.', From db780a79321d7dbecadea9fc1db661d24fece8ea Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 10:59:20 -0400 Subject: [PATCH 39/96] update `field_report` object definition --- custom_connectors/oauth2/plangrid.rb | 50 ++++++++++++---------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index ebb3970c..f282aec1 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -464,11 +464,11 @@ field_report: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'File report ID' }, + { name: 'uid', label: 'Field Report ID' }, { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -483,28 +483,27 @@ } }, { name: 'title' }, { name: 'description' }, - { name: 'report_date', type: 'date_time', + { name: 'report_date', label: 'Report Date', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, - { name: 'field_report_type', type: 'object', properties: [ + { name: 'status' }, + { name: 'field_report_type', label: 'Field Report Type', type: 'object', properties: [ { name: 'name' }, - { name: 'project_uid' }, { name: 'status' }, - { name: 'uid' } + { name: 'uid', label: 'UID' } ] }, - { name: 'pdf_url' }, - { name: 'pdf_form_values', type: 'array', of: 'object', + { name: 'pdf_url', label: 'PDF URL' }, + { name: 'pdf_form_values', label: 'PDF Form Values', type: 'array', of: 'object', properties: [ { name: 'name' }, { name: 'value' } ] }, - { name: 'pg_form_values', type: 'array', of: 'object', properties: [ - { name: 'pg_equipment_entries', type: 'array', of: 'object', + { name: 'pg_form_values', label: 'Daily Report Values', type: 'array', of: 'object', properties: [ + { name: 'pg_worklog_entries', label: 'Work Log Entries', type: 'array', of: 'object', properties: [ - { name: 'uid' }, + { name: 'trade' }, { name: 'timespan' }, - { name: 'quantity', type: 'integer' }, - { name: 'item' }, + { name: 'headcount', type: 'integer' }, { name: 'description' }, { name: 'deleted', type: 'boolean', control_type: 'checkbox', @@ -518,21 +517,19 @@ hint: 'Allowed values are: true, false' } } ] }, - { name: 'pg_materials_entries', type: 'array', of: 'object', + { name: 'pg_materials_entries', label: 'Material Entries', type: 'array', of: 'object', properties: [ - { name: 'uid' }, { name: 'unit', type: 'integer' }, { name: 'quantity', type: 'integer' }, { name: 'item' }, { name: 'description' }, { name: 'deleted' } ] }, - { name: 'pg_worklog_entries', type: 'array', of: 'object', + { name: 'pg_equipment_entries', label: 'Equipment Entries', type: 'array', of: 'object', properties: [ - { name: 'uid' }, - { name: 'trade' }, { name: 'timespan' }, - { name: 'headcount', type: 'integer' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, { name: 'description' }, { name: 'deleted', type: 'boolean', control_type: 'checkbox', @@ -547,26 +544,23 @@ } } ] } ] }, - { name: 'attachments', type: 'object', properties: [ + { name: 'attachments', label: 'Documents', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'created_by', type: 'object', properties: [ - { name: 'email' }, - { name: 'uid' }, - { name: 'url' } - ] }, { name: 'photos', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'project_uid', label: 'Project ID' }, - { name: 'report_date', type: 'date' }, { name: 'snapshots', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'status' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'email' }, + { name: 'uid', label: 'UID' }, + { name: 'url' } + ] }, { name: 'updated_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, From 9d9441964db6af79859adebbbb296abbffdb076c Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 10:59:59 -0400 Subject: [PATCH 40/96] update title and description for `Get field reports...` action, fix query params --- custom_connectors/oauth2/plangrid.rb | 38 +++++++++++++++++----------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index f282aec1..0ee4976a 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1903,11 +1903,11 @@ end }, get_field_reports_in_project: { - title: 'Get fields reports in project', + title: 'Get field reports in a project', description: 'Get field reports in'\ - ' in Plangrid project', + ' a PlanGrid project', help: { - body: 'Get fields reports in project action uses the ' \ + body: 'Get field reports in a project action uses the ' \ "Retrieve Field Reports in a" \ ' Project API.', @@ -1920,7 +1920,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1933,17 +1933,17 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'updated_after', type: 'date_time', - hint: 'Only retrieve field reports created/updated after ' \ - 'specified UTC date and time.' }, - { name: 'report_date_min', type: 'date_time', - label: 'Report start date', + { name: 'report_date_min', type: 'date', + label: 'Report Start Date', hint: 'Only retrieve field reports between a date range ' \ 'starting with this date in UTC format.' }, - { name: 'report_date_max', type: 'date_time', - label: 'Report end date', + { name: 'report_date_max', type: 'date', + label: 'Report End Date', hint: 'Only retrieve field reports between a date range ' \ 'starting with this date in UTC format.' }, + { name: 'updated_after', label: 'Updated After', type: 'date_time', + hint: 'Only retrieve field reports created/updated after ' \ + 'specified UTC date and time.' }, { name: 'sort_by', control_type: 'select', pick_list: %w[report_date updated_at]&.map { |e| [e.labelize, e] }, @@ -1951,6 +1951,14 @@ toggle_field: { name: 'sort_by', type: 'string', control_type: 'text', hint: 'Allowed values report_date or updated_at' + } }, + { name: 'sort_order', control_type: 'select', + pick_list: + %w[asc desc]&.map { |e| [e.labelize, e] }, + toggle_hint: 'Select sort order', + toggle_field: { + name: 'sort_by', type: 'string', control_type: 'text', + hint: 'Allowed values asc or desc' } } ] end, @@ -1958,17 +1966,17 @@ project_uid = input.delete('project_uid') query_params = '' input&.map do |key, val| - if %w[updated_after report_date_min report_date_max].include?(key) - query_params = query_params + "#{key}=#{val.to_time.utc.iso8601}" + if %w[updated_after].include?(key) + query_params = query_params + "&" + "#{key}=#{val.to_time.utc.iso8601}" else - query_params = query_params + "#{key}=#{val}" + query_params = query_params + "&" + "#{key}=#{val}" end end { field_reports: get("/projects/#{project_uid}/field_reports?" \ "#{query_params}")['data'] } end, output_fields: lambda do |object_definitions| - { name: 'field_reports', type: 'array', of: 'object', + { name: 'field_reports', label: 'Field Reports', type: 'array', of: 'object', properties: object_definitions['field_report'] } end, sample_output: lambda do |_connection, _input| From b791115eb1561040393351576a0a0f39c959dd23 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 11:00:24 -0400 Subject: [PATCH 41/96] update title and description for `New or updated field report` trigger --- custom_connectors/oauth2/plangrid.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 0ee4976a..23389ec5 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2762,17 +2762,17 @@ end }, new_updated_field_report: { - title: 'New/updated field report in a Project', - description: 'New/updated field report '\ - 'in Plangrid Project', + title: 'New or updated field report in a project', + description: 'New or updated field report '\ + 'in a PlanGrid project', help: { - body: 'New/updated field report in Project trigger uses the' \ + body: 'New or updated field report in a project trigger uses the' \ " Retrieve " \ - 'field reports in a Project API.', + 'Field Reports in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-field-reports-in-a-project', - learn_more_text: 'Retrieve field reports in a Project' + learn_more_text: 'Retrieve Field Reports in a Project' }, input_fields: lambda do |_object_definitions| [ From 59f120510496a84da422319db3ef0eeb86d72363 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 14:22:48 -0400 Subject: [PATCH 42/96] update `user` object definition --- custom_connectors/oauth2/plangrid.rb | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 23389ec5..5c2fc59d 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -687,15 +687,31 @@ fields: lambda do |_connection, _config_fields| [ { name: 'uid', label: 'User ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project ID', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, { name: 'email' }, - { name: 'first_name' }, - { name: 'last_name' }, - { name: 'language' }, + { name: 'first_name', label: 'First Name' }, + { name: 'last_name', label: 'Last Name' }, + { name: 'language'}, { name: 'role', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' } ] }, - { name: 'removed' } + { name: 'removed', label: 'Removed?' } ] end }, From c7bbd4dc333565741162b0db3fc3a841689200d0 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 14:23:25 -0400 Subject: [PATCH 43/96] update title and description for `Invite user...` action, append `project_uid` to result --- custom_connectors/oauth2/plangrid.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 5c2fc59d..5c69db6e 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1529,23 +1529,23 @@ end }, invite_user_to_project: { - title: 'Invite a user to a project', + title: 'Invite user to a project', description: 'Invite user to'\ - ' project team Plangrid', + ' a PlanGrid project', help: { body: 'Invite user to a project action uses the ' \ "Invite user in Project team API.", + "project-team' target='_blank'>Invite User in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ 'invite-user-to-project-team', - learn_more_text: 'Invite User to Project Team' + learn_more_text: 'Invite User to Project' }, input_fields: lambda do |_object_definitions| [ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1559,16 +1559,17 @@ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, { name: 'email', optional: false }, - { name: 'role_uid', label: 'Role ID', + { name: 'role_uid', label: 'Role ID', sticky: true, hint: 'Unique identifier of role to assign user on project team' } ] end, execute: lambda do |_connection, input| - post("/projects/#{input.delete('project_uid')}/users/invites"). + project_uid = input.delete('project_uid') + post("/projects/#{project_uid}/users/invites"). payload(input). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") - end + end&.merge('project_uid' => project_uid) end, output_fields: lambda do |object_definitions| object_definitions['user'] From f27a2dbf96e1e342cd02ee6ec0b546b9dbc1025e Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 14:23:47 -0400 Subject: [PATCH 44/96] update title and description for `Get user...` action --- custom_connectors/oauth2/plangrid.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 5c69db6e..2b9544a6 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1582,14 +1582,14 @@ get_user_in_project: { title: 'Get user in project', description: 'Get user in'\ - ' Plangrid project', + ' a PlanGrid project', help: { - body: 'Get user in project action uses the ' \ + body: 'Get user in a project action uses the ' \ "Retrieve User on a Project Team.", + "project-team' target='_blank'>Retrieve User in a Project.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ 'users-on-a-project-team', - learn_more_text: 'Retrieve User on a Project Team' + learn_more_text: 'Retrieve User in a Project' }, input_fields: lambda do |_object_definitions| [ From 295e6f7374d4d90e9c1688d422df059986a24e9d Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 14:24:26 -0400 Subject: [PATCH 45/96] update title and description for `Get roles..` action, remove additional params --- custom_connectors/oauth2/plangrid.rb | 37 ++++++++++++---------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 2b9544a6..419336de 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1724,23 +1724,23 @@ end }, get_roles_on_project: { - title: 'Get roles on a project', - description: 'Get roles on '\ - ' Plangrid project', + title: 'Get roles in a project', + description: 'Get roles in '\ + ' a PlanGrid project', help: { - body: 'Get role on a project action uses the ' \ - "Retrieve Role on a Project API.", + body: 'Get roles in a project action uses the ' \ + "Retrieve Roles on a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-role-on-a-project', - learn_more_text: 'Retrieve Role on a Project' + 'retrieve-roles-on-a-project', + learn_more_text: 'Retrieves Role on a Project' }, input_fields: lambda do |_object_definitions| [ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1752,24 +1752,19 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'limit', type: 'integer', - hint: 'Number of roles to retrieve. Maximum value of 50.' }, - { name: 'skip', type: 'integer', - hint: 'Number of roles to skip in the set of results.' } + } } ] end, execute: lambda do |_connection, input| - { roles: get("/projects/#{input.delete('project_uid')}/roles", input) } + project_uid = input.delete('project_uid') + { roles: get("/projects/#{project_uid}/roles")['data'] } end, output_fields: lambda do |_object_definitions| [ - { name: 'roles', type: 'array', of: 'object', properties: [ - { name: 'uid' }, - { name: 'label' } - ] }, - { name: 'total_count' }, - { name: 'next_page_url' } + { name: 'roles', label: 'Roles', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'label', label: 'Role' } + ] } ] end, sample_output: lambda do |_connection, _input| From 4773c8c41ae1e72aa55ae48a0cd679c053460603 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 15:31:44 -0400 Subject: [PATCH 46/96] remove `Get sheets..` action --- custom_connectors/oauth2/plangrid.rb | 56 +--------------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 419336de..e8b447d2 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1772,61 +1772,7 @@ 'label' => 'Admin' } } end }, - get_sheets_in_project: { - title: 'Get sheets in project', - description: 'Get sheets in'\ - ' Plangrid project', - help: { - body: 'Get sheets in project action uses the ' \ - "Retrieve Sheets in a Project.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-sheets-in-a-project', - learn_more_text: 'Retrieve Sheets in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'limit', type: 'integer', - hint: 'Number of sheets to retrieve. Maximum value of 50.' }, - { name: 'skip', type: 'integer', - hint: 'Number of sheets to skip in the set of results' }, - { name: 'updated_after', type: 'date_time', - hint: 'Only retrieve sheets created/updated after ' \ - 'specified UTC date and time.' } - ] - end, - execute: lambda do |_connection, input| - { sheets: get("/projects/#{input.delete('project_uid')}/sheets", - input)['data'] } - end, - output_fields: lambda do |object_definitions| - [{ name: 'sheets', type: 'array', of: 'object', - properties: object_definitions['sheet'] }] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - { - sheets: get("/projects/#{id}/sheets?limit=1")&.dig('data', 0)&. - merge('project_uid' => id) || {} - } - end - }, + get_sheet_in_project: { title: 'Get sheet in a project', description: 'Get sheet in '\ From 7076bd0f80213a0e6fdf4b4da934004557e961cb Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 15:32:11 -0400 Subject: [PATCH 47/96] update `sheet_packet` object definition --- custom_connectors/oauth2/plangrid.rb | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index e8b447d2..5e727082 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -767,13 +767,29 @@ sheet_packet: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'Sheet packet ID' }, - { name: 'file_url' }, + { name: 'uid', label: 'Sheet Packet ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project ID', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'status' }, + { name: 'file_url', label: 'File URL' }, { name: 'resource', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' } - ] }, - { name: 'status' } + ] } ] end }, From 338641a8c1f88a824fa40b7bf6011632a36d0bc0 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 15:32:51 -0400 Subject: [PATCH 48/96] update title and description for `Get sheet packet...` action --- custom_connectors/oauth2/plangrid.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 5e727082..5fd9fc51 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1836,11 +1836,11 @@ end }, get_project_sheet_packet: { - title: 'Get project sheet packet', - description: 'Get project sheet packet in'\ - ' packet in Plangrid', + title: 'Get sheet packet in a project', + description: 'Get sheet packet in'\ + ' a PlanGrid project', help: { - body: 'Get project sheet packet action uses the ' \ + body: 'Get sheet packet in a project action uses the ' \ "Retrieve Sheet Packet API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -1865,12 +1865,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'packet_uid', type: 'Packet ID' } + { name: 'packet_uid', label: 'Sheet Packet ID', optional: false } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/sheets/packets/" \ - "#{input['packet_uid']}") + "#{input['packet_uid']}")&.merge('project_uid' => input['project_uid']) end, output_fields: lambda do |object_definitions| object_definitions['sheet_packet'] From 2067a2ac473f4efb85d6492cbd1c0207cde65af6 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 15:33:24 -0400 Subject: [PATCH 49/96] add `Create sheet packet` action --- custom_connectors/oauth2/plangrid.rb | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 5fd9fc51..62d60c1a 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2183,6 +2183,77 @@ get("/projects/#{id}/attachments")&.dig('data', 0)&. merge('project_uid' => id) || {} end + }, + create_sheet_packet: { + title: 'Create sheet packet in a project', + description: 'Create sheet packet in '\ + ' a PlanGrid project', + help: { + body: 'Create sheet packet in a project action uses the' \ + " Create Sheet Packet in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/upload-photo' \ + '-to-project', + learn_more_text: 'Create Sheet Packet in a Project' + }, + input_fields: lambda do |object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'sheet_uids', label: 'Sheet IDs', optional: false, + type: 'string', + hint: 'A comma separated list of sheet IDs.' }, + { name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'include_annotations', + label: 'Include annotations?', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + ] + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + payload = { + sheet_uids: input.delete('sheet_uids').split(','), + include_annotations: input.delete('include_annotations') + } + post("/projects/#{project_uid}/sheets/packets").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['sheet_packet'] + end, + sample_output: lambda do |_connection, _input| + { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + file_url: "https://packet-assets.plangrid.com/92cf7193-af0c-42fc-a3ab-7ef5149da720.pdf", + resource: { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/packets/92cf7193-af0c-42fc-a3ab-7ef5149da720" + }, + status: "incomplete" + } + end } }, triggers: { From ecedf21a6c5e670052cc300c04bf35760034f338 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 17:25:36 -0400 Subject: [PATCH 50/96] update `task` object definition to reference Task List instead of Issue List --- custom_connectors/oauth2/plangrid.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 62d60c1a..0a654086 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -234,8 +234,8 @@ parse_output: 'date_time_conversion' }, { name: 'string', label: 'Stamp', hint: 'One to two character stamp associated with task.' }, - { name: 'issue_list', label: 'Issue List', type: 'object', properties: [ - { name: 'uid' }, + { name: 'issue_list', label: 'Task List', type: 'object', properties: [ + { name: 'uid', label: 'Task List ID' }, { name: 'url' } ] }, { name: 'description' }, From b465e618a9fd792f7119c7f6f6bc78066e1fe9fa Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 17:26:24 -0400 Subject: [PATCH 51/96] add correct `issue_list_uid` field when creating/updating task --- custom_connectors/oauth2/plangrid.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 0a654086..71d61a5e 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1406,10 +1406,12 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } } + } + }, + { name: 'issue_list_uid', label: 'Task List ID', sticky: true } ].concat(object_definitions['task']. only('title', 'status', 'type', 'assigned_to_uids', - 'room', 'start_date', 'due_at', 'issue_list_uid', + 'room', 'start_date', 'due_at', 'description', 'has_cost_impact', 'cost_impact', 'has_schedule_impact', 'schedule_impact' )) @@ -1465,11 +1467,13 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g.' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'issue_uid', label: 'Task ID', optional: false } + } + }, + { name: 'issue_uid', label: 'Task ID', optional: false }, + { name: 'issue_list_uid', label: 'Task List ID', sticky: true } ].concat(object_definitions['task']. only('title', 'status', 'type', 'assigned_to_uids', - 'room', 'start_date', 'due_at', 'issue_list_uid', + 'room', 'start_date', 'due_at', 'description', 'has_cost_impact', 'cost_impact', 'has_schedule_impact', 'schedule_impact' )) From f7633838afcf5dea4cfd557cd25a3425e66cca44 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 17:26:49 -0400 Subject: [PATCH 52/96] add `Get task list..`, `Update task list..`, `Create task list..` action --- custom_connectors/oauth2/plangrid.rb | 186 +++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 71d61a5e..e1c3aafc 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2258,6 +2258,192 @@ status: "incomplete" } end + }, + get_task_list: { + title: 'Get task list in a project', + description: 'Get task list'\ + ' in a PlanGrid project', + help: { + body: 'Get task list in a project action uses the ' \ + "Retrieve Task List in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-issue-list', + learn_more_text: 'Retrieve Task List in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'issue_list_uid', label: 'Task List ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + get("/projects/#{input['project_uid']}/issue_lists/" \ + "#{input['issue_list_uid']}") + end, + output_fields: lambda do |object_definitions| + [ + { + name: "uid", label: "Task List ID" + }, + { + name: "project_uid", label: "Project ID" + }, + { + name: "name", label: "Name" + }, + { + name: "deleted", label: "Deleted", type: "boolean" + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", + name: "QA/QC", + deleted: false, + project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" + } + end + }, + update_task_list: { + title: 'Update task list in a project', + description: 'Update task list'\ + ' in a PlanGrid project', + help: { + body: 'Update task list in a project action uses the ' \ + "Update Task List in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'update-issue-list', + learn_more_text: 'Update Task List in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'issue_list_uid', label: 'Task List ID', optional: false }, + { name: 'name', optional: false } + ] + end, + execute: lambda do |_connection, input| + patch("/projects/#{input['project_uid']}/issue_lists/" \ + "#{input['issue_list_uid']}").payload({name: input.delete('name')}) + end, + output_fields: lambda do |object_definitions| + [ + { + name: "uid", label: "Task List ID" + }, + { + name: "project_uid", label: "Project ID" + }, + { + name: "name", label: "Name" + }, + { + name: "deleted", label: "Deleted", type: "boolean" + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", + name: "QA/QC", + deleted: false, + project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" + } + end + }, + create_task_list: { + title: 'Create task list in a project', + description: 'Create task list'\ + ' in a PlanGrid project', + help: { + body: 'Create task list in a project action uses the ' \ + "Create Task List in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'create-issue-list', + learn_more_text: 'Create Task List in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'name', optional: false } + ] + end, + execute: lambda do |_connection, input| + post("/projects/#{input.delete('project_uid')}/issue_lists").payload(input) + end, + output_fields: lambda do |object_definitions| + [ + { + name: "uid", label: "Task List ID" + }, + { + name: "project_uid", label: "Project ID" + }, + { + name: "name", label: "Name" + }, + { + name: "deleted", label: "Deleted", type: "boolean" + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", + name: "QA/QC", + deleted: false, + project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" + } + end } }, triggers: { From c1178ed7a04d9cd2618f7725468d8951ea3c42ee Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 23 Aug 2019 18:11:11 -0400 Subject: [PATCH 53/96] add `Create sheet version upload..`, `Upload file to sheet version..`, `Complete sheet upload..` action --- custom_connectors/oauth2/plangrid.rb | 213 +++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index e1c3aafc..05642dc7 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2444,6 +2444,219 @@ project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" } end + }, + create_sheet_version: { + title: 'Create sheet version upload in a project', + description: 'Create sheet version upload'\ + ' in a PlanGrid project', + help: { + body: 'Create sheet version in a project action uses the ' \ + "Upload Version to a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'upload-version-to-project', + learn_more_text: 'Upload Version to a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, + { name: 'version_name', label: 'Version Name', optional: false } + ] + end, + execute: lambda do |_connection, input| + post("/projects/#{input.delete('project_uid')}/sheets/uploads").payload(input) + end, + output_fields: lambda do |object_definitions| + [ + { + name: 'uid', label: 'Sheet Version Upload ID' + }, + { + name: 'complete_url', label: 'Upload Completion URL' + }, + { + name: 'status', + }, + { + name: 'file_upload_requests', label: 'File Upload Requests', + type: 'array', of: 'object', properties: [ + { + name: 'uid', label: 'File Upload ID' + }, + { + name: 'upload_status', label: 'File Upload Status' + }, + { + name: 'url', label: 'File Upload URL' + } + ] + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + complete_url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720", + status: "incomplete", + file_upload_requests: [ + { + uid: "b278fcba-72f0-4161-bfdc-89d5bde4d5e7", + upload_status: "issued", + url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720/files/b278fcba-72f0-4161-bfdc-89d5bde4d5e7" + }, + { + uid: "727fca7d-385b-4476-b257-4b96c00e879b", + upload_status: "issued", + url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720/files/727fca7d-385b-4476-b257-4b96c00e879b" + } + ] + } + end + }, + upload_file_to_sheet_version: { + title: 'Upload file to sheet version in a project', + description: 'Upload file to sheet version'\ + ' in a PlanGrid project', + help: { + body: 'Upload file to sheet version in a project action uses the ' \ + "Upload File to Version in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'upload-file-to-version', + learn_more_text: 'Upload File to Version in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false }, + { name: 'file_upload_request_uid', label: 'File Upload ID', optional: false }, + { name: 'file_name', label: 'File Name', optional: false }, + { name: 'file_content', label: 'File Content', optional: false } + ] + end, + execute: lambda do |_connection, input| + file_content = input.delete('file_content') + project_uid = input.delete('project_uid') + file_upload_info = post("/projects/#{project_uid}/sheets/" \ + "uploads/#{input.delete('ver_upload_uid')}/" \ + "files/#{input.delete('file_upload_request_uid')}"). + headers('Content-Type': 'application/json'). + payload({file_name: input.delete('file_name')}) + url = file_upload_info&.dig('aws_post_form_arguments', 'action') + fields = file_upload_info&.dig('aws_post_form_arguments', 'fields') + # webhook_url = file_upload_info. + # dig('aws_post_form_arguments', 'webhook_url') + headers = fields.map { |o| { o['name'] => o['value'] } }.inject(:merge) + status = + post(url). + payload(key: headers['key'], + policy: headers['policy'], + signature: headers['signature'], + AWSAccessKeyId: headers['AWSAccessKeyId'], + 'content-type': headers['Content-Type'], + 'success_action_redirect': headers['success_action_redirect'], + 'x-amz-server-side-encryption': + headers['x-amz-server-side-encryption'], + 'x-amz-storage-class': headers['x-amz-storage-class'], + file: file_content). + request_format_multipart_form. + after_response do |_code, response, _response_headers| + response + end + end, + output_fields: lambda do |object_definitions| + + end, + sample_output: lambda do |_connection, _input| + + end + }, + complete_version_upload: { + title: 'Complete sheet version upload to a project', + description: 'Complete sheet version upload '\ + ' to a PlanGrid project', + help: { + body: 'Complete sheet version upload to a project action uses the ' \ + "Complete Version Upload in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'complete-version-upload-to-project', + learn_more_text: 'Complete Version Upload in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + post("/projects/#{project_uid}/sheets/" \ + "uploads/#{input.delete('ver_upload_uid')}/completions")&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + [ + { + name: 'uid', label: 'Sheet Version ID' + }, + { + name: 'status', label: 'Status' + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + complete_url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720", + status: "complete" + } + end } }, triggers: { From 38bec9422c6977fda5164fb9df21f54629e64a11 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Thu, 29 Aug 2019 09:14:47 -0400 Subject: [PATCH 54/96] updated to meet rubocop guidelines by Chandra --- custom_connectors/oauth2/plangrid.rb | 1665 +++++++++----------------- 1 file changed, 547 insertions(+), 1118 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 05642dc7..5385c9a7 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1,5 +1,5 @@ { - title: 'PlanGrid', + title: 'Plangrid', connection: { fields: [ { @@ -54,6 +54,43 @@ end }, test: ->(_connection) { get('/me') }, + methods: { + format_api_output_field_names: lambda do |input| + if input.is_a?(Array) + input.map do |array_value| + call('format_api_output_field_names', array_value) + end + elsif input.is_a?(Hash) + input.map do |key, value| + value = call('format_api_output_field_names', value) + key = key.gsub(/\W/) { |string| "__#{string.encode_hex}__" } + { key => value } + end.inject(:merge) + else + input + end + end, + + format_schema_field_names: lambda do |input| + input.map do |field| + if field[:properties].present? + field[:properties] = call('format_schema_field_names', + field[:properties]) + elsif field['properties'].present? + field['properties'] = call('format_schema_field_names', + field['properties']) + end + if field[:name].present? + field[:name] = field[:name]. + gsub(/\W/) { |string| "__#{string.encode_hex}__" } + elsif field['name'].present? + field['name'] = field['name']. + gsub(/\W/) { |string| "__#{string.encode_hex}__" } + end + field + end + end + }, object_definitions: { project: { fields: lambda do |_connection, _config_fields| @@ -61,7 +98,7 @@ { name: 'uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -74,11 +111,11 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'name', label: 'Project Name', sticky: true }, - { name: 'custom_id', label: 'Project Code', sticky: true }, - { name: 'organization_id', label: 'Organization ID' }, + { name: 'name', label: 'Project name', sticky: true }, + { name: 'custom_id', label: 'Project code', sticky: true }, + { name: 'organization_id' }, { name: 'type', control_type: 'select', - label: 'Project Type', sticky: true, + label: 'Project type', sticky: true, pick_list: 'project_types', toggle_hint: 'Select project type', toggle_field: { @@ -93,26 +130,26 @@ 'education-k-12, education-higher, gov-federal, ' \ 'gov-state-local, or other' } }, - { name: 'status', label: 'Project Status', sticky: true }, - { name: 'owner', sticky: true, label: 'Project Owner' }, + { name: 'status', label: 'Project status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project owner' }, { name: 'start_date', type: 'date', sticky: true, render_input: 'date_conversion', parse_output: 'date_conversion', - label: 'Project Start Date', + label: 'Project start date', hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, { name: 'end_date', type: 'date', sticky: true, render_input: 'date_conversion', parse_output: 'date_conversion', - label: 'Project End Date', + label: 'Project end date', hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, { name: 'street_1', sticky: true, - label: 'Street Line 1' }, + label: 'Street line 1' }, { name: 'street_2', sticky: true, label: 'Street line 2' }, - { name: 'city', sticky: true, label: 'Town or City' }, - { name: 'region', sticky: true, label: 'State, Province, or Region' }, - { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, + { name: 'city', sticky: true, label: 'Town or city' }, + { name: 'region', sticky: true, label: 'State, province, or region' }, + { name: 'postal_code', sticky: true, label: 'Zip or postal code' }, { name: 'country', sticky: true, hint: 'Project address country in 2-letter ISO 3166 code.' }, @@ -121,7 +158,22 @@ { name: 'updated_at', type: 'date_time', render_input: 'date_time_conversion', parse_output: 'date_time_conversion', - label: 'Updated at' } + label: 'Updated at' }, + { name: 'add_to_organization', type: 'boolean', + control_type: 'checkbox', + hint: 'Boolean indicating whether to add the project to the ' \ + 'organization that the API user belongs to or not. By default ' \ + 'the project is created as a personal project and not as an ' \ + 'organization-linked project.', + toggle_hint: 'Select from options list', + toggle_field: { + name: 'add_to_organization', + label: 'Add to organization', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } ] end }, @@ -132,7 +184,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -145,14 +197,14 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'name', label: 'Document Name' }, + { name: 'name', label: 'Document name' }, { name: 'folder' }, { name: 'url' }, { name: 'created_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' }, { name: 'email' } ] }, @@ -170,7 +222,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -183,64 +235,26 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'number', type: 'number' }, - { name: 'title' }, - { name: 'status', control_type: 'select', pick_list: - %w[open in_review pending closed].select { |op| [op.labelize, op] }, - toggle_hint: 'Select status', - toggle_field: { - name: 'status', - label: 'Status', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are : "open", "in_review", "pending",' \ - ' "closed".' - } }, - { name: 'type', control_type: 'select', - pick_list: [ - %w[issue issue], - %w[Planned\ work planned_work], - %w[other other] - ], - toggle_hint: 'Select type', - toggle_field: { - name: 'type', - label: 'Type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: "issue", "planned_work",' \ - ' "other".' - } }, { name: 'assignees', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'type' } - ] }, - { name: 'followers', label: 'Watchers', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'type' } + { name: 'assignee' } ] }, - { name: 'room', label: 'Location' }, - { name: 'start_date', label: 'Start Date', - type: 'date_time', - render_input: 'date_conversion', - parse_output: 'date_conversion' }, { name: 'closed_at', type: 'date_time', render_input: 'date_time_conversion', parse_output: 'date_time_conversion' }, - { name: 'due_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'string', label: 'Stamp', - hint: 'One to two character stamp associated with task.' }, - { name: 'issue_list', label: 'Task List', type: 'object', properties: [ - { name: 'uid', label: 'Task List ID' }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] }, + { name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'description' }, - { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, - { name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', + { name: 'cost_impact', type: 'number' }, + { name: 'has_cost_impact', type: 'boolean', control_type: 'checkbox', toggle_hint: 'Select from options list', toggle_field: { name: 'cost_impact', @@ -250,23 +264,12 @@ toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'currency_code', label: 'Currency Code', + { name: 'currency_code', hint: 'The ISO-4217 currency code of the cost_impact,' \ ' Currently only supports USD. maybe null if cost_impact is ' \ 'not specified' }, - { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, - { name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'has_schedule_impact', - label: 'Has schedule impact', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, { name: 'current_annotation', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'color' }, { name: 'stamp' }, { name: 'visibility' }, @@ -281,36 +284,84 @@ hint: 'Allowed values are: true, false' } }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' } ] } ] }, - { name: 'comments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + { name: 'deleted', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, + { name: 'description' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'followers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' } + ] }, + { name: 'issue_list', type: 'object', properties: [ + { name: 'uid' }, { name: 'url' } ] }, + { name: 'number', type: 'number' }, { name: 'photos', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'deleted', label: 'Deleted?', type: 'boolean', + { name: 'room' }, + { name: 'schedule_impact', type: 'integer' }, + { name: 'has_schedule_impact', type: 'boolean', control_type: 'checkbox', toggle_hint: 'Select from options list', toggle_field: { - name: 'deleted', - label: 'Deleted', + name: 'has_schedule_impact', + label: 'Has schedule impact', type: 'string', control_type: 'text', toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] }, + { name: 'start_date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, + { name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending",' \ + ' "closed".' + } }, + { name: 'string', + hint: 'One to two character stamp associated with task.' }, + { name: 'title' }, + { name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work",' \ + ' "other".' + } }, { name: 'updated_at', render_input: 'date_time_conversion', parse_output: 'date_time_conversion', @@ -343,11 +394,11 @@ annotation: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'Annotation ID' }, + { name: 'uid', label: 'Unique Identifier' }, { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -374,8 +425,9 @@ hint: 'Allowed values are: true, false' } }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' } + { name: 'uid' }, + { name: 'label' }, + { name: 'color' } ] } ] end @@ -387,7 +439,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -406,12 +458,12 @@ render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' }, { name: 'email' } ] }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' } ] }, { name: 'deleted', type: 'boolean', @@ -434,7 +486,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -448,27 +500,35 @@ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, { name: 'title' }, - { name: 'url', label: 'URL' }, + { name: 'url' }, { name: 'created_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' }, { name: 'email' } ] }, - { name: 'deleted', type: 'boolean' } + { name: 'deleted', type: 'boolean', control_type: 'checkbox', + toggle_field: { + name: 'deleted', + label: 'Deleted', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } ] end }, field_report: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Field Report ID' }, + fields: lambda do |_connection, config_fields| + standard_fields = [ + { name: 'uid', label: 'File report ID' }, { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -483,27 +543,23 @@ } }, { name: 'title' }, { name: 'description' }, - { name: 'report_date', label: 'Report Date', type: 'date_time', + { name: 'report_date', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, - { name: 'status' }, - { name: 'field_report_type', label: 'Field Report Type', type: 'object', properties: [ + { name: 'field_report_type', type: 'object', properties: [ { name: 'name' }, + { name: 'project_uid' }, { name: 'status' }, - { name: 'uid', label: 'UID' } + { name: 'uid' } ] }, - { name: 'pdf_url', label: 'PDF URL' }, - { name: 'pdf_form_values', label: 'PDF Form Values', type: 'array', of: 'object', - properties: [ - { name: 'name' }, - { name: 'value' } - ] }, - { name: 'pg_form_values', label: 'Daily Report Values', type: 'array', of: 'object', properties: [ - { name: 'pg_worklog_entries', label: 'Work Log Entries', type: 'array', of: 'object', + { name: 'pdf_url' }, + { name: 'pg_form_values', type: 'array', of: 'object', properties: [ + { name: 'pg_equipment_entries', type: 'array', of: 'object', properties: [ - { name: 'trade' }, + { name: 'uid' }, { name: 'timespan' }, - { name: 'headcount', type: 'integer' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, { name: 'description' }, { name: 'deleted', type: 'boolean', control_type: 'checkbox', @@ -517,19 +573,21 @@ hint: 'Allowed values are: true, false' } } ] }, - { name: 'pg_materials_entries', label: 'Material Entries', type: 'array', of: 'object', + { name: 'pg_materials_entries', type: 'array', of: 'object', properties: [ + { name: 'uid' }, { name: 'unit', type: 'integer' }, { name: 'quantity', type: 'integer' }, { name: 'item' }, { name: 'description' }, { name: 'deleted' } ] }, - { name: 'pg_equipment_entries', label: 'Equipment Entries', type: 'array', of: 'object', + { name: 'pg_worklog_entries', type: 'array', of: 'object', properties: [ + { name: 'uid' }, + { name: 'trade' }, { name: 'timespan' }, - { name: 'quantity', type: 'integer' }, - { name: 'item' }, + { name: 'headcount', type: 'integer' }, { name: 'description' }, { name: 'deleted', type: 'boolean', control_type: 'checkbox', @@ -544,23 +602,26 @@ } } ] } ] }, - { name: 'attachments', label: 'Documents', type: 'object', properties: [ + { name: 'attachments', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, + { name: 'created_by', type: 'object', properties: [ + { name: 'email' }, + { name: 'uid' }, + { name: 'url' } + ] }, { name: 'photos', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'report_date', type: 'date' }, { name: 'snapshots', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'created_by', type: 'object', properties: [ - { name: 'email' }, - { name: 'uid', label: 'UID' }, - { name: 'url' } - ] }, + { name: 'status' }, { name: 'updated_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, @@ -578,6 +639,13 @@ { name: 'wind_speed', type: 'number' } ] } ] + pdf_form_fileds = get("/projects/#{config_fields['project_uid']}/" \ + 'field_reports').params(limit: 1)&. + map do |key, _value| + { name: key } + end&.inject(:merge) + standard_fields.merge({ 'pdf_form_values' => + call('format_schema_field_names', pdf_form_fileds) }) end }, rfi: { @@ -587,7 +655,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -602,7 +670,7 @@ } }, { name: 'number', type: 'integer' }, { name: 'status', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'label' }, { name: 'color' } ] }, @@ -629,9 +697,12 @@ { name: 'due_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, + { name: 'assigned_to_uids', + hint: 'Array of unique identifiers of users who ' \ + 'are RFI assignees.' }, { name: 'assigned_to', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' }, { name: 'email' } ] }, @@ -643,7 +714,7 @@ "timestamps-and-timezones' target='_blank'>Timestamps and " \ 'Timezones for accepted date formats' }, { name: 'updated_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' }, { name: 'email' } ] }, @@ -651,7 +722,7 @@ render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' }, { name: 'email' } ] }, @@ -677,7 +748,7 @@ rfi_status: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'Status ID' }, + { name: 'uid', label: 'RFI status ID' }, { name: 'label' }, { name: 'color' } ] @@ -687,31 +758,15 @@ fields: lambda do |_connection, _config_fields| [ { name: 'uid', label: 'User ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, { name: 'email' }, - { name: 'first_name', label: 'First Name' }, - { name: 'last_name', label: 'Last Name' }, - { name: 'language'}, + { name: 'first_name' }, + { name: 'last_name' }, + { name: 'language' }, { name: 'role', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' } ] }, - { name: 'removed', label: 'Removed?' } + { name: 'removed' } ] end }, @@ -719,29 +774,13 @@ fields: lambda do |_connection, _config_fields| [ { name: 'uid', label: 'Sheet ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, { name: 'name' }, - { name: 'version_name', label: 'Version Name' }, + { name: 'version_name' }, { name: 'description' }, - { name: 'tags', type: 'array', of: 'string', hint: 'An array of strings representing the' \ + { name: 'tags', hint: 'An array of strings representing the' \ ' tags added to this sheet.' }, { name: 'published_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' }, { name: 'email' } ] }, @@ -760,36 +799,20 @@ toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'uploaded_file_name', label: 'Uploaded file name' } + { name: 'uploaded_file_name' } ] end }, sheet_packet: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'Sheet Packet ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'status' }, - { name: 'file_url', label: 'File URL' }, + { name: 'uid', label: 'Sheet packet ID' }, + { name: 'file_url' }, { name: 'resource', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + { name: 'uid' }, { name: 'url' } - ] } + ] }, + { name: 'status' } ] end }, @@ -946,7 +969,7 @@ create_project: { title: 'Create project', description: 'Create project in'\ - ' PlanGrid', + ' Plangrid', help: { body: 'Create project action uses the' \ " project in'\ - ' PlanGrid', + ' Plangrid', help: { body: 'Update project action uses the' \ " Update Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-project', - learn_more_text: 'Update Project' + learn_more_text: 'Update a Project' }, input_fields: lambda do |object_definitions| object_definitions['project'].required('uid'). ignored('updated_at', 'latitude', 'longitude', 'organization_id') end, execute: lambda do |_connection, input| - payload = input.each do |key, value| - input[key].present? || input[key] = nil - end - patch("/projects/#{input.delete('uid')}").payload(payload.except('uid')). + patch("/projects/#{input.delete('uid')}").payload(input). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end @@ -1020,11 +1025,11 @@ end }, get_project_details: { - title: 'Get project', - description: 'Get project'\ - ' in PlanGrid', + title: 'Get project info. by ID', + description: 'Get project info.'\ + ' by ID in Plangrid', help: { - body: 'Get project action uses the' \ + body: 'Get project info. by ID action uses the' \ " Retrieve a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-a-project', @@ -1045,8 +1050,8 @@ }, upload_document: { title: 'Upload document to a project', - description: 'Upload document to a'\ - ' PlanGrid project', + description: 'Upload document to a project'\ + ' in Plangrid', help: { body: 'Upload document to a project action uses the' \ " document in a'\ - ' PlanGrid project', - help: { - body: 'Update document in a project action uses the' \ - " Update Document to Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/update-attachment-' \ - 'in-a-project', - learn_more_text: 'Update Document in a Project API' - }, - summarize_input: %w[file_content], - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'attachment_uid', label: 'Document ID', optional: false }, - { name: 'name', label: 'Document Name', - hint: 'New name of the document', sticky: true }, - { name: 'folder', label: 'Folder', - hint: 'New folder of the document', sticky: true } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - patch("/projects/#{project_uid}/attachments/" \ - "#{input.delete('attachment_uid')}"). - headers('Content-type': 'application/json'). - payload(input). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['document'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/attachments")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end + }, create_rfi: { title: 'Create RFI in a project', description: 'Create RFI in'\ - ' a PlanGrid project ', + ' a Plangrid project ', help: { - body: 'Create RFI in a project action uses the ' \ + body: 'Create RFI in project action uses the ' \ "Create RFI in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-rfi-' \ @@ -1273,11 +1228,11 @@ update_rfi: { title: 'Update RFI in a project', description: 'Update RFI in'\ - ' a PlanGrid project', + ' a Plangrid project', help: { - body: 'Update RFI in a project action uses the ' \ + body: 'Update RFI in Project action uses the ' \ "Update RFI in a Project API.", + "project' target='_blank'>patchUpdate RFI in a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-' \ 'rfi-in-a-project', learn_more_text: 'Update RFI in a Project' @@ -1300,7 +1255,8 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'status', label: 'Status UID' } + { name: 'status', label: 'Status', + hint: 'Use this for create and update rfi status' } ].concat(object_definitions['rfi']. only('uid', 'locked', 'title', 'question', 'answer', 'sent_at', 'due_at', 'assigned_to_uids'). @@ -1331,10 +1287,10 @@ }, get_rfi_in_project: { title: 'Get RFI in a project', - description: 'Get RFI in '\ - 'a PlanGrid project', + description: 'Get RFI by ID in'\ + ' Plangrid project', help: { - body: 'Get RFI in a project action uses the' \ + body: 'Get RFI by ID in a project action uses the' \ " Retrieve RFI in a Project API.", @@ -1343,29 +1299,12 @@ learn_more_text: 'Retrieve RFI in a Project' }, input_fields: lambda do |object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'rfi_uid', label: 'RFI ID', optional: false } - ] + object_definitions['rfi'].only('project_uid', 'uid'). + required('project_uid', 'uid') end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') - get("/projects/#{project_uid}/rfis/#{input['rfi_uid']}")&. + get("/projects/#{project_uid}/rfis/#{input['uid']}")&. merge('project_uid' => project_uid) end, output_fields: lambda do |object_definitions| @@ -1380,11 +1319,11 @@ create_task: { title: 'Create task in a project', description: 'Create task in'\ - ' a PlanGrid project', + ' Plangrid project', help: { - body: 'Create task in a project action uses the ' \ + body: 'Create task in Project action uses the ' \ "Create Task in Project API.", + "project' target='_blank'>Create task in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-task-in-' \ 'a-project', learn_more_text: 'Create Task in a Project' @@ -1406,15 +1345,12 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } - }, - { name: 'issue_list_uid', label: 'Task List ID', sticky: true } + } } ].concat(object_definitions['task']. - only('title', 'status', 'type', 'assigned_to_uids', - 'room', 'start_date', 'due_at', - 'description', 'has_cost_impact', 'cost_impact', - 'has_schedule_impact', 'schedule_impact' - )) + only('assigned_to_uids', 'cost_impact', 'description', 'due_at', + 'has_cost_impact', 'has_schedule_impact', + 'issue_list_uid', 'room', 'schedule_impact', 'start_date', + 'status', 'title', 'type')) end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') @@ -1440,13 +1376,13 @@ end }, update_task: { - title: 'Update task in a project', + title: 'Update task in a Project', description: 'Update task in'\ - ' a PlanGrid project', + ' Plangrid project', help: { - body: 'Update task in a project action uses the ' \ + body: 'Update task in Project action uses the ' \ "Update Task in Project API.", + "project' target='_blank'>Create task in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-project', learn_more_text: 'Update Task in a Project' }, @@ -1467,24 +1403,17 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g.' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } - }, - { name: 'issue_uid', label: 'Task ID', optional: false }, - { name: 'issue_list_uid', label: 'Task List ID', sticky: true } + } } ].concat(object_definitions['task']. - only('title', 'status', 'type', 'assigned_to_uids', - 'room', 'start_date', 'due_at', - 'description', 'has_cost_impact', 'cost_impact', - 'has_schedule_impact', 'schedule_impact' - )) + only('uid', 'assigned_to_uids', 'cost_impact', 'description', + 'due_at', 'has_cost_impact', 'has_schedule_impact', + 'issue_list_uid', 'room', 'schedule_impact', 'start_date', + 'status', 'title', 'type').required('uid')) end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') - payload = input.each do |key, value| - input[key].present? || input[key] = nil - end patch("/projects/#{project_uid}/issues/" \ - "#{input.delete('issue_uid')}").payload(payload). + "#{input.delete('uid')}").payload(input). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end&.merge('project_uid' => project_uid) @@ -1501,7 +1430,7 @@ get_task: { title: 'Get task in a project', description: 'Get task in'\ - ' a PlanGrid project', + ' in a Plangrid project', help: { body: 'Get task in a project action uses the ' \ "user to'\ - ' a PlanGrid project', + ' project team Plangrid', help: { body: 'Invite user to a project action uses the ' \ "Invite User in Project API.", + "project-team' target='_blank'>Invite user in Project team API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ 'invite-user-to-project-team', - learn_more_text: 'Invite User to Project' + learn_more_text: 'Invite User to Project Team' }, input_fields: lambda do |_object_definitions| [ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1579,17 +1508,16 @@ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, { name: 'email', optional: false }, - { name: 'role_uid', label: 'Role ID', sticky: true, + { name: 'role_uid', label: 'Role ID', hint: 'Unique identifier of role to assign user on project team' } ] end, execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - post("/projects/#{project_uid}/users/invites"). + post("/projects/#{input.delete('project_uid')}/users/invites"). payload(input). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) + end end, output_fields: lambda do |object_definitions| object_definitions['user'] @@ -1599,17 +1527,17 @@ get("/projects/#{id}/users")&.dig('data', 0) || {} end }, - get_user_in_project: { - title: 'Get user in project', + get_user_by_id: { + title: 'Get user in a project', description: 'Get user in'\ - ' a PlanGrid project', + ' Plangrid project', help: { - body: 'Get user in a project action uses the ' \ + body: 'Get user in project action uses the ' \ "Retrieve User in a Project.", + "project-team' target='_blank'>Retrieve User on a Project Team.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ 'users-on-a-project-team', - learn_more_text: 'Retrieve User in a Project' + learn_more_text: 'Retrieve User on a Project Team' }, input_fields: lambda do |_object_definitions| [ @@ -1648,7 +1576,7 @@ get_snapshot_in_project: { title: 'Get snapshot in a project', description: 'Get snapshot in'\ - ' a PlanGrid project', + ' a Plangrid project', help: { body: 'Get snapshot in a project action uses the ' \ " input['project_uid']) + "#{input['snapshot_uid']}") end, output_fields: lambda do |object_definitions| object_definitions['snapshot'] @@ -1693,10 +1621,10 @@ }, get_rfi_statuses_in_project: { title: 'Get RFI statuses in project', - description: 'Get RFI statuses in'\ - ' a PlanGrid project', + description: 'Get rfi statuses in'\ + ' Plangrid project', help: { - body: 'Get RFI statuses in project action uses the ' \ + body: 'Get rfi statuses in project action uses the ' \ "Retrieve RFI Statuses in a Project.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ @@ -1744,23 +1672,23 @@ end }, get_roles_on_project: { - title: 'Get roles in a project', - description: 'Get roles in '\ - ' a PlanGrid project', + title: 'Get roles on a project', + description: 'Get roles on '\ + ' Plangrid project', help: { - body: 'Get roles in a project action uses the ' \ - "Retrieve Roles on a Project API.", + body: 'Get role on a project action uses the ' \ + "Retrieve Role on a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-roles-on-a-project', - learn_more_text: 'Retrieves Role on a Project' + 'retrieve-role-on-a-project', + learn_more_text: 'Retrieve Role on a Project' }, input_fields: lambda do |_object_definitions| [ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1772,19 +1700,24 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } } + } }, + { name: 'limit', type: 'integer', + hint: 'Number of roles to retrieve. Maximum value of 50.' }, + { name: 'skip', type: 'integer', + hint: 'Number of roles to skip in the set of results.' } ] end, execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - { roles: get("/projects/#{project_uid}/roles")['data'] } + { roles: get("/projects/#{input.delete('project_uid')}/roles", input) } end, output_fields: lambda do |_object_definitions| [ - { name: 'roles', label: 'Roles', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'label', label: 'Role' } - ] } + { name: 'roles', type: 'array', of: 'object', properties: [ + { name: 'uid' }, + { name: 'label' } + ] }, + { name: 'total_count' }, + { name: 'next_page_url' } ] end, sample_output: lambda do |_connection, _input| @@ -1792,15 +1725,69 @@ 'label' => 'Admin' } } end }, - + get_sheets_in_project: { + title: 'Get sheets in a project', + description: 'Get sheets in'\ + ' Plangrid project', + help: { + body: 'Get sheets in project action uses the ' \ + "Retrieve Sheets in a Project.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-sheets-in-a-project', + learn_more_text: 'Retrieve Sheets in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'limit', type: 'integer', + hint: 'Number of sheets to retrieve. Maximum value of 50.' }, + { name: 'skip', type: 'integer', + hint: 'Number of sheets to skip in the set of results' }, + { name: 'updated_after', type: 'date_time', + hint: 'Only retrieve sheets created/updated after ' \ + 'specified UTC date and time.' } + ] + end, + execute: lambda do |_connection, input| + { sheets: get("/projects/#{input.delete('project_uid')}/sheets", + input)['data'] } + end, + output_fields: lambda do |object_definitions| + [{ name: 'sheets', type: 'array', of: 'object', + properties: object_definitions['sheet'] }] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + { + sheets: get("/projects/#{id}/sheets?limit=1")&.dig('data', 0)&. + merge('project_uid' => id) || {} + } + end + }, get_sheet_in_project: { - title: 'Get sheet in a project', - description: 'Get sheet in '\ - 'a PlanGrid project', + title: 'Get sheet by ID in project', + description: 'Get sheet in'\ + ' Plangrid project', help: { - body: 'Get sheet in a project action uses the ' \ + body: 'Get project sheet details action uses the ' \ "Retrieve Sheet in a Project.", + " target='_blank'>Retrieve Sheets in a Project.", learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-a-sheet', learn_more_text: 'Retrieve Sheet in a Project' @@ -1810,7 +1797,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1823,12 +1810,11 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'sheet_uid', label: 'Sheet ID', optional: false } + { name: 'sheet_uid', type: 'Sheet ID', optional: false } ] end, execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/sheets/#{input['sheet_uid']}")&. - merge('project_uid' => input['project_uid']) + get("/projects/#{input['project_uid']}/sheets/#{input['sheet_uid']}") end, output_fields: lambda do |object_definitions| object_definitions['sheet'] @@ -1840,11 +1826,11 @@ end }, get_project_sheet_packet: { - title: 'Get sheet packet in a project', - description: 'Get sheet packet in'\ - ' a PlanGrid project', + title: 'Get project sheet packet', + description: 'Get project sheet packet in'\ + ' packet in Plangrid', help: { - body: 'Get sheet packet in a project action uses the ' \ + body: 'Get project sheet packet action uses the ' \ "Retrieve Sheet Packet API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -1869,23 +1855,23 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'packet_uid', label: 'Sheet Packet ID', optional: false } + { name: 'packet_uid', type: 'Packet ID' } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/sheets/packets/" \ - "#{input['packet_uid']}")&.merge('project_uid' => input['project_uid']) + "#{input['packet_uid']}") end, output_fields: lambda do |object_definitions| object_definitions['sheet_packet'] end }, get_field_reports_in_project: { - title: 'Get field reports in a project', + title: 'Get fields reports in project', description: 'Get field reports in'\ - ' a PlanGrid project', + ' in Plangrid project', help: { - body: 'Get field reports in a project action uses the ' \ + body: 'Get fields reports in project action uses the ' \ "Retrieve Field Reports in a" \ ' Project API.', @@ -1898,7 +1884,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project ID', + label: 'Project', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1911,17 +1897,17 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'report_date_min', type: 'date', - label: 'Report Start Date', + { name: 'updated_after', type: 'date_time', + hint: 'Only retrieve field reports created/updated after ' \ + 'specified UTC date and time.' }, + { name: 'report_date_min', type: 'date_time', + label: 'Report start date', hint: 'Only retrieve field reports between a date range ' \ 'starting with this date in UTC format.' }, - { name: 'report_date_max', type: 'date', - label: 'Report End Date', + { name: 'report_date_max', type: 'date_time', + label: 'Report end date', hint: 'Only retrieve field reports between a date range ' \ 'starting with this date in UTC format.' }, - { name: 'updated_after', label: 'Updated After', type: 'date_time', - hint: 'Only retrieve field reports created/updated after ' \ - 'specified UTC date and time.' }, { name: 'sort_by', control_type: 'select', pick_list: %w[report_date updated_at]&.map { |e| [e.labelize, e] }, @@ -1929,14 +1915,6 @@ toggle_field: { name: 'sort_by', type: 'string', control_type: 'text', hint: 'Allowed values report_date or updated_at' - } }, - { name: 'sort_order', control_type: 'select', - pick_list: - %w[asc desc]&.map { |e| [e.labelize, e] }, - toggle_hint: 'Select sort order', - toggle_field: { - name: 'sort_by', type: 'string', control_type: 'text', - hint: 'Allowed values asc or desc' } } ] end, @@ -1944,17 +1922,17 @@ project_uid = input.delete('project_uid') query_params = '' input&.map do |key, val| - if %w[updated_after].include?(key) - query_params = query_params + "&" + "#{key}=#{val.to_time.utc.iso8601}" + if %w[updated_after report_date_min report_date_max].include?(key) + query_params = query_params + "#{key}=#{val.to_time.utc.iso8601}" else - query_params = query_params + "&" + "#{key}=#{val}" + query_params = query_params + "#{key}=#{val}" end end { field_reports: get("/projects/#{project_uid}/field_reports?" \ "#{query_params}")['data'] } end, output_fields: lambda do |object_definitions| - { name: 'field_reports', label: 'Field Reports', type: 'array', of: 'object', + { name: 'field_reports', type: 'array', of: 'object', properties: object_definitions['field_report'] } end, sample_output: lambda do |_connection, _input| @@ -1965,9 +1943,9 @@ end }, upload_photo: { - title: 'Upload photo to a project', + title: 'Upload photo to project', description: 'Upload photo to '\ - ' a PlanGrid project', + ' project in Plangrid', help: { body: 'Upload photo to a project action uses the' \ " project_uid) + end end, output_fields: lambda do |object_definitions| object_definitions['photo'] @@ -2046,16 +2022,16 @@ end }, update_photo_metadata: { - title: 'Update photo in a project', - description: 'Update photo in'\ - ' a PlanGrid project', + title: 'Update photo metadata', + description: 'Update photo metadata to '\ + ' Project in Plangrid', help: { - body: 'Update photo action uses the' \ + body: 'Update photo metadata action uses the' \ " Update Photo in a Project API.", + "project' target='_blank'>Update Document to Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-photo-' \ 'in-a-project', - learn_more_text: 'Update Photo in a Project API' + learn_more_text: 'Update photo to Project API' }, summarize_input: %w[file_content], input_fields: lambda do |_object_definitions| @@ -2072,20 +2048,19 @@ toggle_hint: 'Use project ID', hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'photo_uid', label: 'Photo ID', optional: false }, + { name: 'photo_uid', type: 'Photo ID', optional: false }, { name: 'title', label: 'Photo title', - hint: 'New title of the photo', sticky: true } + hint: 'New title of the photo' } ] end, execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - patch("/projects/#{project_uid}/photos/" \ + patch("/projects/#{input.delete('project_uid')}/photos/" \ "#{input.delete('photo_uid')}"). headers('Content-type': 'application/json'). payload(input). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) + end end, output_fields: lambda do |object_definitions| object_definitions['photo'] @@ -2096,12 +2071,12 @@ merge('project_uid' => id) || {} end }, - get_photo_details: { - title: 'Get photo in a project', + get_photo_by_id: { + title: 'Get photo in a Project', description: 'Get photo in'\ - ' a PlanGrid project', + ' a Plangrid project', help: { - body: 'Get photo action uses the ' \ + body: 'Get photo details action uses the ' \ "Retrieve Photo in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -2126,12 +2101,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'photo_uid', label: 'Photo ID', optional: false } + { name: 'photo_uid', type: 'Photo ID', optional: false } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/photos/" \ - "#{input['photo_uid']}")&.merge('project_uid' => input.delete('project_uid')) + "#{input['photo_uid']}") end, output_fields: lambda do |object_definitions| object_definitions['photo'] @@ -2142,12 +2117,12 @@ merge('project_uid' => id) || {} end }, - get_document_details: { + get_document_by_id: { title: 'Get document in a project', - description: 'Get document'\ - ' in a PlanGrid project', + description: 'Get document in'\ + ' in Plangrid project', help: { - body: 'Get document in a project action uses the ' \ + body: 'Get document details action uses the ' \ "Retrieve Document in a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -2172,12 +2147,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'attachment_uid', label: 'Document ID', optional: false } + { name: 'attachment_uid', type: 'Document ID', optional: false } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/attachments/" \ - "#{input['attachment_uid']}")&.merge('project_uid' => input.delete('project_uid')) + "#{input['attachment_uid']}") end, output_fields: lambda do |object_definitions| object_definitions['document'] @@ -2187,654 +2162,104 @@ get("/projects/#{id}/attachments")&.dig('data', 0)&. merge('project_uid' => id) || {} end - }, - create_sheet_packet: { - title: 'Create sheet packet in a project', - description: 'Create sheet packet in '\ - ' a PlanGrid project', + } + }, + triggers: { + new_updated_project: { + title: 'New/updated project', + description: 'New/updated project in'\ + ' Plangrid', help: { - body: 'Create sheet packet in a project action uses the' \ - " Create Sheet Packet in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/upload-photo' \ - '-to-project', - learn_more_text: 'Create Sheet Packet in a Project' + body: 'New/updated project trigger uses the' \ + " List all Projects API.", + learn_more_url: 'https://developer.plangrid.com/docs/list-all-projects', + learn_more_text: 'List All Projects API' }, - input_fields: lambda do |object_definitions| + input_fields: lambda do |_object_definitions| [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'sheet_uids', label: 'Sheet IDs', optional: false, - type: 'string', - hint: 'A comma separated list of sheet IDs.' }, - { name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'include_annotations', - label: 'Include annotations?', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } ] end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - payload = { - sheet_uids: input.delete('sheet_uids').split(','), - include_annotations: input.delete('include_annotations') + poll: lambda do |_connection, input, closure| + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 20 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get('/projects'). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'updated_after' => now.to_time.utc.iso8601 } + end + { + events: response['data'] || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? } - post("/projects/#{project_uid}/sheets/packets").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) + end, + dedup: lambda do |project| + "#{project['uid']}@#{project['updated_at']}" end, output_fields: lambda do |object_definitions| - object_definitions['sheet_packet'] + object_definitions['project'] end, sample_output: lambda do |_connection, _input| - { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - file_url: "https://packet-assets.plangrid.com/92cf7193-af0c-42fc-a3ab-7ef5149da720.pdf", - resource: { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/packets/92cf7193-af0c-42fc-a3ab-7ef5149da720" - }, - status: "incomplete" - } + get('/projects')&.dig('data', 0) || {} end }, - get_task_list: { - title: 'Get task list in a project', - description: 'Get task list'\ - ' in a PlanGrid project', + new_updated_documents: { + title: 'New/updated documents in a project', + description: 'New/updated document in '\ + 'Project Plangrid', help: { - body: 'Get task list in a project action uses the ' \ - "Retrieve Task List in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-issue-list', - learn_more_text: 'Retrieve Task List in a Project API' + body: 'New/updated documents in Project trigger uses the' \ + " Retrieve Documents in a Project" \ + ' API.', + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'attachments-in-a-project', + learn_more_text: 'Retrieve Documents in a Project' }, input_fields: lambda do |_object_definitions| [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', + { name: 'project_uid', optional: false, label: 'Project', - optional: false, + control_type: 'select', pick_list: 'project_list', toggle_hint: 'Select project', toggle_field: { name: 'project_uid', + label: 'Project ID', type: 'string', control_type: 'text', - optional: false, - label: 'Project ID', toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'issue_list_uid', label: 'Task List ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/issue_lists/" \ - "#{input['issue_list_uid']}") - end, - output_fields: lambda do |object_definitions| - [ - { - name: "uid", label: "Task List ID" - }, - { - name: "project_uid", label: "Project ID" - }, - { - name: "name", label: "Name" - }, { - name: "deleted", label: "Deleted", type: "boolean" - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", - name: "QA/QC", - deleted: false, - project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" - } - end - }, - update_task_list: { - title: 'Update task list in a project', - description: 'Update task list'\ - ' in a PlanGrid project', - help: { - body: 'Update task list in a project action uses the ' \ - "Update Task List in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'update-issue-list', - learn_more_text: 'Update Task List in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'issue_list_uid', label: 'Task List ID', optional: false }, - { name: 'name', optional: false } - ] - end, - execute: lambda do |_connection, input| - patch("/projects/#{input['project_uid']}/issue_lists/" \ - "#{input['issue_list_uid']}").payload({name: input.delete('name')}) - end, - output_fields: lambda do |object_definitions| - [ - { - name: "uid", label: "Task List ID" - }, - { - name: "project_uid", label: "Project ID" - }, - { - name: "name", label: "Name" - }, - { - name: "deleted", label: "Deleted", type: "boolean" - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", - name: "QA/QC", - deleted: false, - project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" - } - end - }, - create_task_list: { - title: 'Create task list in a project', - description: 'Create task list'\ - ' in a PlanGrid project', - help: { - body: 'Create task list in a project action uses the ' \ - "Create Task List in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'create-issue-list', - learn_more_text: 'Create Task List in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'name', optional: false } - ] - end, - execute: lambda do |_connection, input| - post("/projects/#{input.delete('project_uid')}/issue_lists").payload(input) - end, - output_fields: lambda do |object_definitions| - [ - { - name: "uid", label: "Task List ID" - }, - { - name: "project_uid", label: "Project ID" - }, - { - name: "name", label: "Name" - }, - { - name: "deleted", label: "Deleted", type: "boolean" - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", - name: "QA/QC", - deleted: false, - project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" - } - end - }, - create_sheet_version: { - title: 'Create sheet version upload in a project', - description: 'Create sheet version upload'\ - ' in a PlanGrid project', - help: { - body: 'Create sheet version in a project action uses the ' \ - "Upload Version to a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'upload-version-to-project', - learn_more_text: 'Upload Version to a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, - { name: 'version_name', label: 'Version Name', optional: false } - ] - end, - execute: lambda do |_connection, input| - post("/projects/#{input.delete('project_uid')}/sheets/uploads").payload(input) - end, - output_fields: lambda do |object_definitions| - [ - { - name: 'uid', label: 'Sheet Version Upload ID' - }, - { - name: 'complete_url', label: 'Upload Completion URL' - }, - { - name: 'status', - }, - { - name: 'file_upload_requests', label: 'File Upload Requests', - type: 'array', of: 'object', properties: [ - { - name: 'uid', label: 'File Upload ID' - }, - { - name: 'upload_status', label: 'File Upload Status' - }, - { - name: 'url', label: 'File Upload URL' - } - ] - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - complete_url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720", - status: "incomplete", - file_upload_requests: [ - { - uid: "b278fcba-72f0-4161-bfdc-89d5bde4d5e7", - upload_status: "issued", - url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720/files/b278fcba-72f0-4161-bfdc-89d5bde4d5e7" - }, - { - uid: "727fca7d-385b-4476-b257-4b96c00e879b", - upload_status: "issued", - url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720/files/727fca7d-385b-4476-b257-4b96c00e879b" - } - ] - } - end - }, - upload_file_to_sheet_version: { - title: 'Upload file to sheet version in a project', - description: 'Upload file to sheet version'\ - ' in a PlanGrid project', - help: { - body: 'Upload file to sheet version in a project action uses the ' \ - "Upload File to Version in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'upload-file-to-version', - learn_more_text: 'Upload File to Version in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false }, - { name: 'file_upload_request_uid', label: 'File Upload ID', optional: false }, - { name: 'file_name', label: 'File Name', optional: false }, - { name: 'file_content', label: 'File Content', optional: false } - ] - end, - execute: lambda do |_connection, input| - file_content = input.delete('file_content') - project_uid = input.delete('project_uid') - file_upload_info = post("/projects/#{project_uid}/sheets/" \ - "uploads/#{input.delete('ver_upload_uid')}/" \ - "files/#{input.delete('file_upload_request_uid')}"). - headers('Content-Type': 'application/json'). - payload({file_name: input.delete('file_name')}) - url = file_upload_info&.dig('aws_post_form_arguments', 'action') - fields = file_upload_info&.dig('aws_post_form_arguments', 'fields') - # webhook_url = file_upload_info. - # dig('aws_post_form_arguments', 'webhook_url') - headers = fields.map { |o| { o['name'] => o['value'] } }.inject(:merge) - status = - post(url). - payload(key: headers['key'], - policy: headers['policy'], - signature: headers['signature'], - AWSAccessKeyId: headers['AWSAccessKeyId'], - 'content-type': headers['Content-Type'], - 'success_action_redirect': headers['success_action_redirect'], - 'x-amz-server-side-encryption': - headers['x-amz-server-side-encryption'], - 'x-amz-storage-class': headers['x-amz-storage-class'], - file: file_content). - request_format_multipart_form. - after_response do |_code, response, _response_headers| - response - end - end, - output_fields: lambda do |object_definitions| - - end, - sample_output: lambda do |_connection, _input| - - end - }, - complete_version_upload: { - title: 'Complete sheet version upload to a project', - description: 'Complete sheet version upload '\ - ' to a PlanGrid project', - help: { - body: 'Complete sheet version upload to a project action uses the ' \ - "Complete Version Upload in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'complete-version-upload-to-project', - learn_more_text: 'Complete Version Upload in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - post("/projects/#{project_uid}/sheets/" \ - "uploads/#{input.delete('ver_upload_uid')}/completions")&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - [ - { - name: 'uid', label: 'Sheet Version ID' - }, - { - name: 'status', label: 'Status' - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - complete_url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720", - status: "complete" - } - end - } - }, - triggers: { - new_updated_project: { - title: 'New or updated project', - description: 'New or updated project in'\ - ' PlanGrid', - help: { - body: 'New or updated project trigger uses the' \ - " List All Projects API.", - learn_more_url: 'https://developer.plangrid.com/docs/list-all-projects', - learn_more_text: 'List All Projects API' - }, - input_fields: lambda do |_object_definitions| - [ - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] - end, - poll: lambda do |_connection, input, closure| - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 20 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get('/projects'). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'updated_after' => now.to_time.utc.iso8601 } - end - { - events: response['data'] || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? - } - end, - dedup: lambda do |project| - "#{project['uid']}@#{project['updated_at']}" - end, - output_fields: lambda do |object_definitions| - object_definitions['project'] - end, - sample_output: lambda do |_connection, _input| - get('/projects')&.dig('data', 0) || {} - end - }, - new_updated_sheets: { - title: 'New or updated sheet in a project', - description: 'New or updated sheet in '\ - 'a PlanGrid project', - help: { - body: 'New or updated sheet in a project trigger uses the' \ - " Retrieve Sheets in a Project" \ - ' API.', - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'sheets-in-a-project', - learn_more_text: 'Retrieve Sheets in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] - end, - poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 5 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get("/projects/#{project_uid}/sheets"). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'project_uid' => project_uid, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } - end - sheets = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } - { - events: sheets || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? - } - end, - dedup: lambda do |sheet| - "#{sheet['uid']}@#{sheet['created_at']}" - end, - output_fields: lambda do |object_definitions| - object_definitions['sheet'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/sheets")&.dig('data', 0) || {} - end - }, - new_updated_documents: { - title: 'New or updated document in a project', - description: 'New or updated document in '\ - 'a PlanGrid project', - help: { - body: 'New or updated document in a project trigger uses the' \ - " Retrieve Documents in a Project" \ - ' API.', - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'attachments-in-a-project', - learn_more_text: 'Retrieve Documents in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' } ] end, @@ -2881,11 +2306,11 @@ end }, new_updated_task: { - title: 'New or updated task in a project', - description: 'New or updated task in a '\ - ' PlanGrid project', + title: 'New/updated task in a Project', + description: 'New/updated task in a '\ + 'Project Plangrid', help: { - body: 'New or updated task in a project trigger uses the' \ + body: 'New/updated task in a Project trigger uses the' \ " Retrieve Tasks " \ ' in a Project API.', @@ -2964,14 +2389,14 @@ end }, new_updated_annotations: { - title: 'New or updated annotation in a project', - description: 'New or updated annotation '\ - 'in a PlanGrid project', + title: 'New/updated annotations in Project', + description: 'New/updated annotations '\ + 'in Project Plangrid', help: { - body: 'New or updated annotation in project trigger uses the' \ + body: 'New/updated annotations in Project trigger uses the' \ " Retrieve " \ - ' Annotations in a Project API.', + ' annotations in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-annotations-in-a-project', learn_more_text: 'Retrieve Annotations in a Project' @@ -3046,17 +2471,17 @@ end }, new_updated_photos: { - title: 'New or updated photo in a project', - description: 'New or updated photo '\ - 'in a PlanGrid project', + title: 'New/updated photos in Project', + description: 'New/updated photos '\ + 'in Plangrid Project', help: { - body: 'New or updated photo in a project trigger uses the' \ + body: 'New/updated photos in Project trigger uses the' \ " Retrieve " \ ' photos in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-photos-in-a-project', - learn_more_text: 'Retrieve Photos in a Project' + learn_more_text: 'Retrieve photos in a Project' }, input_fields: lambda do |_object_definitions| [ @@ -3128,16 +2553,16 @@ end }, new_updated_snapshot: { - title: 'New or updated snapshot in a project', - description: 'New or updated snapshot '\ - 'in a PlanGrid project', + title: 'New/updated snapshot in a Project', + description: 'New/updated snapshot '\ + 'in a Project Plangrid', help: { - body: 'New or updated snapshot in a project trigger uses the' \ + body: 'New/updated snapshot in a Project trigger uses the' \ " Retrieve " \ + "remove-snapshot-reference-in-rfi' target='_blank'>Retrieve " \ ' Snapshots in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-snapshots-in-a-project', + 'remove-snapshot-reference-in-rfi', learn_more_text: 'Retrieve Snapshots in a Project' }, input_fields: lambda do |_object_definitions| @@ -3210,17 +2635,17 @@ end }, new_updated_field_report: { - title: 'New or updated field report in a project', - description: 'New or updated field report '\ - 'in a PlanGrid project', + title: 'New/updated field report in a Project', + description: 'New/updated field report '\ + 'in Plangrid Project', help: { - body: 'New or updated field report in a project trigger uses the' \ + body: 'New/updated field report in Project trigger uses the' \ " Retrieve " \ - 'Field Reports in a Project API.', + 'field reports in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-field-reports-in-a-project', - learn_more_text: 'Retrieve Field Reports in a Project' + learn_more_text: 'Retrieve field reports in a Project' }, input_fields: lambda do |_object_definitions| [ @@ -3273,8 +2698,14 @@ 'project_uid' => project_uid, 'updated_after' => now.to_time.utc.iso8601 } end - field_reports = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } + results = response['data']&. + map do |field_report| + field_report.merge({ 'pdf_form_fileds' => + field_report.delete('pdf_form_fileds')&. + map { |a| { a[0] => a[1] } }&.inject(:merge) }). + merge('project_uid' => project_uid) + end + field_reports = call('format_api_output_field_names', results) { events: field_reports || [], next_poll: closure, @@ -3294,11 +2725,11 @@ end }, new_updated_rfi: { - title: 'New or updated RFI in a project', - description: 'New or updated RFI '\ - 'in a PlanGrid project', + title: 'New/updated RFI in a Project', + description: 'New/updated RFI '\ + 'in a Plangrid Project', help: { - body: 'New or updated RFI in a project trigger uses the' \ + body: 'New/updated RFI in a Project trigger uses the' \ " Retrieve " \ ' RFIs in a Project API.', @@ -3387,14 +2818,12 @@ 'gov-state-local', 'other'].map { |type| [type.labelize, type] } end, project_folders: lambda do |_connection, project_uid:| - if project_uid.length === 36 - folders = get("/projects/#{project_uid}/attachments")['data']&. - pluck('folder')&.uniq - if folders.size > 0 - folders&.map { |folder| [folder || 'Root', folder || ''] } - else - [['Root', '']] - end + folders = get("/projects/#{project_uid}/attachments")['data']&. + pluck('folder')&.uniq + if folders.size > 0 + folders&.map { |folder| [folder || 'Root', folder || ''] } + else + [['Root', '']] end end } From 396716097b1b392f9d45687d2cdcaac5fef649fc Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 30 Aug 2019 13:06:14 -0400 Subject: [PATCH 55/96] update `new or updated field report..` trigger and `get field report..` action to output `pdf_form_fields` --- custom_connectors/oauth2/plangrid.rb | 1704 +++++++++++++++++--------- 1 file changed, 1144 insertions(+), 560 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 5385c9a7..253c77be 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1,5 +1,5 @@ { - title: 'Plangrid', + title: 'PlanGrid', connection: { fields: [ { @@ -54,43 +54,6 @@ end }, test: ->(_connection) { get('/me') }, - methods: { - format_api_output_field_names: lambda do |input| - if input.is_a?(Array) - input.map do |array_value| - call('format_api_output_field_names', array_value) - end - elsif input.is_a?(Hash) - input.map do |key, value| - value = call('format_api_output_field_names', value) - key = key.gsub(/\W/) { |string| "__#{string.encode_hex}__" } - { key => value } - end.inject(:merge) - else - input - end - end, - - format_schema_field_names: lambda do |input| - input.map do |field| - if field[:properties].present? - field[:properties] = call('format_schema_field_names', - field[:properties]) - elsif field['properties'].present? - field['properties'] = call('format_schema_field_names', - field['properties']) - end - if field[:name].present? - field[:name] = field[:name]. - gsub(/\W/) { |string| "__#{string.encode_hex}__" } - elsif field['name'].present? - field['name'] = field['name']. - gsub(/\W/) { |string| "__#{string.encode_hex}__" } - end - field - end - end - }, object_definitions: { project: { fields: lambda do |_connection, _config_fields| @@ -98,7 +61,7 @@ { name: 'uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -111,11 +74,11 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'name', label: 'Project name', sticky: true }, - { name: 'custom_id', label: 'Project code', sticky: true }, - { name: 'organization_id' }, + { name: 'name', label: 'Project Name', sticky: true }, + { name: 'custom_id', label: 'Project Code', sticky: true }, + { name: 'organization_id', label: 'Organization ID' }, { name: 'type', control_type: 'select', - label: 'Project type', sticky: true, + label: 'Project Type', sticky: true, pick_list: 'project_types', toggle_hint: 'Select project type', toggle_field: { @@ -130,26 +93,26 @@ 'education-k-12, education-higher, gov-federal, ' \ 'gov-state-local, or other' } }, - { name: 'status', label: 'Project status', sticky: true }, - { name: 'owner', sticky: true, label: 'Project owner' }, + { name: 'status', label: 'Project Status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project Owner' }, { name: 'start_date', type: 'date', sticky: true, render_input: 'date_conversion', parse_output: 'date_conversion', - label: 'Project start date', + label: 'Project Start Date', hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, { name: 'end_date', type: 'date', sticky: true, render_input: 'date_conversion', parse_output: 'date_conversion', - label: 'Project end date', + label: 'Project End Date', hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, { name: 'street_1', sticky: true, - label: 'Street line 1' }, + label: 'Street Line 1' }, { name: 'street_2', sticky: true, label: 'Street line 2' }, - { name: 'city', sticky: true, label: 'Town or city' }, - { name: 'region', sticky: true, label: 'State, province, or region' }, - { name: 'postal_code', sticky: true, label: 'Zip or postal code' }, + { name: 'city', sticky: true, label: 'Town or City' }, + { name: 'region', sticky: true, label: 'State, Province, or Region' }, + { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, { name: 'country', sticky: true, hint: 'Project address country in 2-letter ISO 3166 code.' }, @@ -158,22 +121,7 @@ { name: 'updated_at', type: 'date_time', render_input: 'date_time_conversion', parse_output: 'date_time_conversion', - label: 'Updated at' }, - { name: 'add_to_organization', type: 'boolean', - control_type: 'checkbox', - hint: 'Boolean indicating whether to add the project to the ' \ - 'organization that the API user belongs to or not. By default ' \ - 'the project is created as a personal project and not as an ' \ - 'organization-linked project.', - toggle_hint: 'Select from options list', - toggle_field: { - name: 'add_to_organization', - label: 'Add to organization', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } } + label: 'Updated at' } ] end }, @@ -184,7 +132,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -197,14 +145,14 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'name', label: 'Document name' }, + { name: 'name', label: 'Document Name' }, { name: 'folder' }, { name: 'url' }, { name: 'created_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, @@ -222,7 +170,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -235,26 +183,64 @@ hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, + { name: 'number', type: 'number' }, + { name: 'title' }, + { name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending",' \ + ' "closed".' + } }, + { name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work",' \ + ' "other".' + } }, { name: 'assignees', type: 'array', of: 'object', properties: [ - { name: 'assignee' } + { name: 'uid', label: 'UID' }, + { name: 'type' } + ] }, + { name: 'followers', label: 'Watchers', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'type' } ] }, + { name: 'room', label: 'Location' }, + { name: 'start_date', label: 'Start Date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, { name: 'closed_at', type: 'date_time', render_input: 'date_time_conversion', parse_output: 'date_time_conversion' }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'comments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'string', label: 'Stamp', + hint: 'One to two character stamp associated with task.' }, + { name: 'issue_list', label: 'Task List', type: 'object', properties: [ + { name: 'uid', label: 'Task List ID' }, { name: 'url' } ] }, - { name: 'cost_impact', type: 'number' }, - { name: 'has_cost_impact', type: 'boolean', + { name: 'description' }, + { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, + { name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', control_type: 'checkbox', toggle_hint: 'Select from options list', toggle_field: { name: 'cost_impact', @@ -264,12 +250,23 @@ toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'currency_code', + { name: 'currency_code', label: 'Currency Code', hint: 'The ISO-4217 currency code of the cost_impact,' \ ' Currently only supports USD. maybe null if cost_impact is ' \ 'not specified' }, + { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, + { name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_schedule_impact', + label: 'Has schedule impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, { name: 'current_annotation', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'color' }, { name: 'stamp' }, { name: 'visibility' }, @@ -284,84 +281,36 @@ hint: 'Allowed values are: true, false' } }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' } ] } ] }, - { name: 'deleted', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'description' }, - { name: 'due_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'followers', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' } - ] }, - { name: 'issue_list', type: 'object', properties: [ - { name: 'uid' }, + { name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'number', type: 'number' }, { name: 'photos', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'room' }, - { name: 'schedule_impact', type: 'integer' }, - { name: 'has_schedule_impact', type: 'boolean', + { name: 'deleted', label: 'Deleted?', type: 'boolean', control_type: 'checkbox', toggle_hint: 'Select from options list', toggle_field: { - name: 'has_schedule_impact', - label: 'Has schedule impact', + name: 'deleted', + label: 'Deleted', type: 'string', control_type: 'text', toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'start_date', - type: 'date_time', - render_input: 'date_conversion', - parse_output: 'date_conversion' }, - { name: 'status', control_type: 'select', pick_list: - %w[open in_review pending closed].select { |op| [op.labelize, op] }, - toggle_hint: 'Select status', - toggle_field: { - name: 'status', - label: 'Status', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are : "open", "in_review", "pending",' \ - ' "closed".' - } }, - { name: 'string', - hint: 'One to two character stamp associated with task.' }, - { name: 'title' }, - { name: 'type', control_type: 'select', - pick_list: [ - %w[issue issue], - %w[Planned\ work planned_work], - %w[other other] - ], - toggle_hint: 'Select type', - toggle_field: { - name: 'type', - label: 'Type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: "issue", "planned_work",' \ - ' "other".' - } }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] }, { name: 'updated_at', render_input: 'date_time_conversion', parse_output: 'date_time_conversion', @@ -394,11 +343,11 @@ annotation: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'Unique Identifier' }, + { name: 'uid', label: 'Annotation ID' }, { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -425,9 +374,8 @@ hint: 'Allowed values are: true, false' } }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid' }, - { name: 'label' }, - { name: 'color' } + { name: 'uid', label: 'UID' }, + { name: 'url' } ] } ] end @@ -439,7 +387,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -458,12 +406,12 @@ render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, { name: 'sheet', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' } ] }, { name: 'deleted', type: 'boolean', @@ -486,7 +434,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -500,35 +448,27 @@ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, { name: 'title' }, - { name: 'url' }, + { name: 'url', label: 'URL' }, { name: 'created_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, - { name: 'deleted', type: 'boolean', control_type: 'checkbox', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } } + { name: 'deleted', type: 'boolean' } ] end }, field_report: { - fields: lambda do |_connection, config_fields| - standard_fields = [ - { name: 'uid', label: 'File report ID' }, + fields: lambda do |_connection, _config_fields| + [ + { name: 'uid', label: 'Field Report ID' }, { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -543,23 +483,27 @@ } }, { name: 'title' }, { name: 'description' }, - { name: 'report_date', type: 'date_time', + { name: 'report_date', label: 'Report Date', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, - { name: 'field_report_type', type: 'object', properties: [ + { name: 'status' }, + { name: 'field_report_type', label: 'Field Report Type', type: 'object', properties: [ { name: 'name' }, - { name: 'project_uid' }, { name: 'status' }, - { name: 'uid' } + { name: 'uid', label: 'UID' } ] }, - { name: 'pdf_url' }, - { name: 'pg_form_values', type: 'array', of: 'object', properties: [ - { name: 'pg_equipment_entries', type: 'array', of: 'object', + { name: 'pdf_url', label: 'PDF URL' }, + { name: 'pdf_form_values', label: 'PDF Form Values', type: 'array', of: 'object', properties: [ + { name: 'name', label: 'Field Name' }, + { name: 'value', label: 'Field Value' } + ]}, + { name: 'pdf_form_fields', label: 'PDF Field Values', type: 'object' }, + { name: 'pg_form_values', label: 'Daily Report Values', type: 'array', of: 'object', properties: [ + { name: 'pg_worklog_entries', label: 'Work Log Entries', type: 'array', of: 'object', properties: [ - { name: 'uid' }, + { name: 'trade' }, { name: 'timespan' }, - { name: 'quantity', type: 'integer' }, - { name: 'item' }, + { name: 'headcount', type: 'integer' }, { name: 'description' }, { name: 'deleted', type: 'boolean', control_type: 'checkbox', @@ -573,21 +517,19 @@ hint: 'Allowed values are: true, false' } } ] }, - { name: 'pg_materials_entries', type: 'array', of: 'object', + { name: 'pg_materials_entries', label: 'Material Entries', type: 'array', of: 'object', properties: [ - { name: 'uid' }, { name: 'unit', type: 'integer' }, { name: 'quantity', type: 'integer' }, { name: 'item' }, { name: 'description' }, { name: 'deleted' } ] }, - { name: 'pg_worklog_entries', type: 'array', of: 'object', + { name: 'pg_equipment_entries', label: 'Equipment Entries', type: 'array', of: 'object', properties: [ - { name: 'uid' }, - { name: 'trade' }, { name: 'timespan' }, - { name: 'headcount', type: 'integer' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, { name: 'description' }, { name: 'deleted', type: 'boolean', control_type: 'checkbox', @@ -602,26 +544,23 @@ } } ] } ] }, - { name: 'attachments', type: 'object', properties: [ + { name: 'attachments', label: 'Documents', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'created_by', type: 'object', properties: [ - { name: 'email' }, - { name: 'uid' }, - { name: 'url' } - ] }, { name: 'photos', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'project_uid', label: 'Project ID' }, - { name: 'report_date', type: 'date' }, { name: 'snapshots', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, { name: 'url' } ] }, - { name: 'status' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'email' }, + { name: 'uid', label: 'UID' }, + { name: 'url' } + ] }, { name: 'updated_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, @@ -639,13 +578,6 @@ { name: 'wind_speed', type: 'number' } ] } ] - pdf_form_fileds = get("/projects/#{config_fields['project_uid']}/" \ - 'field_reports').params(limit: 1)&. - map do |key, _value| - { name: key } - end&.inject(:merge) - standard_fields.merge({ 'pdf_form_values' => - call('format_schema_field_names', pdf_form_fileds) }) end }, rfi: { @@ -655,7 +587,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', sticky: true, toggle_hint: 'Select project', toggle_field: { @@ -670,7 +602,7 @@ } }, { name: 'number', type: 'integer' }, { name: 'status', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'label' }, { name: 'color' } ] }, @@ -697,12 +629,9 @@ { name: 'due_at', type: 'date_time', render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, - { name: 'assigned_to_uids', - hint: 'Array of unique identifiers of users who ' \ - 'are RFI assignees.' }, { name: 'assigned_to', type: 'array', of: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, @@ -714,7 +643,7 @@ "timestamps-and-timezones' target='_blank'>Timestamps and " \ 'Timezones for accepted date formats' }, { name: 'updated_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, @@ -722,7 +651,7 @@ render_input: 'parse_iso8601_timestamp', parse_output: 'parse_iso8601_timestamp' }, { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, @@ -748,7 +677,7 @@ rfi_status: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'RFI status ID' }, + { name: 'uid', label: 'Status ID' }, { name: 'label' }, { name: 'color' } ] @@ -758,15 +687,31 @@ fields: lambda do |_connection, _config_fields| [ { name: 'uid', label: 'User ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project ID', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, { name: 'email' }, - { name: 'first_name' }, - { name: 'last_name' }, - { name: 'language' }, + { name: 'first_name', label: 'First Name' }, + { name: 'last_name', label: 'Last Name' }, + { name: 'language'}, { name: 'role', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' } ] }, - { name: 'removed' } + { name: 'removed', label: 'Removed?' } ] end }, @@ -774,13 +719,29 @@ fields: lambda do |_connection, _config_fields| [ { name: 'uid', label: 'Sheet ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project ID', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, { name: 'name' }, - { name: 'version_name' }, + { name: 'version_name', label: 'Version Name' }, { name: 'description' }, - { name: 'tags', hint: 'An array of strings representing the' \ + { name: 'tags', type: 'array', of: 'string', hint: 'An array of strings representing the' \ ' tags added to this sheet.' }, { name: 'published_by', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' }, { name: 'email' } ] }, @@ -799,20 +760,36 @@ toggle_hint: 'Use custom value', hint: 'Allowed values are: true, false' } }, - { name: 'uploaded_file_name' } + { name: 'uploaded_file_name', label: 'Uploaded file name' } ] end }, sheet_packet: { fields: lambda do |_connection, _config_fields| [ - { name: 'uid', label: 'Sheet packet ID' }, - { name: 'file_url' }, + { name: 'uid', label: 'Sheet Packet ID' }, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project ID', + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'status' }, + { name: 'file_url', label: 'File URL' }, { name: 'resource', type: 'object', properties: [ - { name: 'uid' }, + { name: 'uid', label: 'UID' }, { name: 'url' } - ] }, - { name: 'status' } + ] } ] end }, @@ -969,7 +946,7 @@ create_project: { title: 'Create project', description: 'Create project in'\ - ' Plangrid', + ' PlanGrid', help: { body: 'Create project action uses the' \ " project in'\ - ' Plangrid', + ' PlanGrid', help: { body: 'Update project action uses the' \ " Update Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-project', - learn_more_text: 'Update a Project' + learn_more_text: 'Update Project' }, input_fields: lambda do |object_definitions| object_definitions['project'].required('uid'). ignored('updated_at', 'latitude', 'longitude', 'organization_id') end, execute: lambda do |_connection, input| - patch("/projects/#{input.delete('uid')}").payload(input). + payload = input.each do |key, value| + input[key].present? || input[key] = nil + end + patch("/projects/#{input.delete('uid')}").payload(payload.except('uid')). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end @@ -1025,11 +1020,11 @@ end }, get_project_details: { - title: 'Get project info. by ID', - description: 'Get project info.'\ - ' by ID in Plangrid', + title: 'Get project', + description: 'Get project'\ + ' in PlanGrid', help: { - body: 'Get project info. by ID action uses the' \ + body: 'Get project action uses the' \ " Retrieve a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-a-project', @@ -1050,8 +1045,8 @@ }, upload_document: { title: 'Upload document to a project', - description: 'Upload document to a project'\ - ' in Plangrid', + description: 'Upload document to a'\ + ' PlanGrid project', help: { body: 'Upload document to a project action uses the' \ " document in a'\ + ' PlanGrid project', + help: { + body: 'Update document in a project action uses the' \ + " Update Document to Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/update-attachment-' \ + 'in-a-project', + learn_more_text: 'Update Document in a Project API' + }, + summarize_input: %w[file_content], + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'attachment_uid', label: 'Document ID', optional: false }, + { name: 'name', label: 'Document Name', + hint: 'New name of the document', sticky: true }, + { name: 'folder', label: 'Folder', + hint: 'New folder of the document', sticky: true } + ] + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + patch("/projects/#{project_uid}/attachments/" \ + "#{input.delete('attachment_uid')}"). + headers('Content-type': 'application/json'). + payload(input). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + object_definitions['document'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/attachments")&.dig('data', 0)&. + merge('project_uid' => id) || {} + end }, create_rfi: { title: 'Create RFI in a project', description: 'Create RFI in'\ - ' a Plangrid project ', + ' a PlanGrid project ', help: { - body: 'Create RFI in project action uses the ' \ + body: 'Create RFI in a project action uses the ' \ "Create RFI in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-rfi-' \ @@ -1228,11 +1273,11 @@ update_rfi: { title: 'Update RFI in a project', description: 'Update RFI in'\ - ' a Plangrid project', + ' a PlanGrid project', help: { - body: 'Update RFI in Project action uses the ' \ + body: 'Update RFI in a project action uses the ' \ "patchUpdate RFI in a Project API.", + "project' target='_blank'>Update RFI in a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-' \ 'rfi-in-a-project', learn_more_text: 'Update RFI in a Project' @@ -1255,8 +1300,7 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'status', label: 'Status', - hint: 'Use this for create and update rfi status' } + { name: 'status', label: 'Status UID' } ].concat(object_definitions['rfi']. only('uid', 'locked', 'title', 'question', 'answer', 'sent_at', 'due_at', 'assigned_to_uids'). @@ -1287,10 +1331,10 @@ }, get_rfi_in_project: { title: 'Get RFI in a project', - description: 'Get RFI by ID in'\ - ' Plangrid project', + description: 'Get RFI in '\ + 'a PlanGrid project', help: { - body: 'Get RFI by ID in a project action uses the' \ + body: 'Get RFI in a project action uses the' \ " Retrieve RFI in a Project API.", @@ -1299,12 +1343,29 @@ learn_more_text: 'Retrieve RFI in a Project' }, input_fields: lambda do |object_definitions| - object_definitions['rfi'].only('project_uid', 'uid'). - required('project_uid', 'uid') + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'rfi_uid', label: 'RFI ID', optional: false } + ] end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') - get("/projects/#{project_uid}/rfis/#{input['uid']}")&. + get("/projects/#{project_uid}/rfis/#{input['rfi_uid']}")&. merge('project_uid' => project_uid) end, output_fields: lambda do |object_definitions| @@ -1319,11 +1380,11 @@ create_task: { title: 'Create task in a project', description: 'Create task in'\ - ' Plangrid project', + ' a PlanGrid project', help: { - body: 'Create task in Project action uses the ' \ + body: 'Create task in a project action uses the ' \ "Create task in Project API.", + "project' target='_blank'>Create Task in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-task-in-' \ 'a-project', learn_more_text: 'Create Task in a Project' @@ -1345,12 +1406,15 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g. ' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } } + } + }, + { name: 'issue_list_uid', label: 'Task List ID', sticky: true } ].concat(object_definitions['task']. - only('assigned_to_uids', 'cost_impact', 'description', 'due_at', - 'has_cost_impact', 'has_schedule_impact', - 'issue_list_uid', 'room', 'schedule_impact', 'start_date', - 'status', 'title', 'type')) + only('title', 'status', 'type', 'assigned_to_uids', + 'room', 'start_date', 'due_at', + 'description', 'has_cost_impact', 'cost_impact', + 'has_schedule_impact', 'schedule_impact' + )) end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') @@ -1376,13 +1440,13 @@ end }, update_task: { - title: 'Update task in a Project', + title: 'Update task in a project', description: 'Update task in'\ - ' Plangrid project', + ' a PlanGrid project', help: { - body: 'Update task in Project action uses the ' \ + body: 'Update task in a project action uses the ' \ "Create task in Project API.", + "project' target='_blank'>Update Task in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/create-project', learn_more_text: 'Update Task in a Project' }, @@ -1403,17 +1467,24 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g.' \ ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } } + } + }, + { name: 'issue_uid', label: 'Task ID', optional: false }, + { name: 'issue_list_uid', label: 'Task List ID', sticky: true } ].concat(object_definitions['task']. - only('uid', 'assigned_to_uids', 'cost_impact', 'description', - 'due_at', 'has_cost_impact', 'has_schedule_impact', - 'issue_list_uid', 'room', 'schedule_impact', 'start_date', - 'status', 'title', 'type').required('uid')) + only('title', 'status', 'type', 'assigned_to_uids', + 'room', 'start_date', 'due_at', + 'description', 'has_cost_impact', 'cost_impact', + 'has_schedule_impact', 'schedule_impact' + )) end, execute: lambda do |_connection, input| project_uid = input.delete('project_uid') + payload = input.each do |key, value| + input[key].present? || input[key] = nil + end patch("/projects/#{project_uid}/issues/" \ - "#{input.delete('uid')}").payload(input). + "#{input.delete('issue_uid')}").payload(payload). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end&.merge('project_uid' => project_uid) @@ -1430,7 +1501,7 @@ get_task: { title: 'Get task in a project', description: 'Get task in'\ - ' in a Plangrid project', + ' a PlanGrid project', help: { body: 'Get task in a project action uses the ' \ "user to'\ - ' project team Plangrid', + ' a PlanGrid project', help: { body: 'Invite user to a project action uses the ' \ "Invite user in Project team API.", + "project-team' target='_blank'>Invite User in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ 'invite-user-to-project-team', - learn_more_text: 'Invite User to Project Team' + learn_more_text: 'Invite User to Project' }, input_fields: lambda do |_object_definitions| [ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1508,16 +1579,17 @@ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, { name: 'email', optional: false }, - { name: 'role_uid', label: 'Role ID', + { name: 'role_uid', label: 'Role ID', sticky: true, hint: 'Unique identifier of role to assign user on project team' } ] end, execute: lambda do |_connection, input| - post("/projects/#{input.delete('project_uid')}/users/invites"). + project_uid = input.delete('project_uid') + post("/projects/#{project_uid}/users/invites"). payload(input). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") - end + end&.merge('project_uid' => project_uid) end, output_fields: lambda do |object_definitions| object_definitions['user'] @@ -1527,17 +1599,17 @@ get("/projects/#{id}/users")&.dig('data', 0) || {} end }, - get_user_by_id: { - title: 'Get user in a project', + get_user_in_project: { + title: 'Get user in project', description: 'Get user in'\ - ' Plangrid project', + ' a PlanGrid project', help: { - body: 'Get user in project action uses the ' \ + body: 'Get user in a project action uses the ' \ "Retrieve User on a Project Team.", + "project-team' target='_blank'>Retrieve User in a Project.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ 'users-on-a-project-team', - learn_more_text: 'Retrieve User on a Project Team' + learn_more_text: 'Retrieve User in a Project' }, input_fields: lambda do |_object_definitions| [ @@ -1576,7 +1648,7 @@ get_snapshot_in_project: { title: 'Get snapshot in a project', description: 'Get snapshot in'\ - ' a Plangrid project', + ' a PlanGrid project', help: { body: 'Get snapshot in a project action uses the ' \ " input['project_uid']) end, output_fields: lambda do |object_definitions| object_definitions['snapshot'] @@ -1621,10 +1693,10 @@ }, get_rfi_statuses_in_project: { title: 'Get RFI statuses in project', - description: 'Get rfi statuses in'\ - ' Plangrid project', + description: 'Get RFI statuses in'\ + ' a PlanGrid project', help: { - body: 'Get rfi statuses in project action uses the ' \ + body: 'Get RFI statuses in project action uses the ' \ "Retrieve RFI Statuses in a Project.", learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ @@ -1672,23 +1744,23 @@ end }, get_roles_on_project: { - title: 'Get roles on a project', - description: 'Get roles on '\ - ' Plangrid project', + title: 'Get roles in a project', + description: 'Get roles in '\ + ' a PlanGrid project', help: { - body: 'Get role on a project action uses the ' \ - "Retrieve Role on a Project API.", + body: 'Get roles in a project action uses the ' \ + "Retrieve Roles on a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-role-on-a-project', - learn_more_text: 'Retrieve Role on a Project' + 'retrieve-roles-on-a-project', + learn_more_text: 'Retrieves Role on a Project' }, input_fields: lambda do |_object_definitions| [ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1700,24 +1772,19 @@ toggle_hint: 'Use project ID', hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'limit', type: 'integer', - hint: 'Number of roles to retrieve. Maximum value of 50.' }, - { name: 'skip', type: 'integer', - hint: 'Number of roles to skip in the set of results.' } + } } ] end, execute: lambda do |_connection, input| - { roles: get("/projects/#{input.delete('project_uid')}/roles", input) } + project_uid = input.delete('project_uid') + { roles: get("/projects/#{project_uid}/roles")['data'] } end, output_fields: lambda do |_object_definitions| [ - { name: 'roles', type: 'array', of: 'object', properties: [ - { name: 'uid' }, - { name: 'label' } - ] }, - { name: 'total_count' }, - { name: 'next_page_url' } + { name: 'roles', label: 'Roles', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'label', label: 'Role' } + ] } ] end, sample_output: lambda do |_connection, _input| @@ -1725,69 +1792,15 @@ 'label' => 'Admin' } } end }, - get_sheets_in_project: { - title: 'Get sheets in a project', - description: 'Get sheets in'\ - ' Plangrid project', - help: { - body: 'Get sheets in project action uses the ' \ - "Retrieve Sheets in a Project.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-sheets-in-a-project', - learn_more_text: 'Retrieve Sheets in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'limit', type: 'integer', - hint: 'Number of sheets to retrieve. Maximum value of 50.' }, - { name: 'skip', type: 'integer', - hint: 'Number of sheets to skip in the set of results' }, - { name: 'updated_after', type: 'date_time', - hint: 'Only retrieve sheets created/updated after ' \ - 'specified UTC date and time.' } - ] - end, - execute: lambda do |_connection, input| - { sheets: get("/projects/#{input.delete('project_uid')}/sheets", - input)['data'] } - end, - output_fields: lambda do |object_definitions| - [{ name: 'sheets', type: 'array', of: 'object', - properties: object_definitions['sheet'] }] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - { - sheets: get("/projects/#{id}/sheets?limit=1")&.dig('data', 0)&. - merge('project_uid' => id) || {} - } - end - }, + get_sheet_in_project: { - title: 'Get sheet by ID in project', - description: 'Get sheet in'\ - ' Plangrid project', + title: 'Get sheet in a project', + description: 'Get sheet in '\ + 'a PlanGrid project', help: { - body: 'Get project sheet details action uses the ' \ + body: 'Get sheet in a project action uses the ' \ "Retrieve Sheets in a Project.", + " target='_blank'>Retrieve Sheet in a Project.", learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-a-sheet', learn_more_text: 'Retrieve Sheet in a Project' @@ -1797,7 +1810,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1810,11 +1823,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'sheet_uid', type: 'Sheet ID', optional: false } + { name: 'sheet_uid', label: 'Sheet ID', optional: false } ] end, execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/sheets/#{input['sheet_uid']}") + get("/projects/#{input['project_uid']}/sheets/#{input['sheet_uid']}")&. + merge('project_uid' => input['project_uid']) end, output_fields: lambda do |object_definitions| object_definitions['sheet'] @@ -1826,11 +1840,11 @@ end }, get_project_sheet_packet: { - title: 'Get project sheet packet', - description: 'Get project sheet packet in'\ - ' packet in Plangrid', + title: 'Get sheet packet in a project', + description: 'Get sheet packet in'\ + ' a PlanGrid project', help: { - body: 'Get project sheet packet action uses the ' \ + body: 'Get sheet packet in a project action uses the ' \ "Retrieve Sheet Packet API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -1855,23 +1869,23 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'packet_uid', type: 'Packet ID' } + { name: 'packet_uid', label: 'Sheet Packet ID', optional: false } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/sheets/packets/" \ - "#{input['packet_uid']}") + "#{input['packet_uid']}")&.merge('project_uid' => input['project_uid']) end, output_fields: lambda do |object_definitions| object_definitions['sheet_packet'] end }, get_field_reports_in_project: { - title: 'Get fields reports in project', + title: 'Get field reports in a project', description: 'Get field reports in'\ - ' in Plangrid project', + ' a PlanGrid project', help: { - body: 'Get fields reports in project action uses the ' \ + body: 'Get field reports in a project action uses the ' \ "Retrieve Field Reports in a" \ ' Project API.', @@ -1884,7 +1898,7 @@ { name: 'project_uid', control_type: 'select', pick_list: 'project_list', - label: 'Project', + label: 'Project ID', optional: false, toggle_hint: 'Select project', toggle_field: { @@ -1897,17 +1911,17 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'updated_after', type: 'date_time', - hint: 'Only retrieve field reports created/updated after ' \ - 'specified UTC date and time.' }, - { name: 'report_date_min', type: 'date_time', - label: 'Report start date', + { name: 'report_date_min', type: 'date', + label: 'Report Start Date', hint: 'Only retrieve field reports between a date range ' \ 'starting with this date in UTC format.' }, - { name: 'report_date_max', type: 'date_time', - label: 'Report end date', + { name: 'report_date_max', type: 'date', + label: 'Report End Date', hint: 'Only retrieve field reports between a date range ' \ 'starting with this date in UTC format.' }, + { name: 'updated_after', label: 'Updated After', type: 'date_time', + hint: 'Only retrieve field reports created/updated after ' \ + 'specified UTC date and time.' }, { name: 'sort_by', control_type: 'select', pick_list: %w[report_date updated_at]&.map { |e| [e.labelize, e] }, @@ -1915,6 +1929,14 @@ toggle_field: { name: 'sort_by', type: 'string', control_type: 'text', hint: 'Allowed values report_date or updated_at' + } }, + { name: 'sort_order', control_type: 'select', + pick_list: + %w[asc desc]&.map { |e| [e.labelize, e] }, + toggle_hint: 'Select sort order', + toggle_field: { + name: 'sort_by', type: 'string', control_type: 'text', + hint: 'Allowed values asc or desc' } } ] end, @@ -1922,17 +1944,26 @@ project_uid = input.delete('project_uid') query_params = '' input&.map do |key, val| - if %w[updated_after report_date_min report_date_max].include?(key) - query_params = query_params + "#{key}=#{val.to_time.utc.iso8601}" + if %w[updated_after].include?(key) + query_params = query_params + "&" + "#{key}=#{val.to_time.utc.iso8601}" else - query_params = query_params + "#{key}=#{val}" + query_params = query_params + "&" + "#{key}=#{val}" end end - { field_reports: get("/projects/#{project_uid}/field_reports?" \ - "#{query_params}")['data'] } + + results = get("/projects/#{project_uid}/field_reports?" \ + "#{query_params}")['data'] + + field_reports = results.map do |field_report| + field_report.merge({ + 'pdf_form_fields' => field_report['pdf_form_values'] + &.map { |a| { a['name'] => a['value'] } }&.inject(:merge) }) + end + { field_reports: field_reports } + end, output_fields: lambda do |object_definitions| - { name: 'field_reports', type: 'array', of: 'object', + { name: 'field_reports', label: 'Field Reports', type: 'array', of: 'object', properties: object_definitions['field_report'] } end, sample_output: lambda do |_connection, _input| @@ -1943,9 +1974,9 @@ end }, upload_photo: { - title: 'Upload photo to project', + title: 'Upload photo to a project', description: 'Upload photo to '\ - ' project in Plangrid', + ' a PlanGrid project', help: { body: 'Upload photo to a project action uses the' \ " project_uid) end, output_fields: lambda do |object_definitions| object_definitions['photo'] @@ -2022,16 +2055,16 @@ end }, update_photo_metadata: { - title: 'Update photo metadata', - description: 'Update photo metadata to '\ - ' Project in Plangrid', + title: 'Update photo in a project', + description: 'Update photo in'\ + ' a PlanGrid project', help: { - body: 'Update photo metadata action uses the' \ + body: 'Update photo action uses the' \ " Update Document to Project API.", + "project' target='_blank'>Update Photo in a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/update-photo-' \ 'in-a-project', - learn_more_text: 'Update photo to Project API' + learn_more_text: 'Update Photo in a Project API' }, summarize_input: %w[file_content], input_fields: lambda do |_object_definitions| @@ -2048,19 +2081,20 @@ toggle_hint: 'Use project ID', hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'photo_uid', type: 'Photo ID', optional: false }, + { name: 'photo_uid', label: 'Photo ID', optional: false }, { name: 'title', label: 'Photo title', - hint: 'New title of the photo' } + hint: 'New title of the photo', sticky: true } ] end, execute: lambda do |_connection, input| - patch("/projects/#{input.delete('project_uid')}/photos/" \ + project_uid = input.delete('project_uid') + patch("/projects/#{project_uid}/photos/" \ "#{input.delete('photo_uid')}"). headers('Content-type': 'application/json'). payload(input). after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") - end + end&.merge('project_uid' => project_uid) end, output_fields: lambda do |object_definitions| object_definitions['photo'] @@ -2071,12 +2105,12 @@ merge('project_uid' => id) || {} end }, - get_photo_by_id: { - title: 'Get photo in a Project', + get_photo_details: { + title: 'Get photo in a project', description: 'Get photo in'\ - ' a Plangrid project', + ' a PlanGrid project', help: { - body: 'Get photo details action uses the ' \ + body: 'Get photo action uses the ' \ "Retrieve Photo in Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -2101,12 +2135,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'photo_uid', type: 'Photo ID', optional: false } + { name: 'photo_uid', label: 'Photo ID', optional: false } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/photos/" \ - "#{input['photo_uid']}") + "#{input['photo_uid']}")&.merge('project_uid' => input.delete('project_uid')) end, output_fields: lambda do |object_definitions| object_definitions['photo'] @@ -2117,12 +2151,12 @@ merge('project_uid' => id) || {} end }, - get_document_by_id: { + get_document_details: { title: 'Get document in a project', - description: 'Get document in'\ - ' in Plangrid project', + description: 'Get document'\ + ' in a PlanGrid project', help: { - body: 'Get document details action uses the ' \ + body: 'Get document in a project action uses the ' \ "Retrieve Document in a Project API.", learn_more_url: 'https://developer.plangrid.com/docs/' \ @@ -2147,12 +2181,12 @@ hint: 'Provide project ID e.g. ' \ '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { name: 'attachment_uid', type: 'Document ID', optional: false } + { name: 'attachment_uid', label: 'Document ID', optional: false } ] end, execute: lambda do |_connection, input| get("/projects/#{input['project_uid']}/attachments/" \ - "#{input['attachment_uid']}") + "#{input['attachment_uid']}")&.merge('project_uid' => input.delete('project_uid')) end, output_fields: lambda do |object_definitions| object_definitions['document'] @@ -2162,116 +2196,666 @@ get("/projects/#{id}/attachments")&.dig('data', 0)&. merge('project_uid' => id) || {} end - } - }, - triggers: { - new_updated_project: { - title: 'New/updated project', - description: 'New/updated project in'\ - ' Plangrid', + }, + create_sheet_packet: { + title: 'Create sheet packet in a project', + description: 'Create sheet packet in '\ + ' a PlanGrid project', help: { - body: 'New/updated project trigger uses the' \ - " List all Projects API.", - learn_more_url: 'https://developer.plangrid.com/docs/list-all-projects', - learn_more_text: 'List All Projects API' + body: 'Create sheet packet in a project action uses the' \ + " Create Sheet Packet in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/upload-photo' \ + '-to-project', + learn_more_text: 'Create Sheet Packet in a Project' }, - input_fields: lambda do |_object_definitions| + input_fields: lambda do |object_definitions| [ - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'sheet_uids', label: 'Sheet IDs', optional: false, + type: 'string', + hint: 'A comma separated list of sheet IDs.' }, + { name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'include_annotations', + label: 'Include annotations?', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } }, ] end, - poll: lambda do |_connection, input, closure| - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 20 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get('/projects'). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'updated_after' => now.to_time.utc.iso8601 } - end - { - events: response['data'] || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + payload = { + sheet_uids: input.delete('sheet_uids').split(','), + include_annotations: input.delete('include_annotations') } - end, - dedup: lambda do |project| - "#{project['uid']}@#{project['updated_at']}" + post("/projects/#{project_uid}/sheets/packets").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end&.merge('project_uid' => project_uid) end, output_fields: lambda do |object_definitions| - object_definitions['project'] + object_definitions['sheet_packet'] end, sample_output: lambda do |_connection, _input| - get('/projects')&.dig('data', 0) || {} + { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + file_url: "https://packet-assets.plangrid.com/92cf7193-af0c-42fc-a3ab-7ef5149da720.pdf", + resource: { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/packets/92cf7193-af0c-42fc-a3ab-7ef5149da720" + }, + status: "incomplete" + } end }, - new_updated_documents: { - title: 'New/updated documents in a project', - description: 'New/updated document in '\ - 'Project Plangrid', + get_task_list: { + title: 'Get task list in a project', + description: 'Get task list'\ + ' in a PlanGrid project', help: { - body: 'New/updated documents in Project trigger uses the' \ - " Retrieve Documents in a Project" \ - ' API.', - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'attachments-in-a-project', - learn_more_text: 'Retrieve Documents in a Project' + body: 'Get task list in a project action uses the ' \ + "Retrieve Task List in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'retrieve-issue-list', + learn_more_text: 'Retrieve Task List in a Project API' }, input_fields: lambda do |_object_definitions| [ - { name: 'project_uid', optional: false, + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', label: 'Project', - control_type: 'select', pick_list: 'project_list', + optional: false, toggle_hint: 'Select project', toggle_field: { name: 'project_uid', - label: 'Project ID', type: 'string', control_type: 'text', + optional: false, + label: 'Project ID', toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } + { name: 'issue_list_uid', label: 'Task List ID', optional: false } ] end, - poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 5 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else + execute: lambda do |_connection, input| + get("/projects/#{input['project_uid']}/issue_lists/" \ + "#{input['issue_list_uid']}") + end, + output_fields: lambda do |object_definitions| + [ + { + name: "uid", label: "Task List ID" + }, + { + name: "project_uid", label: "Project ID" + }, + { + name: "name", label: "Name" + }, + { + name: "deleted", label: "Deleted", type: "boolean" + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", + name: "QA/QC", + deleted: false, + project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" + } + end + }, + update_task_list: { + title: 'Update task list in a project', + description: 'Update task list'\ + ' in a PlanGrid project', + help: { + body: 'Update task list in a project action uses the ' \ + "Update Task List in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'update-issue-list', + learn_more_text: 'Update Task List in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'issue_list_uid', label: 'Task List ID', optional: false }, + { name: 'name', optional: false } + ] + end, + execute: lambda do |_connection, input| + patch("/projects/#{input['project_uid']}/issue_lists/" \ + "#{input['issue_list_uid']}").payload({name: input.delete('name')}) + end, + output_fields: lambda do |object_definitions| + [ + { + name: "uid", label: "Task List ID" + }, + { + name: "project_uid", label: "Project ID" + }, + { + name: "name", label: "Name" + }, + { + name: "deleted", label: "Deleted", type: "boolean" + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", + name: "QA/QC", + deleted: false, + project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" + } + end + }, + create_task_list: { + title: 'Create task list in a project', + description: 'Create task list'\ + ' in a PlanGrid project', + help: { + body: 'Create task list in a project action uses the ' \ + "Create Task List in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'create-issue-list', + learn_more_text: 'Create Task List in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'name', optional: false } + ] + end, + execute: lambda do |_connection, input| + post("/projects/#{input.delete('project_uid')}/issue_lists").payload(input) + end, + output_fields: lambda do |object_definitions| + [ + { + name: "uid", label: "Task List ID" + }, + { + name: "project_uid", label: "Project ID" + }, + { + name: "name", label: "Name" + }, + { + name: "deleted", label: "Deleted", type: "boolean" + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", + name: "QA/QC", + deleted: false, + project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" + } + end + }, + create_sheet_version: { + title: 'Create sheet version upload in a project', + description: 'Create sheet version upload'\ + ' in a PlanGrid project', + help: { + body: 'Create sheet version in a project action uses the ' \ + "Upload Version to a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'upload-version-to-project', + learn_more_text: 'Upload Version to a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, + { name: 'version_name', label: 'Version Name', optional: false } + ] + end, + execute: lambda do |_connection, input| + post("/projects/#{input.delete('project_uid')}/sheets/uploads").payload(input) + end, + output_fields: lambda do |object_definitions| + [ + { + name: 'uid', label: 'Sheet Version Upload ID' + }, + { + name: 'complete_url', label: 'Upload Completion URL' + }, + { + name: 'status', + }, + { + name: 'file_upload_requests', label: 'File Upload Requests', + type: 'array', of: 'object', properties: [ + { + name: 'uid', label: 'File Upload ID' + }, + { + name: 'upload_status', label: 'File Upload Status' + }, + { + name: 'url', label: 'File Upload URL' + } + ] + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + complete_url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720", + status: "incomplete", + file_upload_requests: [ + { + uid: "b278fcba-72f0-4161-bfdc-89d5bde4d5e7", + upload_status: "issued", + url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720/files/b278fcba-72f0-4161-bfdc-89d5bde4d5e7" + }, + { + uid: "727fca7d-385b-4476-b257-4b96c00e879b", + upload_status: "issued", + url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720/files/727fca7d-385b-4476-b257-4b96c00e879b" + } + ] + } + end + }, + upload_file_to_sheet_version: { + title: 'Upload file to sheet version in a project', + description: 'Upload file to sheet version'\ + ' in a PlanGrid project', + help: { + body: 'Upload file to sheet version in a project action uses the ' \ + "Upload File to Version in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'upload-file-to-version', + learn_more_text: 'Upload File to Version in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false }, + { name: 'file_upload_request_uid', label: 'File Upload ID', optional: false }, + { name: 'file_name', label: 'File Name', optional: false }, + { name: 'file_content', label: 'File Content', optional: false } + ] + end, + execute: lambda do |_connection, input| + file_content = input.delete('file_content') + project_uid = input.delete('project_uid') + file_upload_info = post("/projects/#{project_uid}/sheets/" \ + "uploads/#{input.delete('ver_upload_uid')}/" \ + "files/#{input.delete('file_upload_request_uid')}"). + headers('Content-Type': 'application/json'). + payload({file_name: input.delete('file_name')}) + url = file_upload_info&.dig('aws_post_form_arguments', 'action') + fields = file_upload_info&.dig('aws_post_form_arguments', 'fields') + # webhook_url = file_upload_info. + # dig('aws_post_form_arguments', 'webhook_url') + headers = fields.map { |o| { o['name'] => o['value'] } }.inject(:merge) + status = + post(url). + payload(key: headers['key'], + policy: headers['policy'], + signature: headers['signature'], + AWSAccessKeyId: headers['AWSAccessKeyId'], + 'content-type': headers['Content-Type'], + 'success_action_redirect': headers['success_action_redirect'], + 'x-amz-server-side-encryption': + headers['x-amz-server-side-encryption'], + 'x-amz-storage-class': headers['x-amz-storage-class'], + file: file_content). + request_format_multipart_form. + after_response do |_code, response, _response_headers| + response + end + end, + output_fields: lambda do |object_definitions| + + end, + sample_output: lambda do |_connection, _input| + + end + }, + complete_version_upload: { + title: 'Complete sheet version upload to a project', + description: 'Complete sheet version upload '\ + ' to a PlanGrid project', + help: { + body: 'Complete sheet version upload to a project action uses the ' \ + "Complete Version Upload in a Project API.", + learn_more_url: 'https://developer.plangrid.com/docs/' \ + 'complete-version-upload-to-project', + learn_more_text: 'Complete Version Upload in a Project API' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Use project ID', + hint: 'Provide project ID e.g. ' \ + '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false } + ] + end, + execute: lambda do |_connection, input| + project_uid = input.delete('project_uid') + post("/projects/#{project_uid}/sheets/" \ + "uploads/#{input.delete('ver_upload_uid')}/completions")&.merge('project_uid' => project_uid) + end, + output_fields: lambda do |object_definitions| + [ + { + name: 'uid', label: 'Sheet Version ID' + }, + { + name: 'status', label: 'Status' + } + ] + end, + sample_output: lambda do |_connection, _input| + { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + complete_url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720", + status: "complete" + } + end + } + }, + triggers: { + new_updated_project: { + title: 'New or updated project', + description: 'New or updated project in'\ + ' PlanGrid', + help: { + body: 'New or updated project trigger uses the' \ + " List All Projects API.", + learn_more_url: 'https://developer.plangrid.com/docs/list-all-projects', + learn_more_text: 'List All Projects API' + }, + input_fields: lambda do |_object_definitions| + [ + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 20 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get('/projects'). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'updated_after' => now.to_time.utc.iso8601 } + end + { + events: response['data'] || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |project| + "#{project['uid']}@#{project['updated_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['project'] + end, + sample_output: lambda do |_connection, _input| + get('/projects')&.dig('data', 0) || {} + end + }, + new_updated_sheets: { + title: 'New or updated sheet in a project', + description: 'New or updated sheet in '\ + 'a PlanGrid project', + help: { + body: 'New or updated sheet in a project trigger uses the' \ + " Retrieve Sheets in a Project" \ + ' API.', + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'sheets-in-a-project', + learn_more_text: 'Retrieve Sheets in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 5 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else + get("/projects/#{project_uid}/sheets"). + params(limit: limit, + skip: skip, + updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'project_uid' => project_uid, + 'next_page_url' => next_page_url } + else + { 'offset' => 0, + 'project_uid' => project_uid, + 'updated_after' => now.to_time.utc.iso8601 } + end + sheets = response['data']&. + map { |o| o.merge('project_uid' => project_uid) } + { + events: sheets || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |sheet| + "#{sheet['uid']}@#{sheet['created_at']}" + end, + output_fields: lambda do |object_definitions| + object_definitions['sheet'] + end, + sample_output: lambda do |_connection, _input| + id = get('projects')&.[]('data', 0)&.[]('uid') + get("/projects/#{id}/sheets")&.dig('data', 0) || {} + end + }, + new_updated_documents: { + title: 'New or updated document in a project', + description: 'New or updated document in '\ + 'a PlanGrid project', + help: { + body: 'New or updated document in a project trigger uses the' \ + " Retrieve Documents in a Project" \ + ' API.', + learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ + 'attachments-in-a-project', + learn_more_text: 'Retrieve Documents in a Project' + }, + input_fields: lambda do |_object_definitions| + [ + { name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Use project ID', + hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } }, + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + end, + poll: lambda do |_connection, input, closure| + project_uid = closure&.[]('project_uid') || input['project_uid'] + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 5 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + else get("/projects/#{project_uid}/attachments"). params(limit: limit, skip: skip, @@ -2306,11 +2890,11 @@ end }, new_updated_task: { - title: 'New/updated task in a Project', - description: 'New/updated task in a '\ - 'Project Plangrid', + title: 'New or updated task in a project', + description: 'New or updated task in a '\ + ' PlanGrid project', help: { - body: 'New/updated task in a Project trigger uses the' \ + body: 'New or updated task in a project trigger uses the' \ " Retrieve Tasks " \ ' in a Project API.', @@ -2389,14 +2973,14 @@ end }, new_updated_annotations: { - title: 'New/updated annotations in Project', - description: 'New/updated annotations '\ - 'in Project Plangrid', + title: 'New or updated annotation in a project', + description: 'New or updated annotation '\ + 'in a PlanGrid project', help: { - body: 'New/updated annotations in Project trigger uses the' \ + body: 'New or updated annotation in project trigger uses the' \ " Retrieve " \ - ' annotations in a Project API.', + ' Annotations in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-annotations-in-a-project', learn_more_text: 'Retrieve Annotations in a Project' @@ -2471,17 +3055,17 @@ end }, new_updated_photos: { - title: 'New/updated photos in Project', - description: 'New/updated photos '\ - 'in Plangrid Project', + title: 'New or updated photo in a project', + description: 'New or updated photo '\ + 'in a PlanGrid project', help: { - body: 'New/updated photos in Project trigger uses the' \ + body: 'New or updated photo in a project trigger uses the' \ " Retrieve " \ ' photos in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-photos-in-a-project', - learn_more_text: 'Retrieve photos in a Project' + learn_more_text: 'Retrieve Photos in a Project' }, input_fields: lambda do |_object_definitions| [ @@ -2553,16 +3137,16 @@ end }, new_updated_snapshot: { - title: 'New/updated snapshot in a Project', - description: 'New/updated snapshot '\ - 'in a Project Plangrid', + title: 'New or updated snapshot in a project', + description: 'New or updated snapshot '\ + 'in a PlanGrid project', help: { - body: 'New/updated snapshot in a Project trigger uses the' \ + body: 'New or updated snapshot in a project trigger uses the' \ " Retrieve " \ + "retrieve-snapshots-in-a-project' target='_blank'>Retrieve " \ ' Snapshots in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'remove-snapshot-reference-in-rfi', + 'retrieve-snapshots-in-a-project', learn_more_text: 'Retrieve Snapshots in a Project' }, input_fields: lambda do |_object_definitions| @@ -2635,17 +3219,17 @@ end }, new_updated_field_report: { - title: 'New/updated field report in a Project', - description: 'New/updated field report '\ - 'in Plangrid Project', + title: 'New or updated field report in a project', + description: 'New or updated field report '\ + 'in a PlanGrid project', help: { - body: 'New/updated field report in Project trigger uses the' \ + body: 'New or updated field report in a project trigger uses the' \ " Retrieve " \ - 'field reports in a Project API.', + 'Field Reports in a Project API.', learn_more_url: 'https://developer.plangrid.com/docs/' \ 'retrieve-field-reports-in-a-project', - learn_more_text: 'Retrieve field reports in a Project' + learn_more_text: 'Retrieve Field Reports in a Project' }, input_fields: lambda do |_object_definitions| [ @@ -2698,14 +3282,12 @@ 'project_uid' => project_uid, 'updated_after' => now.to_time.utc.iso8601 } end - results = response['data']&. - map do |field_report| - field_report.merge({ 'pdf_form_fileds' => - field_report.delete('pdf_form_fileds')&. - map { |a| { a[0] => a[1] } }&.inject(:merge) }). - merge('project_uid' => project_uid) - end - field_reports = call('format_api_output_field_names', results) + + field_reports = response['data']&.map do |field_report| + field_report.merge({ + 'pdf_form_fields' => field_report['pdf_form_values'] + &.map { |a| { a['name'] => a['value'] } }&.inject(:merge) }) + end { events: field_reports || [], next_poll: closure, @@ -2725,11 +3307,11 @@ end }, new_updated_rfi: { - title: 'New/updated RFI in a Project', - description: 'New/updated RFI '\ - 'in a Plangrid Project', + title: 'New or updated RFI in a project', + description: 'New or updated RFI '\ + 'in a PlanGrid project', help: { - body: 'New/updated RFI in a Project trigger uses the' \ + body: 'New or updated RFI in a project trigger uses the' \ " Retrieve " \ ' RFIs in a Project API.', @@ -2818,12 +3400,14 @@ 'gov-state-local', 'other'].map { |type| [type.labelize, type] } end, project_folders: lambda do |_connection, project_uid:| - folders = get("/projects/#{project_uid}/attachments")['data']&. - pluck('folder')&.uniq - if folders.size > 0 - folders&.map { |folder| [folder || 'Root', folder || ''] } - else - [['Root', '']] + if project_uid.length === 36 + folders = get("/projects/#{project_uid}/attachments")['data']&. + pluck('folder')&.uniq + if folders.size > 0 + folders&.map { |folder| [folder || 'Root', folder || ''] } + else + [['Root', '']] + end end end } From 7c5ca29e120b27735d48fa412586d18a785642b7 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 6 Sep 2019 09:37:12 -0400 Subject: [PATCH 56/96] fix `project_uid` caching issue in triggers --- custom_connectors/oauth2/plangrid.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 253c77be..8de4fc9d 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2936,7 +2936,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{input.delete('project_uid')}/" \ + get("/projects/#{project_uid}/" \ 'issues'). params(limit: limit, skip: skip, @@ -3019,7 +3019,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{input.delete('project_uid')}/" \ + get("/projects/#{project_uid}/" \ 'annotations'). params(limit: limit, skip: skip, @@ -3101,7 +3101,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{input.delete('project_uid')}/" \ + get("/projects/#{project_uid}/" \ 'photos'). params(limit: limit, skip: skip, @@ -3183,7 +3183,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{input.delete('project_uid')}/" \ + get("/projects/#{project_uid}/" \ 'snapshots'). params(limit: limit, skip: skip, @@ -3265,7 +3265,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{input.delete('project_uid')}/" \ + get("/projects/#{project_uid}/" \ 'field_reports'). params(limit: limit, skip: skip, @@ -3353,7 +3353,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{input.delete('project_uid')}/" \ + get("/projects/#{project_uid}/" \ 'rfis'). params(limit: limit, skip: skip, From 5f0dc44e77aff37d5164d469f2bbe26810c50cca Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 6 Sep 2019 10:31:31 -0400 Subject: [PATCH 57/96] update triggers to pull from input `project_uid` instead of closure value --- custom_connectors/oauth2/plangrid.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 8de4fc9d..86a120f7 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2776,7 +2776,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{project_uid}/sheets"). + get("/projects/#{input['project_uid']}/sheets"). params(limit: limit, skip: skip, updated_after: updated_after) @@ -2856,7 +2856,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{project_uid}/attachments"). + get("/projects/#{input['project_uid']}/attachments"). params(limit: limit, skip: skip, updated_after: updated_after) @@ -2936,7 +2936,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{project_uid}/" \ + get("/projects/#{input['project_uid']}/" \ 'issues'). params(limit: limit, skip: skip, @@ -3019,7 +3019,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{project_uid}/" \ + get("/projects/#{input['project_uid']}/" \ 'annotations'). params(limit: limit, skip: skip, @@ -3101,7 +3101,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{project_uid}/" \ + get("/projects/#{input['project_uid']}/" \ 'photos'). params(limit: limit, skip: skip, @@ -3183,7 +3183,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{project_uid}/" \ + get("/projects/#{input['project_uid']}/" \ 'snapshots'). params(limit: limit, skip: skip, @@ -3265,7 +3265,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{project_uid}/" \ + get("/projects/#{input['project_uid']}/" \ 'field_reports'). params(limit: limit, skip: skip, @@ -3353,7 +3353,7 @@ response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) else - get("/projects/#{project_uid}/" \ + get("/projects/#{input['project_uid']}/" \ 'rfis'). params(limit: limit, skip: skip, From aece557f7ccdd611c6c87cd8d51b017f7445e0ce Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Fri, 6 Sep 2019 11:03:13 -0400 Subject: [PATCH 58/96] output `project_uid` from input instead of closure --- custom_connectors/oauth2/plangrid.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 86a120f7..042fbb94 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2791,7 +2791,7 @@ 'updated_after' => now.to_time.utc.iso8601 } end sheets = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } + map { |o| o.merge('project_uid' => input['project_uid']) } { events: sheets || [], next_poll: closure, @@ -2953,7 +2953,7 @@ 'updated_after' => now.to_time.utc.iso8601 } end tasks = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } + map { |o| o.merge('project_uid' => input['project_uid']) } { events: tasks || [], next_poll: closure, @@ -3035,7 +3035,7 @@ 'updated_after' => now.to_time.utc.iso8601 } end annotations = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } + map { |o| o.merge('project_uid' => input['project_uid']) } { events: annotations || [], next_poll: closure, @@ -3117,7 +3117,7 @@ 'updated_after' => now.to_time.utc.iso8601 } end photos = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } + map { |o| o.merge('project_uid' => input['project_uid']) } { events: photos || [], next_poll: closure, @@ -3199,7 +3199,7 @@ 'updated_after' => now.to_time.utc.iso8601 } end snapshots = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } + map { |o| o.merge('project_uid' => input['project_uid']) } { events: snapshots || [], next_poll: closure, @@ -3369,7 +3369,7 @@ 'updated_after' => now.to_time.utc.iso8601 } end rfis = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } + map { |o| o.merge('project_uid' => input['project_uid']) } { events: rfis || [], next_poll: closure, From 1291ccde5d8bc1b329dc35366e91f7585eeb553a Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 16 Mar 2020 15:22:39 -0400 Subject: [PATCH 59/96] update connector to code shared on 01.07.2020 --- custom_connectors/oauth2/plangrid.rb | 5021 ++++++++++---------------- 1 file changed, 1843 insertions(+), 3178 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 042fbb94..75e486bd 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -53,3361 +53,2026 @@ 'https://io.plangrid.com' end }, + test: ->(_connection) { get('/me') }, + object_definitions: { - project: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'uid', - type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'name', label: 'Project Name', sticky: true }, - { name: 'custom_id', label: 'Project Code', sticky: true }, - { name: 'organization_id', label: 'Organization ID' }, - { name: 'type', control_type: 'select', - label: 'Project Type', sticky: true, - pick_list: 'project_types', - toggle_hint: 'Select project type', - toggle_field: { - name: 'type', - label: 'Project type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Project type with possible values of general,' \ - ' manufacturing, power, water-sewer-waste, industrial-' \ - 'petroleum, transportation, hazardous-waste, telecom, ' \ - 'education-k-12, education-higher, gov-federal, ' \ - 'gov-state-local, or other' - } }, - { name: 'status', label: 'Project Status', sticky: true }, - { name: 'owner', sticky: true, label: 'Project Owner' }, - { name: 'start_date', type: 'date', - sticky: true, - render_input: 'date_conversion', - parse_output: 'date_conversion', - label: 'Project Start Date', - hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, - { name: 'end_date', type: 'date', - sticky: true, - render_input: 'date_conversion', - parse_output: 'date_conversion', - label: 'Project End Date', - hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, - { name: 'street_1', sticky: true, - label: 'Street Line 1' }, - { name: 'street_2', sticky: true, label: 'Street line 2' }, - { name: 'city', sticky: true, label: 'Town or City' }, - { name: 'region', sticky: true, label: 'State, Province, or Region' }, - { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, - { name: 'country', - sticky: true, - hint: 'Project address country in 2-letter ISO 3166 code.' }, - { name: 'latitude' }, - { name: 'longitude' }, - { name: 'updated_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion', - label: 'Updated at' } - ] + get_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'rfi_status' + [ + { name: 'limit', type: 'integer', control_type: 'integer', + hint: 'Number of RFI statuses to retrieve. Maximum value of 50.' }, + { name: 'skip', type: 'integer', control_type: 'integer', + hint: 'Number of RFI statuses to skip in the set of results.' } + ] + when 'field_report' + [ + { name: 'report_date_min', type: 'date', + label: 'Report Start Date', + hint: 'Only retrieve field reports between a date range starting with this date in UTC format.' }, + { name: 'report_date_max', type: 'date', + label: 'Report End Date', + hint: 'Only retrieve field reports between a date range ending with this date in UTC format.' }, + { name: 'updated_after', label: 'Updated After', type: 'date_time', + hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, + { + name: 'sort_by', label: 'Sort by column', control_type: 'select', + pick_list: + %w[report_date updated_at]&.map { |e| [e.labelize, e] }, + toggle_hint: 'Select column', + toggle_field: { + name: 'sort_by', label: 'Sort by column', type: 'string', control_type: 'text', + toggle_hint: 'Enter column', + hint: 'Allowed values report_date or updated_at.' + } + }, + { + name: 'sort_order', label: 'Sort by order', control_type: 'select', + pick_list: [%w[Ascending asc], %w[Descending desc]], + toggle_hint: 'Select order', + toggle_field: { + name: 'sort_by', label: 'Sort by order', type: 'string', control_type: 'text', + toggle_hint: 'Enter order', + hint: 'Allowed values Ascending or Descending.' + } + }, + { + name: 'output_schema', + control_type: 'schema-designer', + extends_schema: true, + label: 'PDF field values', + hint: 'Manually define the values expected of your PDF field values in the field report.', + optional: true + } + ] + when 'role', 'project' + [] + else + [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false, + hint: 'ID can be found at the end of the url.' }] + end end }, - document: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Document ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - sticky: true, + + get_output_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'project' + [ + { + name: 'uid', + control_type: 'select', + pick_list: 'project_list', label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'name', label: 'Document Name' }, - { name: 'folder' }, - { name: 'url' }, - { name: 'created_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'deleted', type: 'boolean' }, - { name: 'updated_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' } - ] - end - }, - task: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Task ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'number', type: 'number' }, - { name: 'title' }, - { name: 'status', control_type: 'select', pick_list: - %w[open in_review pending closed].select { |op| [op.labelize, op] }, - toggle_hint: 'Select status', - toggle_field: { - name: 'status', - label: 'Status', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are : "open", "in_review", "pending",' \ - ' "closed".' - } }, - { name: 'type', control_type: 'select', - pick_list: [ - %w[issue issue], - %w[Planned\ work planned_work], - %w[other other] - ], - toggle_hint: 'Select type', - toggle_field: { - name: 'type', - label: 'Type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: "issue", "planned_work",' \ - ' "other".' - } }, - { name: 'assignees', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'type' } - ] }, - { name: 'followers', label: 'Watchers', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'type' } - ] }, - { name: 'room', label: 'Location' }, - { name: 'start_date', label: 'Start Date', - type: 'date_time', - render_input: 'date_conversion', - parse_output: 'date_conversion' }, - { name: 'closed_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'due_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'string', label: 'Stamp', - hint: 'One to two character stamp associated with task.' }, - { name: 'issue_list', label: 'Task List', type: 'object', properties: [ - { name: 'uid', label: 'Task List ID' }, - { name: 'url' } - ] }, - { name: 'description' }, - { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, - { name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'cost_impact', - label: 'Cost impact', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'currency_code', label: 'Currency Code', - hint: 'The ISO-4217 currency code of the cost_impact,' \ - ' Currently only supports USD. maybe null if cost_impact is ' \ - 'not specified' }, - { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, - { name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'has_schedule_impact', - label: 'Has schedule impact', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'current_annotation', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'color' }, - { name: 'stamp' }, - { name: 'visibility' }, - { name: 'deleted', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_hint: 'Select project', + toggle_field: { + name: 'uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + }, + { name: 'name', label: 'Project Name', sticky: true }, + { name: 'custom_id', label: 'Project Code', sticky: true }, + { name: 'organization_id', label: 'Organization ID' }, + { + name: 'type', control_type: 'select', + label: 'Project Type', sticky: true, + pick_list: 'project_types', + toggle_hint: 'Select project type', toggle_field: { - name: 'deleted', - label: 'Deleted', + name: 'type', + label: 'Project type', type: 'string', control_type: 'text', toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' } - ] } - ] }, - { name: 'comments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] }, - { name: 'photos', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] }, - { name: 'deleted', label: 'Deleted?', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + hint: 'Project type with possible values of general,' \ + ' manufacturing, power, water-sewer-waste, industrial-' \ + 'petroleum, transportation, hazardous-waste, telecom, ' \ + 'education-k-12, education-higher, gov-federal, ' \ + 'gov-state-local, or other' + } + }, + { name: 'status', label: 'Project Status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project Owner' }, + { name: 'start_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project Start Date', + hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'end_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project End Date', + hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'street_1', sticky: true, + label: 'Street Line 1' }, + { name: 'street_2', sticky: true, label: 'Street line 2' }, + { name: 'city', sticky: true, label: 'Town or City' }, + { name: 'region', sticky: true, label: 'State, Province, or Region' }, + { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, + { name: 'country', + sticky: true, + hint: 'Project address country in 2-letter ISO 3166 code.' }, + { name: 'latitude' }, + { name: 'longitude' }, + { name: 'updated_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + label: 'Updated at' } + ] + when 'attachment' + [ + { name: 'uid', label: 'Document ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'name', label: 'Document Name' }, + { name: 'folder' }, { name: 'url' }, - { name: 'email' } - ] }, - { name: 'updated_at', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion', - type: 'date_time' }, - { name: 'updated_by', type: 'object', properties: [ + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'deleted', type: 'boolean', control_type: 'checkbox' } + ] + when 'issue' + [ + { name: 'uid', label: 'Task ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'number', type: 'integer' }, + { name: 'title' }, + { + name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending", "closed".' + } + }, + { + name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work", "other".' + } + }, + { + name: 'assignees', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'Assignee ID' }, + { name: 'type' } + ] + }, + { + name: 'followers', label: 'Watchers', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'Follower ID' }, + { name: 'type' } + ] + }, + { name: 'room', label: 'Location' }, + { name: 'start_date', label: 'Start Date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, + { name: 'closed_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'string', label: 'Stamp', + hint: 'One to two character stamp associated with task.' }, + { + name: 'issue_list', label: 'Task List', type: 'object', properties: [ + { name: 'uid', label: 'Task List ID' }, + { name: 'url' } + ] + }, + { name: 'description' }, + { name: 'cost_impact', label: 'Cost Impact', type: 'integer' }, + { + name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'currency_code', label: 'Currency Code', + hint: 'The ISO-4217 currency code of the cost_impact,' \ + ' Currently only supports USD. maybe null if cost_impact is ' \ + 'not specified' }, + { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, + { + name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', + control_type: 'checkbox' + }, + { + name: 'current_annotation', type: 'object', properties: [ + { name: 'uid', label: 'Annotation ID' }, + { name: 'color' }, + { name: 'stamp' }, + { name: 'visibility' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { + name: 'sheet', type: 'object', properties: [ + { name: 'uid', label: 'Sheet ID' }, + { name: 'url' } + ] + } + ] + }, + { + name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'updated_at', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + type: 'date_time' }, + { + name: 'updated_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] + } + ] + when 'file_upload' + [ { name: 'uid' }, + { + name: 'aws_post_form_arguments', type: 'object', + properties: [ + { name: 'action' }, + { name: 'fields', type: 'array', of: 'object', properties: [ + { name: 'name' }, + { name: 'value' } + ] } + ] + }, + { name: "project_uid", label: "Project ID" }, + { name: 'webhook_url' } + ] + when 'annotation' + [ + { name: 'uid', label: 'Annotation ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'color' }, + { name: 'stamp' }, + { name: 'visibility' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { + name: 'sheet', type: 'object', properties: [ + { name: 'uid', label: 'Sheet ID' }, + { name: 'url' } + ] + } + ] + when 'snapshot' + [ + { name: 'uid', label: 'Snapshot ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'title' }, { name: 'url' }, - { name: 'email' } - ] } - - ] - end - }, - file_upload: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid' }, - { name: 'aws_post_form_arguments', type: 'object', - properties: [ - { name: 'action' }, - { name: 'fields', type: 'array', of: 'object', properties: [ + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { + name: 'sheet', type: 'object', properties: [ + { name: 'uid', label: 'Sheet ID' }, + { name: 'url' } + ] + }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + } + ] + when 'photo' + [ + { name: 'uid', label: 'Photo ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'title' }, + { name: 'url', label: 'URL' }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'deleted', type: 'boolean' } + ] + when 'field_report' + [ + { name: 'uid', label: 'Field Report ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'title' }, + { name: 'description' }, + { name: 'report_date', label: 'Report Date', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'status' }, + { + name: 'field_report_type', label: 'Field Report Type', type: 'object', properties: [ + { name: 'name' }, + { name: 'status' }, + { name: 'uid', label: 'Field Report ID' }, + { name: 'project_uid' }, + { name: 'template_type' } + ] + }, + { name: 'pdf_url', label: 'PDF URL' }, + { + name: 'pdf_form_values', label: 'PDF Form Values', type: 'array', of: 'object', + properties: [ { name: 'name' }, { name: 'value' } - ] } - ] }, - { name: 'webhook_url' } - ] + ] + }, + { + name: 'pdf_form_fields', label: 'PDF Field Values', type: 'object' + }, + { + name: 'pg_form_values', type: 'object', properties: [ + { + name: 'pg_worklog_entries', label: 'Work Log Entries', type: 'array', of: 'object', + properties: [ + { name: 'trade' }, + { name: 'timespan' }, + { name: 'headcount', type: 'integer' }, + { name: 'description' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'uid' } + ] + }, + { + name: 'pg_materials_entries', label: 'Material Entries', type: 'array', of: 'object', + properties: [ + { name: 'unit', type: 'integer' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, + { name: 'description' }, + { name: 'deleted', type: "boolean", control_type: 'checkbox' }, + { name: 'uid' } + ] + }, + { + name: 'pg_equipment_entries', label: 'Equipment Entries', type: 'array', of: 'object', + properties: [ + { name: 'timespan' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, + { name: 'description' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'uid' } + ] + } + ] + }, + { + name: 'attachments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'snapshots', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'email' }, + { name: 'uid', label: 'UID' }, + { name: 'url' } + ] + }, + { name: 'updated_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'weather', type: 'object', properties: [ + { name: 'humidity', type: 'number' }, + { name: 'precipitation_accumulation', type: 'number' }, + { name: 'precipitation_accumulation_unit' }, + { name: 'speed_unit' }, + { name: 'summary_key' }, + { name: 'temperature_max', type: 'integer' }, + { name: 'temperature_min' }, + { name: 'temperature_unit' }, + { name: 'wind_bearing', type: 'integer' }, + { name: 'wind_gust', type: 'number' }, + { name: 'wind_speed', type: 'number' } + ] + } + ] + when 'rfi' + [ + { name: 'uid', label: 'RFI ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'number', type: 'integer' }, + { + name: 'status', type: 'object', properties: [ + { name: 'uid', label: 'Status ID' }, + { name: 'label' }, + { name: 'color' } + ] + }, + { + name: 'locked', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'title' }, + { name: 'question' }, + { name: 'answer' }, + { name: 'sent_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { name: 'due_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'assigned_to', type: 'array', of: 'object', + properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'updated_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { + name: 'updated_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { + name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'attachments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'snapshots', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + } + ] + when 'rfi_status' + [ + { name: 'uid', label: 'RFI status ID' }, + { name: 'label' }, + { name: 'color' }, + { name: "project_uid", label: "Project ID" } + ] + when 'user', 'user_invite' + [ + { name: 'uid', label: 'User ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'email' }, + { name: 'first_name', label: 'First Name' }, + { name: 'last_name', label: 'Last Name' }, + { name: 'language' }, + { + name: 'role', type: 'object', properties: [ + { name: 'uid', label: 'role ID' }, + { name: 'url' } + ] + }, + { name: 'removed', label: 'Removed?', type: 'boolean' } + ] + when 'sheet' + [ + { name: 'uid', label: 'Sheet ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'name' }, + { name: 'version_name', label: 'Version Name' }, + { name: 'description' }, + { name: 'tags', type: 'array', of: 'string', hint: 'An array of strings representing the' \ + ' tags added to this sheet.' }, + { + name: 'published_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'published_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'UTC date and time in ISO-8601 format.' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'uploaded_file_name', label: 'Uploaded file name' }, + { name: 'history_set_uid', label: 'History set ID' } + ] + when 'sheet_packet' + [ + { name: 'uid', label: 'Sheet Packet ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'status' }, + { name: 'file_url', label: 'File URL' }, + { + name: 'resource', type: 'object', properties: [ + { name: 'uid', label: 'Resource ID' }, + { name: 'url' } + ] + } + ] + when 'issue_list' + [ + { name: "uid", label: "Task List ID" }, + { name: "project_uid", label: "Project ID" }, + { name: "name", label: "Name" }, + { name: "deleted", label: "Deleted", type: "boolean", control_type: 'checkbox' } + ] + when 'role' + [ + { name: 'uid', label: 'Role ID' }, + { name: 'label', label: 'Role' }, + { name: "project_uid", label: "Project ID" } + ] + when 'sheet_upload' + [ + { name: 'uid', label: 'Sheet Version Upload ID' }, + { name: 'complete_url', label: 'Upload Completion URL' }, + { name: 'status' }, + { name: "project_uid", label: "Project ID" }, + { + name: 'file_upload_requests', label: 'File Upload Requests', + type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'File Upload ID' }, + { name: 'upload_status', label: 'File Upload Status' }, + { name: 'url', label: 'File Upload URL' } + ] + } + ] + when 'version_upload' + [ + { name: 'uid', label: 'Sheet Version ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'status', label: 'Status' } + ] + end end }, - annotation: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Annotation ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', + + create_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'project' + [ + { name: 'name', label: 'Project Name', sticky: true, optional: false }, + { name: 'custom_id', label: 'Project Code', sticky: true }, + { + name: 'type', control_type: 'select', + label: 'Project Type', sticky: true, + pick_list: 'project_types', + toggle_hint: 'Select project type', + toggle_field: { + name: 'type', + label: 'Project type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Project type with possible values of general,' \ + ' manufacturing, power, water-sewer-waste, industrial-' \ + 'petroleum, transportation, hazardous-waste, telecom, ' \ + 'education-k-12, education-higher, gov-federal, ' \ + 'gov-state-local, or other' + } + }, + { name: 'status', label: 'Project Status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project Owner' }, + { name: 'start_date', type: 'date', sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'color' }, - { name: 'stamp' }, - { name: 'visibility' }, - { name: 'deleted', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' } - ] } - ] - end - }, - snapshot: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Snapshot ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'title' }, - { name: 'url' }, - { name: 'created_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' } - ] }, - { name: 'deleted', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } } - ] - end - }, - photo: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Photo ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'title' }, - { name: 'url', label: 'URL' }, - { name: 'created_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'deleted', type: 'boolean' } - ] - end - }, - field_report: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Field Report ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'title' }, - { name: 'description' }, - { name: 'report_date', label: 'Report Date', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'status' }, - { name: 'field_report_type', label: 'Field Report Type', type: 'object', properties: [ - { name: 'name' }, - { name: 'status' }, - { name: 'uid', label: 'UID' } - ] }, - { name: 'pdf_url', label: 'PDF URL' }, - { name: 'pdf_form_values', label: 'PDF Form Values', type: 'array', of: 'object', properties: [ - { name: 'name', label: 'Field Name' }, - { name: 'value', label: 'Field Value' } - ]}, - { name: 'pdf_form_fields', label: 'PDF Field Values', type: 'object' }, - { name: 'pg_form_values', label: 'Daily Report Values', type: 'array', of: 'object', properties: [ - { name: 'pg_worklog_entries', label: 'Work Log Entries', type: 'array', of: 'object', - properties: [ - { name: 'trade' }, - { name: 'timespan' }, - { name: 'headcount', type: 'integer' }, - { name: 'description' }, - { name: 'deleted', type: 'boolean', - control_type: 'checkbox', - toggle_hint: 'Select from options list', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } } - ] }, - { name: 'pg_materials_entries', label: 'Material Entries', type: 'array', of: 'object', - properties: [ - { name: 'unit', type: 'integer' }, - { name: 'quantity', type: 'integer' }, - { name: 'item' }, - { name: 'description' }, - { name: 'deleted' } - ] }, - { name: 'pg_equipment_entries', label: 'Equipment Entries', type: 'array', of: 'object', - properties: [ - { name: 'timespan' }, - { name: 'quantity', type: 'integer' }, - { name: 'item' }, - { name: 'description' }, - { name: 'deleted', type: 'boolean', - control_type: 'checkbox', - toggle_hint: 'Select from options list', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } } - ] } - ] }, - { name: 'attachments', label: 'Documents', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] }, - { name: 'photos', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] }, - { name: 'snapshots', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] }, - { name: 'created_by', type: 'object', properties: [ - { name: 'email' }, - { name: 'uid', label: 'UID' }, - { name: 'url' } - ] }, - { name: 'updated_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'weather', type: 'object', properties: [ - { name: 'humidity', type: 'number' }, - { name: 'precipitation_accumulation', type: 'number' }, - { name: 'precipitation_accumulation_unit' }, - { name: 'speed_unit' }, - { name: 'summary_key' }, - { name: 'temperature_max', type: 'integer' }, - { name: 'temperature_min' }, - { name: 'temperature_unit' }, - { name: 'wind_bearing', type: 'integer' }, - { name: 'wind_gust', type: 'number' }, - { name: 'wind_speed', type: 'number' } - ] } - ] - end - }, - rfi: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'RFI ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'number', type: 'integer' }, - { name: 'status', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'label' }, - { name: 'color' } - ] }, - { name: 'locked', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'locked', - label: 'Locked', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'title' }, - { name: 'question' }, - { name: 'answer' }, - { name: 'sent_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - hint: 'Date when the RFI was sent. See ' \ - "Timestamps and " \ - 'Timezones for accepted date formats' }, - { name: 'due_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'assigned_to', type: 'array', of: 'object', - properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'updated_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - hint: 'Date when the RFI was sent. See ' \ - "Timestamps and " \ - 'Timezones for accepted date formats' }, - { name: 'updated_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'created_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'photos', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] }, - { name: 'attachments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] }, - { name: 'snapshots', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] }, - { name: 'comments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] } - ] - end - }, - rfi_status: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Status ID' }, - { name: 'label' }, - { name: 'color' } - ] - end - }, - user: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'User ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project Start Date', + hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'end_date', type: 'date', sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'email' }, - { name: 'first_name', label: 'First Name' }, - { name: 'last_name', label: 'Last Name' }, - { name: 'language'}, - { name: 'role', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' } - ] }, - { name: 'removed', label: 'Removed?' } - ] - end - }, - sheet: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Sheet ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project End Date', + hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'street_1', sticky: true, + label: 'Street Line 1' }, + { name: 'street_2', sticky: true, label: 'Street line 2' }, + { name: 'city', sticky: true, label: 'Town or City' }, + { name: 'region', sticky: true, label: 'State, Province, or Region' }, + { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, + { name: 'country', sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'name' }, - { name: 'version_name', label: 'Version Name' }, - { name: 'description' }, - { name: 'tags', type: 'array', of: 'string', hint: 'An array of strings representing the' \ - ' tags added to this sheet.' }, - { name: 'published_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] }, - { name: 'published_at', type: 'date_time', - render_input: 'parse_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - hint: 'UTC date and time in ISO-8601 format.' }, - { name: 'deleted', type: 'boolean', - control_type: 'checkbox', - toggle_hint: 'Select from options list', - toggle_field: { - name: 'deleted', - label: 'Deleted', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - { name: 'uploaded_file_name', label: 'Uploaded file name' } - ] - end - }, - sheet_packet: { - fields: lambda do |_connection, _config_fields| - [ - { name: 'uid', label: 'Sheet Packet ID' }, - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', + hint: 'Project address country in 2-letter ISO 3166 code.' }, + { + name: 'add_to_organization', type: 'boolean', sticky: true, + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'add_to_organization', + label: 'Add to Organization', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + } + ] + when 'rfi' + [ + { + name: 'locked', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'locked', + label: 'Locked', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'title', optional: false }, + { name: 'question' }, + { name: 'answer' }, + { name: 'sent_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { name: 'due_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, + { name: 'status', label: 'Status', + hint: "Uid's of the RFI's initial status. Defaults to the first RFI status in the project" } + ] + when 'issue' + [ + { name: 'title' }, + { + name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending", "closed".' + } + }, + { + name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work", "other".' + } + }, + { name: 'room', label: 'Location' }, + { name: 'start_date', label: 'Start Date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'description' }, + { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, + { + name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_cost_impact', + label: 'Has cost impact?', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, + { + name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_schedule_impact', + label: 'Has schedule impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, + { name: 'issue_list_uid', label: 'Task List ID', sticky: true } + ] + when 'sheet_packet' + [ + { name: 'sheet_uids', label: 'Sheet IDs', optional: false, type: 'string', - control_type: 'text', - sticky: true, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'status' }, - { name: 'file_url', label: 'File URL' }, - { name: 'resource', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' } - ] } - ] - end - }, - custom_action_input: { - fields: lambda do |_connection, config_fields| - input_schema = parse_json(config_fields.dig('input', 'schema') || '[]') - - [ - { - name: 'path', - optional: false, - hint: 'Base URI is https://io.plangrid.com' \ - ' - path will be appended to this URI. ' \ - 'Use absolute URI to override this base URI.' - }, - ( - if %w[get delete].include?(config_fields['verb']) - { - name: 'input', - type: 'object', - control_type: 'form-schema-builder', - sticky: input_schema.blank?, - label: 'URL parameters', - add_field_label: 'Add URL parameter', - properties: [ - { - name: 'schema', - extends_schema: true, - sticky: input_schema.blank? - }, - ( - if input_schema.present? - { - name: 'data', - type: 'object', - properties: call('make_schema_builder_fields_sticky', - input_schema) - } - end - ) - ].compact + hint: 'A comma separated list of sheet IDs.' }, + { + name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'include_annotations', + label: 'Include annotations?', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' } - else + }, + ] + when 'issue_list' + [ + { name: 'name', optional: false } + ] + when 'sheet_upload' + [ + { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, + { name: 'version_name', label: 'Version Name', optional: false } + ] + when 'user_invite' + [ + { name: 'email', optional: false }, + { name: 'role_uid', label: 'Role ID', sticky: true, + hint: 'Unique identifier of role to assign user on project team' }, + { name: 'first_name' }, + { name: 'last_name' }, + { name: 'language' } + ] + else + [] + end.concat( + if config_fields['object'] != 'project' + [ { - name: 'input', - type: 'object', - properties: [ - { - name: 'schema', - extends_schema: true, - schema_neutral: true, - control_type: 'schema-designer', - sample_data_type: 'json_input', - sticky: input_schema.blank?, - label: 'Request body parameters', - add_field_label: 'Add request body parameter' - }, - ( - if input_schema.present? - { - name: 'data', - type: 'object', - properties: call('make_schema_builder_fields_sticky', - input_schema) - } - end - ) - ].compact + name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + hint: 'If your project is not in top 50, use project ID toggle', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } } - end - ), - { - name: 'output', - control_type: 'schema-designer', - sample_data_type: 'json_http', - extends_schema: true, - schema_neutral: true, - sticky: true - } - ] + ] + else + [] + end + ) end }, - custom_action_output: { + + update_input_schema: { fields: lambda do |_connection, config_fields| - parse_json(config_fields['output'] || '[]') - end - } - }, - actions: { - custom_action: { - description: "Custom action " \ - "in Plangrid", - help: { - body: 'Build your own Plangrid action for any Plangrid ' \ - 'REST endpoint.', - learn_more_url: 'https://developer.plangrid.com/docs/', - learn_more_text: 'The Plangrid API documentation' - }, - config_fields: [{ - name: 'verb', - label: 'Request type', - hint: 'Select HTTP method of the request', - optional: false, - control_type: 'select', - pick_list: %w[get post patch delete].map { |verb| [verb.upcase, verb] } - }], - - input_fields: lambda do |object_definitions| - object_definitions['custom_action_input'] - end, - - execute: lambda do |_connection, input| - verb = input['verb'] - error("#{verb} not supported") if %w[get post put delete].exclude?(verb) - data = input.dig('input', 'data').presence || {} - case verb - when 'get' - response = - get(input['path'], data). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end.compact - - if response.is_a?(Array) - array_name = parse_json(input['output'] || '[]'). - dig(0, 'name') || 'array' - { array_name.to_s => response } - elsif response.is_a?(Hash) - response - else - error('API response is not a JSON') - end - when 'post' - post(input['path'], data). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end.compact - when 'patch' - patch(input['path'], data). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end.compact - when 'delete' - delete(input['path'], data). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end.compact - end - end, - output_fields: lambda do |object_definitions| - object_definitions['custom_action_output'] - end - }, - create_project: { - title: 'Create project', - description: 'Create project in'\ - ' PlanGrid', - help: { - body: 'Create project action uses the' \ - " Create Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/create-project', - learn_more_text: 'Create Project' - }, - input_fields: lambda do |object_definitions| - [ - { name: 'add_to_organization', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'add_to_organization', - label: 'Add to Organization', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } - } - ].concat(object_definitions['project']. - ignored('uid', 'updated_at', 'latitude', 'longitude', - 'organization_id'). - required('name')) - end, - execute: lambda do |_connection, input| - payload = input.each do |key, value| - input[key].present? || input[key] = nil - end - post('projects').payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end - end, - output_fields: lambda do |object_definitions| - object_definitions['project'] - end, - sample_output: lambda do |_connection, _input| - get('/projects')&.dig('data', 0) || {} - end - }, - update_project: { - title: 'Update project', - description: 'Update project in'\ - ' PlanGrid', - help: { - body: 'Update project action uses the' \ - " Update Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/update-project', - learn_more_text: 'Update Project' - }, - input_fields: lambda do |object_definitions| - object_definitions['project'].required('uid'). - ignored('updated_at', 'latitude', 'longitude', 'organization_id') - end, - execute: lambda do |_connection, input| - payload = input.each do |key, value| - input[key].present? || input[key] = nil - end - patch("/projects/#{input.delete('uid')}").payload(payload.except('uid')). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end - end, - output_fields: lambda do |object_definitions| - object_definitions['project'] - end, - sample_output: lambda do |_connection, _input| - get('/projects')&.dig('data', 0) || {} - end - }, - get_project_details: { - title: 'Get project', - description: 'Get project'\ - ' in PlanGrid', - help: { - body: 'Get project action uses the' \ - " Retrieve a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-a-project', - learn_more_text: 'Retrieve a Project' - }, - input_fields: lambda do |object_definitions| - object_definitions['project'].only('uid').required('uid') - end, - execute: lambda do |_connection, input| - get("/projects/#{input['uid']}") - end, - output_fields: lambda do |object_definitions| - object_definitions['project'] - end, - sample_output: lambda do |_connection, _input| - get('/projects')&.dig('data', 0) || {} - end - }, - upload_document: { - title: 'Upload document to a project', - description: 'Upload document to a'\ - ' PlanGrid project', - help: { - body: 'Upload document to a project action uses the' \ - " Upload Document to Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/upload-' \ - 'attachment-to-project', - learn_more_text: 'Upload Document to Project API' - }, - summarize_input: %w[file_content], - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'content_type', - hint: 'Content type of the document\'s file. e.g. for pdf' \ - ' application/pdf', optional: false }, - { name: 'file_content', optional: false }, - { name: 'name', optional: false, - label: 'Document name', - hint: 'Name of the document.' }, - { name: 'folder', label: 'Folder', sticky: true, - control_type: 'select', - pick_list: 'project_folders', - pick_list_params: { project_uid: 'project_uid' }, - toggle_hint: 'Select folder', - hint: 'Folder shows in select options only if at least one file' \ - ' exist in the folder', - toggle_field: { - name: 'folder', - label: 'Project folder', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Folder in project to place the document ' \ - '(case-sensitive). Leave blank to select root folder' - } }, - { name: 'auto_version', type: 'boolean', sticky: true, - control_type: 'checkbox', - toggle_hint: 'Select from options list', - toggle_field: { - name: 'auto_version', - type: 'boolean', - control_type: 'text', - label: 'Auto version', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } } - ] - end, - execute: lambda do |_connection, input| - file_content = input.delete('file_content') - project_uid = input['project_uid'] - payload = input.except(:project_uid) - file_upload_info = post("/projects/#{project_uid}/" \ - 'attachments/uploads'). - headers('Content-type': 'application/json'). - payload(payload) - url = file_upload_info&.dig('aws_post_form_arguments', 'action') - fields = file_upload_info&.dig('aws_post_form_arguments', 'fields') - # webhook_url = file_upload_info. - # dig('aws_post_form_arguments', 'webhook_url') - headers = fields.map { |o| { o['name'] => o['value'] } }.inject(:merge) - status = - post(url). - payload(key: headers['key'], - policy: headers['policy'], - signature: headers['signature'], - AWSAccessKeyId: headers['AWSAccessKeyId'], - 'content-type': headers['Content-Type'], - 'success_action_redirect': headers['success_action_redirect'], - 'x-amz-server-side-encryption': - headers['x-amz-server-side-encryption'], - 'x-amz-storage-class': headers['x-amz-storage-class'], - file: file_content). - request_format_multipart_form. - after_response do |_code, response, _response_headers| - response - end - status.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['document'] - end, - sample_output: lambda do |_connection, _input| - { - uid: '147a420e-a182-4312-8fa5-4d10064d2f1a', - name: 'Bender', - folder: 'Specifications', - url: 'https://attachment-assets.plangrid.com/147a420e-a182-' \ - '4312-8fa5-4d10064d2f1a.pdf', - created_at: '2013-05-17T02:30:22+00:00', - created_by: { - uid: null, - url: null, - email: 'nick@subcontractor.com' - }, - deleted: false - } - end - }, - update_document: { - title: 'Update document in a project', - description: 'Update document in a'\ - ' PlanGrid project', - help: { - body: 'Update document in a project action uses the' \ - " Update Document to Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/update-attachment-' \ - 'in-a-project', - learn_more_text: 'Update Document in a Project API' - }, - summarize_input: %w[file_content], - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'attachment_uid', label: 'Document ID', optional: false }, - { name: 'name', label: 'Document Name', - hint: 'New name of the document', sticky: true }, - { name: 'folder', label: 'Folder', - hint: 'New folder of the document', sticky: true } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - patch("/projects/#{project_uid}/attachments/" \ - "#{input.delete('attachment_uid')}"). - headers('Content-type': 'application/json'). - payload(input). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['document'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/attachments")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - create_rfi: { - title: 'Create RFI in a project', - description: 'Create RFI in'\ - ' a PlanGrid project ', - help: { - body: 'Create RFI in a project action uses the ' \ - "Create RFI in Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/create-rfi-' \ - 'in-a-project', - learn_more_text: 'Create RFI in a Project' - }, - input_fields: lambda do |object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'status', label: 'Status', - hint: 'Use this for create and update rfi status' } - ].concat(object_definitions['rfi']. - only('locked', 'title', 'question', 'answer', 'sent_at', - 'due_at', 'assigned_to_uids'). - required('title')) - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - payload = input&.map do |key, val| - if %w[due_at sent_at].include?(key) - { key => val.to_time.utc.iso8601 } - else - { key => val } - end - end&.inject(:merge) - post("/projects/#{project_uid}/rfis").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['rfi'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/rfis")&.dig('data', 0) || {} - end - }, - update_rfi: { - title: 'Update RFI in a project', - description: 'Update RFI in'\ - ' a PlanGrid project', - help: { - body: 'Update RFI in a project action uses the ' \ - "Update RFI in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/update-' \ - 'rfi-in-a-project', - learn_more_text: 'Update RFI in a Project' - }, - input_fields: lambda do |object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'status', label: 'Status UID' } - ].concat(object_definitions['rfi']. - only('uid', 'locked', 'title', 'question', 'answer', 'sent_at', - 'due_at', 'assigned_to_uids'). - required('uid')) - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - rfi_id = input.delete('uid') - payload = input&.map do |key, val| - if %w[due_at sent_at].include?(key) - { key => val.to_time.utc.iso8601 } - else - { key => val } - end - end&.inject(:merge) - patch("/projects/#{project_uid}/rfis/#{rfi_id}").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['rfi'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/rfis")&.dig('data', 0) || {} - end - }, - get_rfi_in_project: { - title: 'Get RFI in a project', - description: 'Get RFI in '\ - 'a PlanGrid project', - help: { - body: 'Get RFI in a project action uses the' \ - " Retrieve RFI in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/" \ - "retrieve-rfis-in-a-project', - learn_more_text: 'Retrieve RFI in a Project' - }, - input_fields: lambda do |object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'rfi_uid', label: 'RFI ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - get("/projects/#{project_uid}/rfis/#{input['rfi_uid']}")&. - merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['rfi'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/rfis")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - create_task: { - title: 'Create task in a project', - description: 'Create task in'\ - ' a PlanGrid project', - help: { - body: 'Create task in a project action uses the ' \ - "Create Task in Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/create-task-in-' \ - 'a-project', - learn_more_text: 'Create Task in a Project' - }, - input_fields: lambda do |object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } - }, - { name: 'issue_list_uid', label: 'Task List ID', sticky: true } - ].concat(object_definitions['task']. - only('title', 'status', 'type', 'assigned_to_uids', - 'room', 'start_date', 'due_at', - 'description', 'has_cost_impact', 'cost_impact', - 'has_schedule_impact', 'schedule_impact' - )) - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - payload = input&.map do |key, val| - if %w[due_at].include?(key) - { key => val.to_time.utc.iso8601 } - else - { key => val } - end - end&.inject(:merge) - post("/projects/#{project_uid}/issues").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['task'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/issues")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - update_task: { - title: 'Update task in a project', - description: 'Update task in'\ - ' a PlanGrid project', - help: { - body: 'Update task in a project action uses the ' \ - "Update Task in Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/create-project', - learn_more_text: 'Update Task in a Project' - }, - input_fields: lambda do |object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g.' \ - ' 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } - }, - { name: 'issue_uid', label: 'Task ID', optional: false }, - { name: 'issue_list_uid', label: 'Task List ID', sticky: true } - ].concat(object_definitions['task']. - only('title', 'status', 'type', 'assigned_to_uids', - 'room', 'start_date', 'due_at', - 'description', 'has_cost_impact', 'cost_impact', - 'has_schedule_impact', 'schedule_impact' - )) - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - payload = input.each do |key, value| - input[key].present? || input[key] = nil - end - patch("/projects/#{project_uid}/issues/" \ - "#{input.delete('issue_uid')}").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['task'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/issues")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - get_task: { - title: 'Get task in a project', - description: 'Get task in'\ - ' a PlanGrid project', - help: { - body: 'Get task in a project action uses the ' \ - "Retrieve Task in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'issues-in-a-project', - learn_more_text: 'Retrieve Task in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'issue_uid', label: 'Task ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - get("/projects/#{project_uid}/issues/" \ - "#{input['issue_uid']}"). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['task'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/issues")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - invite_user_to_project: { - title: 'Invite user to a project', - description: 'Invite user to'\ - ' a PlanGrid project', - help: { - body: 'Invite user to a project action uses the ' \ - "Invite User in Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'invite-user-to-project-team', - learn_more_text: 'Invite User to Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'email', optional: false }, - { name: 'role_uid', label: 'Role ID', sticky: true, - hint: 'Unique identifier of role to assign user on project team' } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - post("/projects/#{project_uid}/users/invites"). - payload(input). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['user'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/users")&.dig('data', 0) || {} - end - }, - get_user_in_project: { - title: 'Get user in project', - description: 'Get user in'\ - ' a PlanGrid project', - help: { - body: 'Get user in a project action uses the ' \ - "Retrieve User in a Project.", - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'users-on-a-project-team', - learn_more_text: 'Retrieve User in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'user_uid', label: 'User ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/users/" \ - "#{input['user_uid']}") - end, - output_fields: lambda do |object_definitions| - object_definitions['user'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/users")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - get_snapshot_in_project: { - title: 'Get snapshot in a project', - description: 'Get snapshot in'\ - ' a PlanGrid project', - help: { - body: 'Get snapshot in a project action uses the ' \ - "Retrieve Snapshot in a Project.", - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'snapshot-in-a-project', - learn_more_text: 'Retrieve Snapshot in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'snapshot_uid', label: 'Snapshot ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/snapshots/" \ - "#{input['snapshot_uid']}")&.merge('project_uid' => input['project_uid']) - end, - output_fields: lambda do |object_definitions| - object_definitions['snapshot'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/snapshots")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - get_rfi_statuses_in_project: { - title: 'Get RFI statuses in project', - description: 'Get RFI statuses in'\ - ' a PlanGrid project', - help: { - body: 'Get RFI statuses in project action uses the ' \ - "Retrieve RFI Statuses in a Project.", - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'rfi-statuses-in-a-project', - learn_more_text: 'Retrieve RFI Statuses in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'limit', type: 'integer', - hint: 'Number of RFI statuses to retrieve. Maximum value of 50.' }, - { name: 'skip', type: 'integer', - hint: 'Number of RFI statuses to skip in the set of results.' } - ] - end, - execute: lambda do |_connection, input| - { statuses: - get("/projects/#{input['project_uid']}/rfis/statuses")['data'] } - end, - output_fields: lambda do |object_definitions| - [ - { name: 'statuses', type: 'array', of: 'object', - properties: object_definitions['rfi_status'] } - ] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/rfis/statuses")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - get_roles_on_project: { - title: 'Get roles in a project', - description: 'Get roles in '\ - ' a PlanGrid project', - help: { - body: 'Get roles in a project action uses the ' \ - "Retrieve Roles on a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-roles-on-a-project', - learn_more_text: 'Retrieves Role on a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - { roles: get("/projects/#{project_uid}/roles")['data'] } - end, - output_fields: lambda do |_object_definitions| - [ - { name: 'roles', label: 'Roles', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'label', label: 'Role' } - ] } - ] - end, - sample_output: lambda do |_connection, _input| - { 'roles' => { 'uid' => '9d139e64-cac9-4f23-b4d5-9fd3688b498e', - 'label' => 'Admin' } } - end - }, - - get_sheet_in_project: { - title: 'Get sheet in a project', - description: 'Get sheet in '\ - 'a PlanGrid project', - help: { - body: 'Get sheet in a project action uses the ' \ - "Retrieve Sheet in a Project.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-a-sheet', - learn_more_text: 'Retrieve Sheet in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'sheet_uid', label: 'Sheet ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/sheets/#{input['sheet_uid']}")&. - merge('project_uid' => input['project_uid']) - end, - output_fields: lambda do |object_definitions| - object_definitions['sheet'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/sheets?limit=1")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - get_project_sheet_packet: { - title: 'Get sheet packet in a project', - description: 'Get sheet packet in'\ - ' a PlanGrid project', - help: { - body: 'Get sheet packet in a project action uses the ' \ - "Retrieve Sheet Packet API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-sheet-packet', - learn_more_text: 'Retrieve Sheet Packet' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'packet_uid', label: 'Sheet Packet ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/sheets/packets/" \ - "#{input['packet_uid']}")&.merge('project_uid' => input['project_uid']) - end, - output_fields: lambda do |object_definitions| - object_definitions['sheet_packet'] - end - }, - get_field_reports_in_project: { - title: 'Get field reports in a project', - description: 'Get field reports in'\ - ' a PlanGrid project', - help: { - body: 'Get field reports in a project action uses the ' \ - "Retrieve Field Reports in a" \ - ' Project API.', - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'field-reports-in-a-project', - learn_more_text: 'Retrieve Field Reports in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'report_date_min', type: 'date', - label: 'Report Start Date', - hint: 'Only retrieve field reports between a date range ' \ - 'starting with this date in UTC format.' }, - { name: 'report_date_max', type: 'date', - label: 'Report End Date', - hint: 'Only retrieve field reports between a date range ' \ - 'starting with this date in UTC format.' }, - { name: 'updated_after', label: 'Updated After', type: 'date_time', - hint: 'Only retrieve field reports created/updated after ' \ - 'specified UTC date and time.' }, - { name: 'sort_by', control_type: 'select', - pick_list: - %w[report_date updated_at]&.map { |e| [e.labelize, e] }, - toggle_hint: 'Select sort by column', - toggle_field: { - name: 'sort_by', type: 'string', control_type: 'text', - hint: 'Allowed values report_date or updated_at' - } }, - { name: 'sort_order', control_type: 'select', - pick_list: - %w[asc desc]&.map { |e| [e.labelize, e] }, - toggle_hint: 'Select sort order', - toggle_field: { - name: 'sort_by', type: 'string', control_type: 'text', - hint: 'Allowed values asc or desc' - } } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - query_params = '' - input&.map do |key, val| - if %w[updated_after].include?(key) - query_params = query_params + "&" + "#{key}=#{val.to_time.utc.iso8601}" - else - query_params = query_params + "&" + "#{key}=#{val}" - end - end - - results = get("/projects/#{project_uid}/field_reports?" \ - "#{query_params}")['data'] - - field_reports = results.map do |field_report| - field_report.merge({ - 'pdf_form_fields' => field_report['pdf_form_values'] - &.map { |a| { a['name'] => a['value'] } }&.inject(:merge) }) - end - { field_reports: field_reports } - - end, - output_fields: lambda do |object_definitions| - { name: 'field_reports', label: 'Field Reports', type: 'array', of: 'object', - properties: object_definitions['field_report'] } - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - { field_reports: - get("/projects/#{id}/rfis/field_reports")&. - merge('project_uid' => id) || {} } - end - }, - upload_photo: { - title: 'Upload photo to a project', - description: 'Upload photo to '\ - ' a PlanGrid project', - help: { - body: 'Upload photo to a project action uses the' \ - " Upload Photo to Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/upload-photo' \ - '-to-project', - learn_more_text: 'Upload Photo to Project' - }, - summarize_input: %w[file_content], - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'content_type', optional: false, - hint: "Content type of the photo's file" }, - { name: 'file_content', optional: false }, - { name: 'title', optional: false, label: 'Photo title' } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - file_content = input.delete('file_content') - payload = input.except(:project_uid) - file_upload_info = post("/projects/#{project_uid}/" \ - 'photos/uploads'). - headers('Content-type': 'application/json'). - payload(payload) - url = file_upload_info&.dig('aws_post_form_arguments', 'action') - fields = file_upload_info&.dig('aws_post_form_arguments', 'fields') - # webhook_url = file_upload_info. - # dig('aws_post_form_arguments', 'webhook_url') - headers = fields.map { |o| { o['name'] => o['value'] } }.inject(:merge) - post(url). - payload(key: headers['key'], - policy: headers['policy'], - signature: headers['signature'], - AWSAccessKeyId: headers['AWSAccessKeyId'], - 'content-type': headers['Content-Type'], - 'success_action_redirect': headers['success_action_redirect'], - 'x-amz-server-side-encryption': - headers['x-amz-server-side-encryption'], - 'x-amz-storage-class': headers['x-amz-storage-class'], - file: file_content). - request_format_multipart_form. - after_response do |_code, response, _response_headers| - response - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['photo'] - end, - sample_output: lambda do |_connection, _input| - { - uid: '147a420e-a182-4312-8fa5-4d10064d2f1a', - title: 'Bongo Drums', - url: 'https://attachment-assets.plangrid.com/147a420e-a182-' \ - '4312-8fa5-4d10064d2f1a.pdf', - created_at: '2013-05-17T02:30:22+00:00', - created_by: { - uid: null, - url: null, - email: 'nick@subcontractor.com' - }, - deleted: false - } - end - }, - update_photo_metadata: { - title: 'Update photo in a project', - description: 'Update photo in'\ - ' a PlanGrid project', - help: { - body: 'Update photo action uses the' \ - " Update Photo in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/update-photo-' \ - 'in-a-project', - learn_more_text: 'Update Photo in a Project API' - }, - summarize_input: %w[file_content], - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'photo_uid', label: 'Photo ID', optional: false }, - { name: 'title', label: 'Photo title', - hint: 'New title of the photo', sticky: true } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - patch("/projects/#{project_uid}/photos/" \ - "#{input.delete('photo_uid')}"). - headers('Content-type': 'application/json'). - payload(input). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['photo'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/photos")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - get_photo_details: { - title: 'Get photo in a project', - description: 'Get photo in'\ - ' a PlanGrid project', - help: { - body: 'Get photo action uses the ' \ - "Retrieve Photo in Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-a-sheet', - learn_more_text: 'Retrieve Photo in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'photo_uid', label: 'Photo ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/photos/" \ - "#{input['photo_uid']}")&.merge('project_uid' => input.delete('project_uid')) - end, - output_fields: lambda do |object_definitions| - object_definitions['photo'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/photos")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - get_document_details: { - title: 'Get document in a project', - description: 'Get document'\ - ' in a PlanGrid project', - help: { - body: 'Get document in a project action uses the ' \ - "Retrieve Document in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-a-sheet', - learn_more_text: 'Retrieve Document in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', + case config_fields['object'] + when 'project' + [ + { name: 'name', label: 'Project Name', sticky: true }, + { name: 'custom_id', label: 'Project Code', sticky: true }, + { + name: 'type', control_type: 'select', + label: 'Project Type', sticky: true, + pick_list: 'project_types', + toggle_hint: 'Select project type', + toggle_field: { + name: 'type', + label: 'Project type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Project type with possible values of general,' \ + ' manufacturing, power, water-sewer-waste, industrial-' \ + 'petroleum, transportation, hazardous-waste, telecom, ' \ + 'education-k-12, education-higher, gov-federal, ' \ + 'gov-state-local, or other' + } + }, + { name: 'status', label: 'Project Status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project Owner' }, + { name: 'start_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project Start Date', + hint: 'Project start date. ISO-8601 date format (DD-MM-YYYY).' }, + { name: 'end_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project End Date', + hint: 'Project end date. ISO-8601 date format (DD-MM-YYYY).' }, + { name: 'street_1', sticky: true, + label: 'Street Line 1' }, + { name: 'street_2', sticky: true, label: 'Street line 2' }, + { name: 'city', sticky: true, label: 'Town or City' }, + { name: 'region', sticky: true, label: 'State, Province, or Region' }, + { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, + { name: 'country', + sticky: true, + hint: 'Project address country in 2-letter ISO 3166 code.' } + ] + when 'rfi' + [ + { + name: 'locked', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'locked', + label: 'Locked', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'title', optional: false }, + { name: 'question' }, + { name: 'answer' }, + { name: 'sent_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { name: 'due_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, + { name: 'status', label: 'Status', + hint: "Uid's of the RFI's initial status. Defaults to the first RFI status in the project" } + ] + when 'issue' + [ + { name: 'title' }, + { + name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending", "closed".' + } + }, + { + name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work", "other".' + } + }, + { name: 'room', label: 'Location' }, + { name: 'start_date', label: 'Start Date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'description' }, + { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, + { + name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_cost_impact', + label: 'Has cost impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer', + hint: "The task's schedule impact in seconds, if it has one." }, + { + name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_schedule_impact', + label: 'Has schedule impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, + { name: 'issue_list_uid', label: 'Task List ID', sticky: true } + ] + when 'sheet_packet' + [ + { name: 'sheet_uids', label: 'Sheet IDs', optional: false, type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'attachment_uid', label: 'Document ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/attachments/" \ - "#{input['attachment_uid']}")&.merge('project_uid' => input.delete('project_uid')) - end, - output_fields: lambda do |object_definitions| - object_definitions['document'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/attachments")&.dig('data', 0)&. - merge('project_uid' => id) || {} - end - }, - create_sheet_packet: { - title: 'Create sheet packet in a project', - description: 'Create sheet packet in '\ - ' a PlanGrid project', - help: { - body: 'Create sheet packet in a project action uses the' \ - " Create Sheet Packet in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/upload-photo' \ - '-to-project', - learn_more_text: 'Create Sheet Packet in a Project' - }, - input_fields: lambda do |object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { + hint: 'A comma separated list of sheet IDs.' }, + { + name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'include_annotations', + label: 'Include annotations?', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + ] + when 'issue_list' + [ + { name: 'name', optional: false } + ] + when 'sheet_upload' + [ + { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, + { name: 'version_name', label: 'Version Name', optional: false } + ] + when 'photo' + [ + { name: 'title', label: 'Photo title', + hint: 'New title of the photo', sticky: true } + ] + else + [] + end.concat( + [ + { name: 'project_uid', - type: 'string', - control_type: 'text', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'sheet_uids', label: 'Sheet IDs', optional: false, - type: 'string', - hint: 'A comma separated list of sheet IDs.' }, - { name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'include_annotations', - label: 'Include annotations?', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } }, - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - payload = { - sheet_uids: input.delete('sheet_uids').split(','), - include_annotations: input.delete('include_annotations') - } - post("/projects/#{project_uid}/sheets/packets").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - object_definitions['sheet_packet'] - end, - sample_output: lambda do |_connection, _input| - { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - file_url: "https://packet-assets.plangrid.com/92cf7193-af0c-42fc-a3ab-7ef5149da720.pdf", - resource: { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/packets/92cf7193-af0c-42fc-a3ab-7ef5149da720" - }, - status: "incomplete" - } + hint: 'If your project is not in top 50, use project ID toggle.', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + } + ] + ).concat( + if config_fields['object'] != 'project' + [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false }] + else + [] + end + ) end }, - get_task_list: { - title: 'Get task list in a project', - description: 'Get task list'\ - ' in a PlanGrid project', - help: { - body: 'Get task list in a project action uses the ' \ - "Retrieve Task List in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-issue-list', - learn_more_text: 'Retrieve Task List in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { + + upload_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'attachment' + [ + { name: 'content_type', + hint: 'Content type of the document\'s file. Example for pdf application/pdf', + optional: false }, + { name: 'file_content', optional: false }, + { name: 'name', optional: false, + label: 'Document name', + hint: 'Name of the document.' }, + { + name: 'folder', label: 'Folder', sticky: true, + control_type: 'select', + pick_list: 'project_folders', + pick_list_params: { project_uid: 'project_uid' }, + toggle_hint: 'Select folder', + hint: 'Folder shows in select options only if at least one file exist in the folder', + toggle_field: { + name: 'folder', + label: 'Project folder', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Folder in project to place the document ' \ + '(case-sensitive). Leave blank to select root folder' + } + }, + { + name: 'auto_version', type: 'boolean', sticky: true, + control_type: 'checkbox', + toggle_hint: 'Select from options list', + toggle_field: { + name: 'auto_version', + type: 'boolean', + control_type: 'text', + label: 'Auto version', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + } + ] + when 'photo' + [ + { name: 'content_type', optional: false, + hint: "Content type of the photo's file" }, + { name: 'file_content', optional: false }, + { name: 'title', optional: false, label: 'Photo title' } + ] + when 'file_upload' + [ + { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false }, + { name: 'file_upload_request_uid', label: 'File Upload ID', optional: false }, + { name: 'file_name', label: 'File Name', optional: false }, + { name: 'file_content', label: 'File Content', optional: false } + ] + when 'version_upload' + [ + { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false } + ] + else + [] + end.concat( + [ + { name: 'project_uid', - type: 'string', - control_type: 'text', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'issue_list_uid', label: 'Task List ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - get("/projects/#{input['project_uid']}/issue_lists/" \ - "#{input['issue_list_uid']}") - end, - output_fields: lambda do |object_definitions| - [ - { - name: "uid", label: "Task List ID" - }, - { - name: "project_uid", label: "Project ID" - }, - { - name: "name", label: "Name" - }, - { - name: "deleted", label: "Deleted", type: "boolean" - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", - name: "QA/QC", - deleted: false, - project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" - } + hint: 'If your project is not in top 50, use project ID toggle.', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + } + ] + ) end }, - update_task_list: { - title: 'Update task list in a project', - description: 'Update task list'\ - ' in a PlanGrid project', - help: { - body: 'Update task list in a project action uses the ' \ - "Update Task List in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'update-issue-list', - learn_more_text: 'Update Task List in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'issue_list_uid', label: 'Task List ID', optional: false }, - { name: 'name', optional: false } - ] - end, - execute: lambda do |_connection, input| - patch("/projects/#{input['project_uid']}/issue_lists/" \ - "#{input['issue_list_uid']}").payload({name: input.delete('name')}) - end, - output_fields: lambda do |object_definitions| - [ - { - name: "uid", label: "Task List ID" - }, - { - name: "project_uid", label: "Project ID" - }, - { - name: "name", label: "Name" - }, - { - name: "deleted", label: "Deleted", type: "boolean" - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", - name: "QA/QC", - deleted: false, - project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" - } + + trigger_input: { + fields: lambda do |_connection, config_fields| + if config_fields['object'] != 'project' + [ + { + name: 'project_uid', optional: false, + label: 'Project', + control_type: 'select', pick_list: 'project_list', + hint: 'If your project is not in top 50, use project ID toggle.', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + label: 'Project ID', + type: 'string', + control_type: 'text', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + }, + { + name: 'output_schema', + control_type: 'schema-designer', + ngIf: 'input.object == "field_report"', + extends_schema: true, + label: 'PDF field values', + hint: 'Manually define the values expected of your PDF field values in the field report.', + optional: true + } + ] + else + [] + end end }, - create_task_list: { - title: 'Create task list in a project', - description: 'Create task list'\ - ' in a PlanGrid project', - help: { - body: 'Create task list in a project action uses the ' \ - "Create Task List in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'create-issue-list', - learn_more_text: 'Create Task List in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'name', optional: false } - ] - end, - execute: lambda do |_connection, input| - post("/projects/#{input.delete('project_uid')}/issue_lists").payload(input) - end, - output_fields: lambda do |object_definitions| + + custom_action_input: { + fields: lambda do |_connection, config_fields| + input_schema = parse_json(config_fields.dig('input', 'schema') || '[]') + [ { - name: "uid", label: "Task List ID" - }, - { - name: "project_uid", label: "Project ID" - }, - { - name: "name", label: "Name" - }, - { - name: "deleted", label: "Deleted", type: "boolean" - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "31f54967-4eac-4bd7-9b35-57f00a973a1d", - name: "QA/QC", - deleted: false, - project_uid: "11a2b248-fbf5-439e-ab49-34adef8875f8" - } - end - }, - create_sheet_version: { - title: 'Create sheet version upload in a project', - description: 'Create sheet version upload'\ - ' in a PlanGrid project', - help: { - body: 'Create sheet version in a project action uses the ' \ - "Upload Version to a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'upload-version-to-project', - learn_more_text: 'Upload Version to a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', + name: 'path', optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, - { name: 'version_name', label: 'Version Name', optional: false } - ] - end, - execute: lambda do |_connection, input| - post("/projects/#{input.delete('project_uid')}/sheets/uploads").payload(input) - end, - output_fields: lambda do |object_definitions| - [ - { - name: 'uid', label: 'Sheet Version Upload ID' - }, - { - name: 'complete_url', label: 'Upload Completion URL' - }, - { - name: 'status', + hint: 'Base URI is https://io.plangrid.com' \ + ' - path will be appended to this URI. ' \ + 'Use absolute URI to override this base URI.' }, - { - name: 'file_upload_requests', label: 'File Upload Requests', - type: 'array', of: 'object', properties: [ - { - name: 'uid', label: 'File Upload ID' - }, + ( + if %w[get delete].include?(config_fields['verb']) { - name: 'upload_status', label: 'File Upload Status' - }, + name: 'input', + type: 'object', + control_type: 'form-schema-builder', + sticky: input_schema.blank?, + label: 'URL parameters', + add_field_label: 'Add URL parameter', + properties: [ + { + name: 'schema', + extends_schema: true, + sticky: input_schema.blank? + }, + ( + if input_schema.present? + { + name: 'data', + type: 'object', + properties: call('make_schema_builder_fields_sticky', + input_schema) + } + end + ) + ].compact + } + else { - name: 'url', label: 'File Upload URL' + name: 'input', + type: 'object', + properties: [ + { + name: 'schema', + extends_schema: true, + schema_neutral: true, + control_type: 'schema-designer', + sample_data_type: 'json_input', + sticky: input_schema.blank?, + label: 'Request body parameters', + add_field_label: 'Add request body parameter' + }, + ( + if input_schema.present? + { + name: 'data', + type: 'object', + properties: call('make_schema_builder_fields_sticky', + input_schema) + } + end + ) + ].compact } - ] + end + ), + { + name: 'output', + control_type: 'schema-designer', + sample_data_type: 'json_http', + extends_schema: true, + schema_neutral: true, + sticky: true } ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - complete_url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720", - status: "incomplete", - file_upload_requests: [ - { - uid: "b278fcba-72f0-4161-bfdc-89d5bde4d5e7", - upload_status: "issued", - url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720/files/b278fcba-72f0-4161-bfdc-89d5bde4d5e7" - }, - { - uid: "727fca7d-385b-4476-b257-4b96c00e879b", - upload_status: "issued", - url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720/files/727fca7d-385b-4476-b257-4b96c00e879b" - } - ] - } end }, - upload_file_to_sheet_version: { - title: 'Upload file to sheet version in a project', - description: 'Upload file to sheet version'\ - ' in a PlanGrid project', - help: { - body: 'Upload file to sheet version in a project action uses the ' \ - "Upload File to Version in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'upload-file-to-version', - learn_more_text: 'Upload File to Version in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false }, - { name: 'file_upload_request_uid', label: 'File Upload ID', optional: false }, - { name: 'file_name', label: 'File Name', optional: false }, - { name: 'file_content', label: 'File Content', optional: false } - ] - end, - execute: lambda do |_connection, input| - file_content = input.delete('file_content') - project_uid = input.delete('project_uid') - file_upload_info = post("/projects/#{project_uid}/sheets/" \ - "uploads/#{input.delete('ver_upload_uid')}/" \ - "files/#{input.delete('file_upload_request_uid')}"). - headers('Content-Type': 'application/json'). - payload({file_name: input.delete('file_name')}) - url = file_upload_info&.dig('aws_post_form_arguments', 'action') - fields = file_upload_info&.dig('aws_post_form_arguments', 'fields') - # webhook_url = file_upload_info. - # dig('aws_post_form_arguments', 'webhook_url') - headers = fields.map { |o| { o['name'] => o['value'] } }.inject(:merge) - status = - post(url). - payload(key: headers['key'], - policy: headers['policy'], - signature: headers['signature'], - AWSAccessKeyId: headers['AWSAccessKeyId'], - 'content-type': headers['Content-Type'], - 'success_action_redirect': headers['success_action_redirect'], - 'x-amz-server-side-encryption': - headers['x-amz-server-side-encryption'], - 'x-amz-storage-class': headers['x-amz-storage-class'], - file: file_content). - request_format_multipart_form. - after_response do |_code, response, _response_headers| - response - end - end, - output_fields: lambda do |object_definitions| - - end, - sample_output: lambda do |_connection, _input| - end - }, - complete_version_upload: { - title: 'Complete sheet version upload to a project', - description: 'Complete sheet version upload '\ - ' to a PlanGrid project', - help: { - body: 'Complete sheet version upload to a project action uses the ' \ - "Complete Version Upload in a Project API.", - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'complete-version-upload-to-project', - learn_more_text: 'Complete Version Upload in a Project API' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Use project ID', - hint: 'Provide project ID e.g. ' \ - '0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false } - ] - end, - execute: lambda do |_connection, input| - project_uid = input.delete('project_uid') - post("/projects/#{project_uid}/sheets/" \ - "uploads/#{input.delete('ver_upload_uid')}/completions")&.merge('project_uid' => project_uid) - end, - output_fields: lambda do |object_definitions| - [ - { - name: 'uid', label: 'Sheet Version ID' - }, - { - name: 'status', label: 'Status' - } - ] - end, - sample_output: lambda do |_connection, _input| - { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - complete_url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/uploads/92cf7193-af0c-42fc-a3ab-7ef5149da720", - status: "complete" - } + custom_action_output: { + fields: lambda do |_connection, config_fields| + parse_json(config_fields['output'] || '[]') end } }, - triggers: { - new_updated_project: { - title: 'New or updated project', - description: 'New or updated project in'\ - ' PlanGrid', - help: { - body: 'New or updated project trigger uses the' \ - " List All Projects API.", - learn_more_url: 'https://developer.plangrid.com/docs/list-all-projects', - learn_more_text: 'List All Projects API' - }, - input_fields: lambda do |_object_definitions| - [ - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] - end, - poll: lambda do |_connection, input, closure| - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 20 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get('/projects'). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'updated_after' => now.to_time.utc.iso8601 } - end - { - events: response['data'] || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? - } - end, - dedup: lambda do |project| - "#{project['uid']}@#{project['updated_at']}" - end, - output_fields: lambda do |object_definitions| - object_definitions['project'] - end, - sample_output: lambda do |_connection, _input| - get('/projects')&.dig('data', 0) || {} - end - }, - new_updated_sheets: { - title: 'New or updated sheet in a project', - description: 'New or updated sheet in '\ - 'a PlanGrid project', + + actions: { + custom_action: { + description: "Custom action in Plangrid", help: { - body: 'New or updated sheet in a project trigger uses the' \ - " Retrieve Sheets in a Project" \ - ' API.', - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'sheets-in-a-project', - learn_more_text: 'Retrieve Sheets in a Project' + body: 'Build your own Plangrid action for any Plangrid REST endpoint.', + learn_more_url: 'https://developer.plangrid.com/docs/', + learn_more_text: 'The Plangrid API documentation' }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] - end, - poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 5 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get("/projects/#{input['project_uid']}/sheets"). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'project_uid' => project_uid, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } - end - sheets = response['data']&. - map { |o| o.merge('project_uid' => input['project_uid']) } - { - events: sheets || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? - } + + config_fields: [{ + name: 'verb', + label: 'Request type', + hint: 'Select HTTP method of the request', + optional: false, + control_type: 'select', + pick_list: %w[get post patch delete].map { |verb| [verb.upcase, verb] } + }], + + input_fields: lambda do |object_definitions| + object_definitions['custom_action_input'] end, - dedup: lambda do |sheet| - "#{sheet['uid']}@#{sheet['created_at']}" + + execute: lambda do |_connection, input| + error("#{input['verb']} not supported") if %w[get post patch delete].exclude?(input['verb']) + data = input.dig('input', 'data').presence || {} + case input['verb'] + when 'get' + response = get(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + if response.is_a?(Array) + array_name = parse_json(input['output'] || '[]'). + dig(0, 'name') || 'array' + { array_name.to_s => response } + elsif response.is_a?(Hash) + response + else + error('API response is not a JSON') + end + when 'post' + post(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + when 'patch' + patch(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + when 'delete' + delete(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + end end, + output_fields: lambda do |object_definitions| - object_definitions['sheet'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/sheets")&.dig('data', 0) || {} + object_definitions['custom_action_output'] end }, - new_updated_documents: { - title: 'New or updated document in a project', - description: 'New or updated document in '\ - 'a PlanGrid project', - help: { - body: 'New or updated document in a project trigger uses the' \ - " Retrieve Documents in a Project" \ - ' API.', - learn_more_url: 'https://developer.plangrid.com/docs/retrieve-' \ - 'attachments-in-a-project', - learn_more_text: 'Retrieve Documents in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] + + create_object: { + title: 'Create object', + description: lambda do |_, objects| + "Create #{objects['object']&.downcase || 'object'} in PlanGrid" end, - poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 5 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get("/projects/#{input['project_uid']}/attachments"). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'project_uid' => project_uid, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } - end - documents = response['data']&. - map { |o| o.merge('project_uid' => project_uid) } + help: "Create object in PlanGrid", + + config_fields: [ { - events: documents || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'create_object_list', + hint: 'Select the object from picklist.' } + ], + + input_fields: lambda do |object_definitions| + object_definitions['create_input_schema'] end, - dedup: lambda do |document| - "#{document['uid']}@#{document['created_at']}" + + execute: lambda do |_connection, input| + payload = + input.except('project_uid', 'object').each_with_object({}) do |(key, val), hash| + hash[key] = if %w[due_at sent_at].include?(key) + val.to_time.utc.iso8601 + elsif %w[sheet_uids assigned_to_uids].include?(key) + val.split(",") + else + val + end + end + case input['object'] + when 'project' + post('/projects').payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + when 'sheet_packet', 'sheet_upload', 'user_invite' + path = input['object'].split("_") + post("/projects/#{input['project_uid']}/#{path.first.pluralize}/#{path.last.pluralize}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + else + post("/projects/#{input['project_uid']}/#{input['object'].pluralize}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end.merge('project_uid' => input['project_uid']) end, + output_fields: lambda do |object_definitions| - object_definitions['document'] + object_definitions['get_output_schema'] end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/attachments")&.dig('data', 0) || {} + + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") end }, - new_updated_task: { - title: 'New or updated task in a project', - description: 'New or updated task in a '\ - ' PlanGrid project', - help: { - body: 'New or updated task in a project trigger uses the' \ - " Retrieve Tasks " \ - ' in a Project API.', - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-issues-in-a-project', - learn_more_text: 'Retrieve Tasks in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] + + update_object: { + title: 'Update object', + description: lambda do |_, objects| + "Update #{objects['object']&.downcase || 'object'} in PlanGrid" end, - poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 10 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get("/projects/#{input['project_uid']}/" \ - 'issues'). - params(limit: limit, - skip: skip, - include_annotationless: true, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'project_uid' => project_uid, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } - end - tasks = response['data']&. - map { |o| o.merge('project_uid' => input['project_uid']) } + help: "Update object in PlanGrid", + + config_fields: [ { - events: tasks || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'update_object_list', + hint: 'Select the object from picklist.' } + ], + + input_fields: lambda do |object_definitions| + object_definitions['update_input_schema'] end, - dedup: lambda do |task| - "#{task['uid']}@#{task['updated_at']}" + + execute: lambda do |_connection, input| + payload = + input.except('project_uid', 'uid', 'object').each_with_object({}) do |(key, val), hash| + hash[key] = %w[due_at sent_at].include?(key) ? val.to_time.utc.iso8601 : val + end + if input['object'] == 'project' + patch("/projects/#{input['project_uid']}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + else + patch("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end.merge('project_uid' => input['project_uid']) end, + output_fields: lambda do |object_definitions| - object_definitions['task'] + object_definitions['get_output_schema'] end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/issues")&. - dig('data', 0) || {} + + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") end }, - new_updated_annotations: { - title: 'New or updated annotation in a project', - description: 'New or updated annotation '\ - 'in a PlanGrid project', - help: { - body: 'New or updated annotation in project trigger uses the' \ - " Retrieve " \ - ' Annotations in a Project API.', - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-annotations-in-a-project', - learn_more_text: 'Retrieve Annotations in a Project' - }, - input_fields: lambda do |_object_definitions| + + get_object: { + title: 'Get object by ID', + description: lambda do |_, objects| + "Get #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Get object by ID in PlanGrid", + + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'get_objects', + toggle_hint: 'Select object', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| [ - { name: 'project_uid', optional: false, + { + name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', label: 'Project', - control_type: 'select', pick_list: 'project_list', + optional: false, toggle_hint: 'Select project', + hint: 'If your project is not in top 50, use project ID toggle.', toggle_field: { name: 'project_uid', - label: 'Project ID', type: 'string', control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] - end, - poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 10 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get("/projects/#{input['project_uid']}/" \ - 'annotations'). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'project_uid' => project_uid, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } - end - annotations = response['data']&. - map { |o| o.merge('project_uid' => input['project_uid']) } - { - events: annotations || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? - } + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + }, + ].concat(object_definitions['get_input_schema']) end, - dedup: lambda do |annotation| - "#{annotation['uid']}@#{annotation['updated_at']}" + + execute: lambda do |_connection, input| + params = + input.except('project_uid', 'object').each_with_object({}) do |(key, val), hash| + hash[key] = %w[updated_after].include?(key) ? val.to_time.utc.iso8601 : val + end + case input['object'] + when 'project' + get("/projects/#{input['project_uid']}") + when 'sheet_packet' + get("/projects/#{input['project_uid']}/sheets/packets/#{input['uid']}") + else + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") + end.merge('project_uid' => input['project_uid']) end, + output_fields: lambda do |object_definitions| - object_definitions['annotation'] + object_definitions['get_output_schema'] end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/annotations")&. - dig('data', 0) || {} + + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") end }, - new_updated_photos: { - title: 'New or updated photo in a project', - description: 'New or updated photo '\ - 'in a PlanGrid project', - help: { - body: 'New or updated photo in a project trigger uses the' \ - " Retrieve " \ - ' photos in a Project API.', - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-photos-in-a-project', - learn_more_text: 'Retrieve Photos in a Project' - }, - input_fields: lambda do |_object_definitions| + + search_objects: { + title: 'Search objects', + description: lambda do |_, objects| + "Search #{objects['object']&.downcase&.pluralize || 'objects'} in PlanGrid" + end, + help: "Search objects in PlanGrid", + + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'search_objects', + toggle_hint: 'Select object', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| [ - { name: 'project_uid', optional: false, + { + name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', label: 'Project', - control_type: 'select', pick_list: 'project_list', + optional: false, toggle_hint: 'Select project', + hint: 'If your project is not in top 50, use project ID toggle.', toggle_field: { name: 'project_uid', - label: 'Project ID', type: 'string', control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } } - ] - end, - poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 10 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get("/projects/#{input['project_uid']}/" \ - 'photos'). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'project_uid' => project_uid, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } - end - photos = response['data']&. - map { |o| o.merge('project_uid' => input['project_uid']) } - { - events: photos || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? - } + ].concat(object_definitions['get_input_schema']) end, - dedup: lambda do |photo| - "#{photo['uid']}@#{photo['updated_at']}" + + execute: lambda do |_connection, input| + params = + input.except('project_uid', 'object', 'output_schema').each_with_object({}) do |(key, val), hash| + hash[key] = %w[updated_after].include?(key) ? val.to_time.utc.iso8601 : val + end + case input['object'] + when 'rfi_status' + { data: get("/projects/#{input['project_uid']}/rfis/statuses", params)['data'] } + when 'field_report' + results = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params)['data'] + results.map do |field_report| + field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge)) + end + { data: results } + else + { data: get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params)['data'] } + end.merge('project_uid' => input['project_uid']) end, + output_fields: lambda do |object_definitions| - object_definitions['photo'] - end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/photos")&. - dig('data', 0) || {} - end - }, - new_updated_snapshot: { - title: 'New or updated snapshot in a project', - description: 'New or updated snapshot '\ - 'in a PlanGrid project', - help: { - body: 'New or updated snapshot in a project trigger uses the' \ - " Retrieve " \ - ' Snapshots in a Project API.', - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-snapshots-in-a-project', - learn_more_text: 'Retrieve Snapshots in a Project' - }, - input_fields: lambda do |_object_definitions| [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' + name: 'data', type: 'array', of: 'object', properties: object_definitions['get_output_schema'] } ] end, - poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 10 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - else - get("/projects/#{input['project_uid']}/" \ - 'snapshots'). - params(limit: limit, - skip: skip, - updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'project_uid' => project_uid, - 'next_page_url' => next_page_url } - else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } - end - snapshots = response['data']&. - map { |o| o.merge('project_uid' => input['project_uid']) } + + sample_output: lambda do |_connection, input| + { "data" => Array.wrap(call(:get_sample_output, input['object'], input['project_uid'] || "")) } + end + }, + + upload_object: { + title: 'Upload object', + description: lambda do |_, objects| + "Upload #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Upload object in PlanGrid", + + config_fields: [ { - events: snapshots || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'upload_object_list', + hint: 'Select the object from picklist.' } + ], + + input_fields: lambda do |object_definitions| + object_definitions['upload_input_schema'] end, - dedup: lambda do |annotation| - "#{annotation['uid']}@#{annotation['updated_at']}" + + execute: lambda do |_connection, input| + case input['object'] + when 'file_upload' + file_upload_info = post("/projects/#{input['project_uid']}/sheets/" \ + "uploads/#{input.delete('ver_upload_uid')}/" \ + "files/#{input.delete('file_upload_request_uid')}"). + headers('Content-Type': 'application/json'). + payload(file_name: input.delete('file_name')) + call(:get_upload_object, file_upload_info, input) + when 'photo', 'attachment' + file_upload_info = post("/projects/#{input['project_uid']}/#{input['object'].pluralize}/uploads"). + headers('Content-type': 'application/json'). + payload(input.except('project_uid', 'file_content', 'object')) + call(:get_upload_object, file_upload_info, input) + else + post("/projects/#{input['project_uid']}/sheets/uploads/#{input['ver_upload_uid']}/completions") + end end, + output_fields: lambda do |object_definitions| - object_definitions['snapshot'] + object_definitions['get_output_schema'] end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/snapshots")&. - dig('data', 0) || {} + + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") end }, - new_updated_field_report: { - title: 'New or updated field report in a project', - description: 'New or updated field report '\ - 'in a PlanGrid project', - help: { - body: 'New or updated field report in a project trigger uses the' \ - " Retrieve " \ - 'Field Reports in a Project API.', - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-field-reports-in-a-project', - learn_more_text: 'Retrieve Field Reports in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] + }, + + triggers: { + new_object: { + title: 'New object in PlanGrid', + description: lambda do |_, objects| + "New #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Triggers when an object is created", + + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'object_list', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| + object_definitions['trigger_input'].concat( + [ + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + ) end, poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] updated_after = closure&.[]('updated_after') || (input['since'] || 1.hour.ago).to_time.utc.iso8601 limit = 10 skip = closure&.[]('skip') || 0 response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) + elsif input['object'] == 'project' + get("/projects").params(limit: limit, skip: skip, updated_after: updated_after) + elsif input['object'] == 'issue' + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after, include_annotationless: true) + elsif input['object'] == 'field_report' + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after) else - get("/projects/#{input['project_uid']}/" \ - 'field_reports'). - params(limit: limit, - skip: skip, - updated_after: updated_after, - sort_by: 'updated_at', - sort_order: 'asc') + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after) end closure = if (next_page_url = response['next_page_url']).present? { 'skip' => skip + limit, - 'project_uid' => project_uid, 'next_page_url' => next_page_url } else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } + { 'skip' => 0, + 'updated_after' => response['data']&. + last&.[]('created_at') || response['data']&.last&.[]('published_at') } + end + objects = if input['object'] == 'field_report' + response['data']&.map do |field_report| + field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge), + 'project_uid' => input['project_uid']) + end + else + response['data']&.map { |o| o.merge('project_uid' => input['project_uid']) } end - - field_reports = response['data']&.map do |field_report| - field_report.merge({ - 'pdf_form_fields' => field_report['pdf_form_values'] - &.map { |a| { a['name'] => a['value'] } }&.inject(:merge) }) - end { - events: field_reports || [], + events: objects || [], next_poll: closure, can_poll_more: response['next_page_url'].present? } end, - dedup: lambda do |field_report| - "#{field_report['uid']}@#{field_report['updated_at']}" + dedup: lambda do |object| + object['uid'] end, output_fields: lambda do |object_definitions| - object_definitions['field_report'] + object_definitions['get_output_schema'] end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/field_reports")&. - dig('data', 0) || {} + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") end }, - new_updated_rfi: { - title: 'New or updated RFI in a project', - description: 'New or updated RFI '\ - 'in a PlanGrid project', - help: { - body: 'New or updated RFI in a project trigger uses the' \ - " Retrieve " \ - ' RFIs in a Project API.', - learn_more_url: 'https://developer.plangrid.com/docs/' \ - 'retrieve-rfis-in-a-project', - learn_more_text: 'Retrieve RFIs in a Project' - }, - input_fields: lambda do |_object_definitions| - [ - { name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Use project ID', - hint: 'Use Project ID e.g. 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } }, - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] + + new_updated_object: { + title: 'New or updated object in PlanGrid', + description: lambda do |_, objects| + "New or updated #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Triggers when an object is created or updated", + + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'object_list_new', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| + object_definitions['trigger_input'].concat( + [ + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + ) end, poll: lambda do |_connection, input, closure| - project_uid = closure&.[]('project_uid') || input['project_uid'] updated_after = closure&.[]('updated_after') || (input['since'] || 1.hour.ago).to_time.utc.iso8601 limit = 10 skip = closure&.[]('skip') || 0 + update_time = Time.now.utc.iso8601 response = if (next_page_url = closure&.[]('next_page_url')).present? get(next_page_url) + elsif input['object'] == 'project' + get("/projects").params(limit: limit, skip: skip, updated_after: updated_after) + elsif input['object'] == 'issue' + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after, include_annotationless: true) + elsif input['object'] == 'field_report' + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after) else - get("/projects/#{input['project_uid']}/" \ - 'rfis'). - params(limit: limit, - skip: skip, - updated_after: updated_after) + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after) end + object_update_time = ['annotation', 'sheet', 'attachment'].include? input['object'] closure = if (next_page_url = response['next_page_url']).present? { 'skip' => skip + limit, - 'project_uid' => project_uid, 'next_page_url' => next_page_url } else - { 'offset' => 0, - 'project_uid' => project_uid, - 'updated_after' => now.to_time.utc.iso8601 } + { 'skip' => 0, + 'updated_after' => object_update_time ? update_time : response['data']&.last&.[]('updated_at') } + end + project_hash = { 'project_uid' => input['project_uid'] } + project_hash["updated_after"] = (closure["updated_after"] || updated_after) if ['annotation', 'sheet', 'attachment'].include? input['object'] + objects = if input['object'] == 'field_report' + response['data']&.map do |field_report| + field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge), + 'project_uid' => input['project_uid']) + end + else + response['data']&.map { |o| o.merge('project_uid' => input['project_uid']) } end - rfis = response['data']&. - map { |o| o.merge('project_uid' => input['project_uid']) } { - events: rfis || [], + events: objects || [], next_poll: closure, can_poll_more: response['next_page_url'].present? } end, - dedup: lambda do |rfi| - "#{rfi['uid']}@#{rfi['updated_at']}" + dedup: lambda do |object| + "#{object['uid']}@#{(object['updated_after'] || object['updated_at'])}" end, output_fields: lambda do |object_definitions| - object_definitions['rfi'] + object_definitions['get_output_schema'] end, - sample_output: lambda do |_connection, _input| - id = get('projects')&.[]('data', 0)&.[]('uid') - get("/projects/#{id}/rfis")&. - dig('data', 0) || {} + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") end - } + }, + }, + + methods: { + get_sample_output: lambda do |object, project_uid| + case object + when 'project' + get('/projects')&.dig('data', 0) + when 'field_report' + results = get("/projects/#{project_uid}/field_reports").dig('data', 0)&.merge('project_uid' => project_uid) + when 'rfi_status' + get("/projects/#{project_uid}/rfis/statuses")&.dig('data', 0)&.merge('project_uid' => project_uid) + when 'user_invite' + get("/projects/#{project_uid}/users")&.dig('data', 0)&.merge('project_uid' => project_uid) + when 'sheet_packet' + { + "data" => [ + { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + file_url: "https://packet-assets.plangrid.com/92cf7193-af0c-42fc-a3ab-7ef5149da720.pdf", + resource: { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/" \ + "packets/92cf7193-af0c-42fc-a3ab-7ef5149da720" + }, + status: "incomplete" + } + ] + } + when 'sheet_upload' + { + "data" => [ + { + uid: "d050ed4d-425b-4cd2-a46a-1113be6ed37c", + complete_url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/d050ed4d-425b-4cd2-a46a-1113be6ed37c/completions", + status: "incomplete", + file_upload_requests: [ + { + uid: "cba96343-bfaf-4f95-805a-dd49169944c0", + upload_status: "issued", + url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/d050ed4d-425b-4cd2-a46a-1113be6ed37c/files/cba96343-bfaf-4f95-805a-dd49169944c0" + } + ] + } + ] + } + when 'version_upload' + { + "data" => [ + { + uid: "f23f1677-cb77-425f-bdd5-626a9fba8e83", + complete_url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/f23f1677-cb77-425f-bdd5-626a9fba8e83/completions", + status: "complete" + } + ] + } + else + get("/projects/#{project_uid}/#{object.pluralize}")&.dig('data', 0)&.merge('project_uid' => project_uid) + end + end, + + get_upload_object: lambda do |file_upload_info, input| + headers = file_upload_info&.dig('aws_post_form_arguments', 'fields')&. + each_with_object({}) do |obj, hash| + hash[obj['name']] = obj['value'] + end + post(file_upload_info&.dig('aws_post_form_arguments', 'action')). + payload(key: headers['key'], + policy: headers['policy'], + signature: headers['signature'], + AWSAccessKeyId: headers['AWSAccessKeyId'], + 'content-type': headers['Content-Type'], + 'success_action_redirect': headers['success_action_redirect'], + 'x-amz-server-side-encryption': + headers['x-amz-server-side-encryption'], + 'x-amz-storage-class': headers['x-amz-storage-class'], + file: input['file_content']). + request_format_multipart_form. + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end, + + make_schema_builder_fields_sticky: lambda do |input| + input.map do |field| + if field[:properties].present? + field[:properties] = call("make_schema_builder_fields_sticky", + field[:properties]) + elsif field["properties"].present? + field["properties"] = call("make_schema_builder_fields_sticky", + field["properties"]) + end + field[:sticky] = true + field + end + end }, + pick_lists: { + create_object_list: lambda do |_connection| + [["Project", "project"], ["Sheet Packet", "sheet_packet"], ["Task List", "issue_list"], ["Task", "issue"], ["RFI", "rfi"], + ["Sheet Version", "sheet_upload"], ["Invite User", "user_invite"]] + end, + + update_object_list: lambda do |_connection| + [["Project", "project"], ["Task List", "issue_list"], ["Task", "issue"], ["RFI", "rfi"], + ["Photo Metadata", "photo"]] + end, + + upload_object_list: lambda do |_connection| + [["Document", "attachment"], ["Photo", "photo"], ["File to sheet version", "file_upload"], + ["Complete version", "version_upload"]] + end, + + get_objects: lambda do |_connection| + [["Project", "project"], ["RFI", "rfi"], ["Task", "issue"], ["User", "user"], + ["Snapshot", "snapshot"], ["Sheet", "sheet"], ["Sheet Packet", "sheet_packet"], + ["Photo", "photo"], ["Document", "attachment"], ["Task_list", "issue_list"]] + end, + + search_objects: lambda do |_connection| + [["RFI Status", "rfi_status"], ["Role", "role"], ["Field Report", "field_report"]] + end, + + object_list: lambda do |_connection| + [["Project", "project"], ["Sheet", "sheet"], ["Document", "attachment"], ["Task", "issue"], ["RFI", "rfi"], + ["Annotation", "annotation"], ["Photo", "photo"], ["Snapshot", "snapshot"], ["Field Report", "field_report"]] + end, + + object_list_new: lambda do |_connection| + [["Project", "project"], ["Task", "issue"], ["RFI", "rfi"], ["Sheet", "sheet"], ["Field Report", "field_report"], + ["Document", "attachment"], ["Annotation", "annotation"]] + end, + project_list: lambda do |_connection| - get('projects')&.[]('data')&.pluck('name', 'uid') + get('/projects')&.[]('data')&.pluck('name', 'uid') end, + project_types: lambda do |_connection| ['general', 'manufacturing', 'power', 'water-sewer-waste', 'industrial-petroleum', 'transportation', 'hazardous-waste', 'telecom', 'education-k-12', 'education-higher', 'gov-federal', 'gov-state-local', 'other'].map { |type| [type.labelize, type] } end, + project_folders: lambda do |_connection, project_uid:| - if project_uid.length === 36 + if project_uid.length == 36 folders = get("/projects/#{project_uid}/attachments")['data']&. pluck('folder')&.uniq - if folders.size > 0 - folders&.map { |folder| [folder || 'Root', folder || ''] } - else - [['Root', '']] - end + folders.size > 0 ? folders&.map { |folder| [folder || 'Root', folder || ''] } : [['Root', '']] end end } From 4ecb5f702657ab8395a9a3c680e70cc14a302d45 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 16 Mar 2020 17:11:28 -0400 Subject: [PATCH 60/96] add `custom_items` object to field report output --- custom_connectors/oauth2/plangrid.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 75e486bd..5d0aab1c 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -498,6 +498,22 @@ } ] }, + { + name: 'custom_items', label: 'Custom Form Items', type: 'array', + of: 'object', properties: [ + { name: 'section_label', label: 'Section Name' }, + { name: 'item_label', label: 'Item Label' }, + { name: 'value_name', label: 'Value Name' }, + { name: 'notes' }, + { name: 'text_val', label: 'Text Value' }, + { name: 'choice_val', label: 'Choice Value' }, + { name: 'number_val', label: 'Number Value', type: 'number' }, + { name: 'date_val', label: 'Date Value', type: 'date_time' }, + { name: 'array_val', label: 'Array Value', type: 'array', + of: 'string' }, + { name: 'toggle_val', label: 'Toggle Value', type: 'integer' } + ] + }, { name: 'attachments', type: 'object', properties: [ { name: 'total_count', type: 'integer' }, From 0d1da5572a740ce6b0b0e1db85afff3992a2c789 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Tue, 17 Mar 2020 16:43:51 -0400 Subject: [PATCH 61/96] - add `field_report_template` to `search object` action - add `skip` and `limit` parameters for `field_report` input - add `total_count` and `next_page_url` to output for `search object` action --- custom_connectors/oauth2/plangrid.rb | 68 +++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 5d0aab1c..d2adcbef 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -77,6 +77,10 @@ hint: 'Only retrieve field reports between a date range ending with this date in UTC format.' }, { name: 'updated_after', label: 'Updated After', type: 'date_time', hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, + { name: 'skip', type: 'integer', + hint: 'Number of records to skip.' }, + { name: 'limit', type: 'integer', + hint: 'Number of records to retrieve.' }, { name: 'sort_by', label: 'Sort by column', control_type: 'select', pick_list: @@ -107,6 +111,17 @@ optional: true } ] + when 'field_report_template' + [ + { name: 'updated_after', label: 'Updated After', type: 'date_time', + hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, + { name: 'updated_before', label: 'Updated Before', type: 'date_time', + hint: 'Only retrieve field reports created/updated before specified UTC date and time.' }, + { name: 'skip', type: 'integer', + hint: 'Number of records to skip.' }, + { name: 'limit', type: 'integer', + hint: 'Number of records to retrieve.' } + ] when 'role', 'project' [] else @@ -558,6 +573,41 @@ ] } ] + when 'field_report_template' + [ + { name: 'uid', label: 'Field Report Template ID' }, + { name: 'name' }, + { name: 'field_reports', label: 'Field Reports', + type: 'object', properties: [ + { name: 'url' } + ] + }, + { name: 'is_pdf', label: 'Is PDF', type: 'boolean' }, + { name: 'pdf_url', label: 'PDF URL' }, + { name: 'template_type', label: 'Template Type' }, + { name: 'status' }, + { name: 'group_permissions', label: 'Group Permissions', + type: 'array', of: 'object', properties: [ + { name: 'permissions', type: 'array', of: 'string' }, + { name: 'role_name', label: 'Role Name' }, + { name: 'role_uid', label: 'Role UID' } + ] + }, + { name: 'user_permissions', label: 'User Permissions', + type: 'array', of: 'object', properties: [ + { name: 'permissions', type: 'array', of:' string' }, + { name: 'user_id', label: 'User UID'} + ] + }, + { name: 'created_by', label: 'Created By', type: 'object', + properties: [ + { name: 'email' }, + { name: 'uid' }, + { name: 'url' } + ] + }, + { name: 'updated_at', label: 'Updated At', type: 'date_time' } + ] when 'rfi' [ { name: 'uid', label: 'RFI ID' }, @@ -1691,15 +1741,18 @@ end case input['object'] when 'rfi_status' - { data: get("/projects/#{input['project_uid']}/rfis/statuses", params)['data'] } + response = get("/projects/#{input['project_uid']}/rfis/statuses", params) + { data: response['data'], total_count: response['total_count'], next_page_url: response['next_page_url'] } when 'field_report' - results = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params)['data'] + response = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params) + results = response['data'] results.map do |field_report| field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge)) end - { data: results } + { data: results, total_count: response['total_count'], next_page_url: response['next_page_url'] } else - { data: get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params)['data'] } + response = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params) + { data: response['data'], total_count: response['total_count'], next_page_url: response['next_page_url'] } end.merge('project_uid' => input['project_uid']) end, @@ -1707,7 +1760,9 @@ [ { name: 'data', type: 'array', of: 'object', properties: object_definitions['get_output_schema'] - } + }, + { name: 'total_count', label: 'Total Count', type: 'integer' }, + { name: 'next_page_url', label: 'Next Page URL' } ] end, @@ -2060,7 +2115,8 @@ end, search_objects: lambda do |_connection| - [["RFI Status", "rfi_status"], ["Role", "role"], ["Field Report", "field_report"]] + [["RFI Status", "rfi_status"], ["Role", "role"], ["Field Report", "field_report"], + ["Field Report Template", "field_report_template"]] end, object_list: lambda do |_connection| From 6acefd64699cd69a39873bfd0eb889725de21a75 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Tue, 17 Mar 2020 16:53:18 -0400 Subject: [PATCH 62/96] - add `template_uid` filter parameter when searching for field reports --- custom_connectors/oauth2/plangrid.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index d2adcbef..c0437de8 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -69,6 +69,8 @@ ] when 'field_report' [ + { name: 'template_uid', label: 'Field Report Template ID', + hint: 'Only retrieve field reports for the specified template ID.'}, { name: 'report_date_min', type: 'date', label: 'Report Start Date', hint: 'Only retrieve field reports between a date range starting with this date in UTC format.' }, From 5b94522f98597d899ad4ea06f25e71e282111d48 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 20:59:13 -0400 Subject: [PATCH 63/96] update picklist for `create object` action --- custom_connectors/oauth2/plangrid.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index c0437de8..6fa18f62 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2096,8 +2096,18 @@ pick_lists: { create_object_list: lambda do |_connection| - [["Project", "project"], ["Sheet Packet", "sheet_packet"], ["Task List", "issue_list"], ["Task", "issue"], ["RFI", "rfi"], - ["Sheet Version", "sheet_upload"], ["Invite User", "user_invite"]] + [ + ['Project', 'project'], + ['Field Report Export', 'field_reports/export'], + ['Invite User', 'user_invite'], + ['RFI', 'rfi'], + ['Task List', 'issue_list'], + ['Task', 'issue'], + ['Sheet Packet', 'sheet_packet'], + ['Sheet Version', 'sheet_upload'], + ['Submittal Item', 'submittals/item'], + ['Submittal Package', 'submittals/package'] + ] end, update_object_list: lambda do |_connection| From d7ba2d5b71d19cd5969f43e10c68351a8e48bdf8 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:02:51 -0400 Subject: [PATCH 64/96] add submittals package, submittals item, and field report exports to `create_input_schema` --- custom_connectors/oauth2/plangrid.rb | 123 +++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 6fa18f62..ad039d7f 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -996,6 +996,129 @@ { name: 'last_name' }, { name: 'language' } ] + when 'submittals/package' + [ + { name: 'name', optional: false, + hint: 'The name of the submittal package.' }, + { name: 'custom_id', optional: false, + hint: 'A custom ID for the submittal package.' }, + { name: 'item_uids', optional: false, label: 'Submittal Item IDs', + hint: 'The IDs of the specific submittal items to include in the submittal package. ' \ + 'Separate each item with a comma.' }, + { name: 'ball_in_court_status', + hint: "Reference to the role of the user from whom the next step is expected." \ + " Can be 'manager', 'submitter', or 'reviewer'." }, + { name: 'design_review_due_date', type: 'date', + hint: 'Due date for the design review.' }, + { name: 'file_group_uid', + hint: 'UID of the file group to associate with this submittal package.' }, + { name: 'general_contractor_review_due_date', type: 'date', + hint: "Due date of the general contractor's review." }, + { name: 'lead_time_days', type: 'integer', + hint: 'Number of days of lead time provided for this submittal package.' }, + { name: 'notes' }, + { name: 'required_on_job_date', type: 'date', + hint: 'The date when the submitted material is required on the job.' }, + { name: 'submittal_due_date', type: 'date', + hint: 'Due date for this submittal package.' }, + { name: 'managers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of manager.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'reviewers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of reviewer.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'watchers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of watcher.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + } + ] + when 'submittals/item' + [ + { name: 'name', optional: false, + hint: 'Name of the submittal item.' }, + { name: 'description', + hint: 'Description of the submittal package.' }, + { name: 'package_uid', + hint: 'ID of the submittal package to which this item should be associated.' }, + { name: 'submittal_due_date', type: 'date', + hint: 'Date when the submittal is due.' }, + { name: 'lead_time_days', type: 'integer', + hint: 'The number of days of lead time provided for this submittal item.' }, + { name: 'required_on_job_date', type: 'date', + hint: 'The date when the submitted material is required on the job.' }, + { name: 'design_review_due_date', type: 'date', + hint: 'The date when the design review is due.' }, + { name: 'general_contractor_review_due_date', type: 'date', + hint: 'The date when the general contractor\'s review is due.' }, + { name: 'managers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of manager.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'reviewers', type: 'array', of: 'object', + hint: 'A list describing users assigned the role of reviewer.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'submitters', type: 'array', of: 'object', + hint: 'A list describing users assigned the role of submitter.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'watchers', type: 'array', of: 'object', + hint: 'A list describing users assigned the role of watcher.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + } + ] + when 'field_reports/export' + [ + { name: 'field_report_uids', label: 'Field Report IDs', optional: false, + hint: 'A comma separated list of field report IDs.' }, + { + name: 'file_type', + control_type: 'select', + pick_list: 'field_report_export_file_type', + sticky: true, + hint: 'Select the file type of the export', + }, + { + name: 'timezone', + control_type: 'select', + pick_list: 'timezones', + sticky: true, + toggle_hint: 'Select timezone', + toggle_field: { + name: 'timezone', + type: 'string', + label: 'Timezone', + control_type: 'text', + optional: false, + toggle_hint: 'Enter timezone', + hint: 'A valid timezone. See fill list ' \ + 'here.' + } + } + ] else [] end.concat( From fc936a834956de547f7cc1638aa65795dccfa469 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:07:02 -0400 Subject: [PATCH 65/96] add field report export, submittal package, and submittal item to `get_output_schema` --- custom_connectors/oauth2/plangrid.rb | 139 +++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index ad039d7f..4da5d87d 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -610,6 +610,14 @@ }, { name: 'updated_at', label: 'Updated At', type: 'date_time' } ] + when 'field_reports/export' + [ + { name: 'uid', label: 'Export ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'status' }, + { name: 'file_url' }, + { name: 'resource_url' } + ] when 'rfi' [ { name: 'uid', label: 'RFI ID' }, @@ -793,6 +801,137 @@ { name: "project_uid", label: "Project ID" }, { name: 'status', label: 'Status' } ] + when 'submittals/package' + [ + { name: 'uid', label: 'Submittal Package ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'name' }, + { name: 'spec_section' }, + { name: 'spec_section_name' }, + { name: 'custom_id' }, + { name: 'version' }, + { name: 'ball_in_court_status' }, + { name: 'lead_time_days', type: 'integer' }, + { name: 'submittals_due_date', type: 'date_time' }, + { name: 'required_on_job_date', type: 'date_time' }, + { name: 'transmission_status' }, + { name: 'is_voided', type: 'boolean' }, + { name: 'items', type: 'object', properties: [ + { name: 'uids', type: 'array', of: 'string' }, + { name: 'url' }, + { name: 'total_count', type: 'integer'} + ]}, + { name: 'visible_file_group_uid' }, + { name: 'design_review_due_date', type: 'date_time' }, + { name: 'general_contractor_review_due_date', type: 'date_time' }, + { name: 'latest_review', type: 'object', properties: [ + { name: 'uid', label: 'Review ID' }, + { name: 'created_at', type: 'date_time' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'file_group_uid' }, + { name: 'is_official_review' }, + { name: 'package_version' }, + { name: 'review_response_uid' }, + { name: 'reviewed_by', type: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]} + ]}, + { name: 'latest_review_response_uid' }, + { name: 'received_from_design_at', type: 'date_time' }, + { name: 'sent_to_design_at', type: 'date_time' }, + { name: 'received_from_sub_at', type: 'date_time' }, + { name: 'returned_to_sub_at', type: 'date_time' }, + { name: 'managers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'reviewers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'submitters', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'unioned_watchers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'watchers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'created_at', type: 'date_time' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'published_at', type: 'date_time' }, + { name: 'updated_at', type: 'date_time' }, + { name: 'updated_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ]} + ] + when 'submittals/item' + [ + { name: 'uid', label: 'Submittal Item ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'name' }, + { name: 'description' }, + { name: 'spec_bullet' }, + { name: 'spec_doc' }, + { name: 'spec_heading' }, + { name: 'spec_page' }, + { name: 'spec_section' }, + { name: 'spec_section_name' }, + { name: 'spec_subsection_name' }, + { name: 'lead_time_days', type:'integer' }, + { name: 'required_on_job_date', type: 'date_time' }, + { name: 'submittal_due_date', type: 'date_time' }, + { name: 'submittals_type' }, + { name: 'package', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'design_review_due_date', type: 'date_time' }, + { name: 'general_contractor_review_due_date', type: 'date_time' }, + { name: 'reviewers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'managers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'submitters', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'watchers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'created_at' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ]} + ] end end }, From d5071ff077455ac91bffc1f8278264e5857b23c6 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:11:19 -0400 Subject: [PATCH 66/96] update `create_object` action to include field report exports, submittal package, and submittal item --- custom_connectors/oauth2/plangrid.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 4da5d87d..947fee53 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1802,6 +1802,14 @@ end, execute: lambda do |_connection, input| + if input['object'] == 'submittals/package' + input['item_uids'] = input['item_uids'].split(',') + end + + if input['object'] == 'field_reports/export' + input['field_report_uids'] = input['field_report_uids'].split(',') + end + payload = input.except('project_uid', 'object').each_with_object({}) do |(key, val), hash| hash[key] = if %w[due_at sent_at].include?(key) @@ -1824,6 +1832,12 @@ after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end + + when 'field_reports/export' + post("/projects/#{input['project_uid']}/field_reports/export").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end else post("/projects/#{input['project_uid']}/#{input['object'].pluralize}").payload(payload). after_error_response(/.*/) do |_code, body, _header, message| From 77a2c20722c8a668c7fa8acffae58c3b72cf00c8 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:14:24 -0400 Subject: [PATCH 67/96] add `field_report_export_file_type` and `timezones` pick list for field report export --- custom_connectors/oauth2/plangrid.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 947fee53..d99e088c 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2434,6 +2434,24 @@ pluck('folder')&.uniq folders.size > 0 ? folders&.map { |folder| [folder || 'Root', folder || ''] } : [['Root', '']] end + end, + + field_report_export_file_type: lambda do |_connection| + [ + [ 'PDF', 'pdf' ], + [ 'XLSL', 'xlsx' ] + ] + end, + + timezones: lambda do |_connection| + [ + ['America/Los_Angeles','America/Los_Angeles'], + ['America/Denver','America/Denver'], + ['America/Phoenix','America/Phoenix'], + ['America/Chicago','America/Chicago'], + ['America/Mexico_City','America/Mexico_City'], + ['America/New_York','America/New_York'] + ] end } } From 8fee3bb4fe7f8ceb827f6fb9141103f6d79c9d8d Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:19:42 -0400 Subject: [PATCH 68/96] add submittals package and submittals item to `update_object` picklist and `update_object_input` schema --- custom_connectors/oauth2/plangrid.rb | 102 ++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index d99e088c..58abb1eb 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1473,6 +1473,99 @@ { name: 'title', label: 'Photo title', hint: 'New title of the photo', sticky: true } ] + when 'submittals/package' + [ + { name: 'name', + hint: 'The name of the submittal package.' }, + { name: 'custom_id', + hint: 'A custom ID for the submittal package.' }, + { name: 'item_uids', label: 'Submittal Item IDs', type: 'array', + hint: 'The UIDs of the specific items to include in the submittal package.' }, + { name: 'ball_in_court_status', + hint: 'Reference to the role of the user from whom the next step is expected.' \ + ' Can be \'manager\', \'submitter\', or \'reviewer\'.' }, + { name: 'design_review_due_date', type: 'date', + hint: 'Due date for the design review.' }, + { name: 'file_group_uid', + hint: 'UID of the file group to associate with this submittal package.' }, + { name: 'general_contractor_review_due_date', type: 'date', + hint: 'Due date of the general contractor\'s review.' }, + { name: 'lead_time_days', type: 'integer', + hint: 'Number of days of lead time provided for this submittal package.' }, + { name: 'notes' }, + { name: 'required_on_job_date', type: 'date', + hint: 'The date when the submitted material is required on the job.' }, + { name: 'submittal_due_date', type: 'date', + hint: 'Due date for this submittal package.' }, + { name: 'managers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of manager.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'reviewers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of reviewer.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'watchers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of watcher.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + } + ] + when 'submittals/item' + [ + { name: 'name', + hint: 'Name of the submittal item.' }, + { name: 'description', + hint: 'Description of the submittal package.' }, + { name: 'package_uid', label: 'Submittal Package ID', + hint: 'ID of the submittal package to which this item should be associated.' }, + { name: 'submittal_due_date', type: 'date', + hint: 'Date when the submittal is due.' }, + { name: 'lead_time_days', type: 'integer', + hint: 'The number of days of lead time provided for this submittal item.' }, + { name: 'required_on_job_date', type: 'date', + hint: 'The date when the submitted material is required on the job.' }, + { name: 'design_review_due_date', type: 'date', + hint: 'The date when the design review is due.' }, + { name: 'general_contractor_review_due_date', type: 'date', + hint: 'The date when the general contractor\'s review is due.' }, + { name: 'managers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of manager.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'reviewers', type: 'array', of: 'object', + hint: 'A list describing users assigned the role of reviewer.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'submitters', type: 'array', of: 'object', + hint: 'A list describing users assigned the role of submitter.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + }, + { name: 'watchers', type: 'array', of: 'object', + hint: 'A list describing users assigned the role of watcher.', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group' } + ] + } + ] else [] end.concat( @@ -1497,10 +1590,13 @@ } ] ).concat( - if config_fields['object'] != 'project' - [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false }] + case config_fields['object'] + when 'submittals/package' + [{ name: 'uid', label: 'Submittal Package ID', optional: false }] + when 'submittals/item' + [{ name: 'uid', label: 'Submittal Item ID', optional: false }] else - [] + [{ name: 'uid', label: "#{config_fields['object'].labelize} ID", optional: false }] end ) end From f78e88e0491471b8735fbc9172daabab8e37a031 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:25:38 -0400 Subject: [PATCH 69/96] update `get_object` action to include field report exports, submittal item, submittal package, submittal file group, and submittal review status --- custom_connectors/oauth2/plangrid.rb | 72 ++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 58abb1eb..a2f785a7 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -124,8 +124,22 @@ { name: 'limit', type: 'integer', hint: 'Number of records to retrieve.' } ] + when 'field_reports/export' + [{ name: 'uid', label: 'Export ID', optional: false }] when 'role', 'project' [] + when 'submittals/item' + [{ name: 'uids', label: 'Submittal Item ID', optional: false }] + when 'submittals/package' + [{ name: 'uid', label: 'Submittal Package ID', optional: false, + hint: 'ID can be found at the end of the url.' }] + when 'submittals_file_group' + [ + { name: 'uid', label: 'Submittal Package ID', optional: false, + hint: 'ID can be found at the end of the url.' }, + { name: 'created_after', type: 'date_time', + hint: 'Only return file groups created after the specified date.' } + ] else [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false, hint: 'ID can be found at the end of the url.' }] @@ -932,6 +946,51 @@ { name: 'url' } ]} ] + when 'submittals_file_group' + [ + { name: 'package_uid', label: 'Submittal Package ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'data', label: 'File Groups', + type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'File Group ID' }, + { name: 'files', type: 'array', of: 'object', properties: [ + { name: 'document_uid', label: 'Document ID' }, + { name: 'name' }, + { name: 'url' }, + { name: 'created_at', type: 'date_time' }, + { name: 'file_group_uid' } + ]}, + { name: 'package', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' } + ]}, + { name: 'upload_completed', type: 'boolean'} + ] + }, + { name: 'total_count' }, + { name: 'next_page_url' } + ] + when 'submittals_review_status' + [ + { name: 'package_uid', label: 'Submittal Package ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'data', label: 'Review Status', + type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'Review ID' }, + { name: 'review_response_uid', label: 'Review Response ID' }, + { name: 'is_official_review', type: 'boolean' }, + { name: 'package_version', type: 'integer' }, + { name: 'file_group_uid', label: 'File Group ID' }, + { name: 'created_at' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'User ID' }, + { name: 'url' } + ]} + ] + }, + { name: 'total_count' }, + { name: 'next_page_url' } + ] end end }, @@ -2050,8 +2109,21 @@ case input['object'] when 'project' get("/projects/#{input['project_uid']}") + when 'field_reports/export' + get("/projects/#{input['project_uid']}/field_reports/export/#{input['uid']}") when 'sheet_packet' get("/projects/#{input['project_uid']}/sheets/packets/#{input['uid']}") + when 'submittals/item' + get("/projects/#{input['project_uid']}/submittals/items?uids=#{input['uids']}").dig('data',0) + when 'submittals_file_group' + get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/file_groups") + .merge('package_uid' => input['uid']) + when 'submittals_history' + get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/history") + .merge('package_uid' => input['uid']) + when 'submittals_review_status' + get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/reviews") + .merge('package_uid' => input['uid']) else get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") end.merge('project_uid' => input['project_uid']) From 1d253bbc16fdf4e7e37deec5003c68c05bf6deeb Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:30:28 -0400 Subject: [PATCH 70/96] add `download object` action for documents, field report exports, and sheet packets --- custom_connectors/oauth2/plangrid.rb | 91 ++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index a2f785a7..015628d6 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1749,6 +1749,20 @@ end }, + download_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'field_reports/export' + [{ name: 'uid', label: 'Export ID', optional: false }] + when 'sheets/packet' + [{ name: 'uid', label: "Sheet Packet ID", optional: false, + hint: 'Ensure the status of the sheet packet export is `complete` before downloading.' }] + else + [{ name: 'uid', label: "#{config_fields['object'].labelize} ID", optional: false }] + end + end + }, + trigger_input: { fields: lambda do |_connection, config_fields| if config_fields['object'] != 'project' @@ -2266,6 +2280,75 @@ call(:get_sample_output, input['object'], input['project_uid'] || "") end }, + + download_object: { + title: 'Download object', + description: lambda do |_, objects| + "Download #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Download object in PlanGrid", + + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'download_object_list', + toggle_hint: 'Select object', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| + [ + { + name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + hint: 'If your project is not in top 50, use project ID toggle.', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + }, + ].concat(object_definitions['download_input_schema']) + end, + + execute: lambda do |_connection, input| + case input['object'] + when 'field_reports/export' + record = get("/projects/#{input['project_uid']}/field_reports/export/#{input['uid']}") + file_content = get(record['url'] || record['file_url']). + response_format_raw. + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + { content: file_content } + else + record = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") + file_content = get(record['url'] || record['file_url']). + response_format_raw. + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + { content: file_content } + end + end, + + output_fields: lambda do |object_definitions| + [ + { name: 'content', label: 'File Contents' } + ] + end }, triggers: { @@ -2595,6 +2678,14 @@ 'telecom', 'education-k-12', 'education-higher', 'gov-federal', 'gov-state-local', 'other'].map { |type| [type.labelize, type] } end, + + download_object_list: lambda do |_connection| + [ + ['Document', 'attachment'], + ['Field Report Export', 'field_reports/export'], + ['Sheet Packet', 'sheets/packet'] + ] + end, project_folders: lambda do |_connection, project_uid:| if project_uid.length == 36 From 355a55822a1218998f64636eeea9b784753414a3 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:32:40 -0400 Subject: [PATCH 71/96] update `update_object_list` and `upload_object_list` picklists --- custom_connectors/oauth2/plangrid.rb | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 015628d6..9e99c58b 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2638,13 +2638,24 @@ end, update_object_list: lambda do |_connection| - [["Project", "project"], ["Task List", "issue_list"], ["Task", "issue"], ["RFI", "rfi"], - ["Photo Metadata", "photo"]] + [ + ['Project', 'project'], + ['Photo', 'photo'], + ['RFI', 'rfi'], + ['Task List', 'issue_list'], + ['Task', 'issue'], + ['Submittal Package', 'submittals/package'], + ['Submittal Item', 'submittals/item'] + ] end, upload_object_list: lambda do |_connection| - [["Document", "attachment"], ["Photo", "photo"], ["File to sheet version", "file_upload"], - ["Complete version", "version_upload"]] + [ + ['Document', 'attachment'], + ['Photo', 'photo'], + ['File to Sheet Version', 'file_upload'], + ['Complete Sheet Version', 'version_upload'] + ] end, get_objects: lambda do |_connection| From 152f6665bce86ac423c6e24303066cce9d2c54b0 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:35:26 -0400 Subject: [PATCH 72/96] add field report templates to `search_object` action --- custom_connectors/oauth2/plangrid.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 9e99c58b..12309ae4 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2219,7 +2219,7 @@ output_fields: lambda do |object_definitions| [ { - name: 'data', type: 'array', of: 'object', properties: object_definitions['get_output_schema'] + name: 'data', label: 'Results', type: 'array', of: 'object', properties: object_definitions['get_output_schema'] }, { name: 'total_count', label: 'Total Count', type: 'integer' }, { name: 'next_page_url', label: 'Next Page URL' } @@ -2665,8 +2665,20 @@ end, search_objects: lambda do |_connection| - [["RFI Status", "rfi_status"], ["Role", "role"], ["Field Report", "field_report"], - ["Field Report Template", "field_report_template"]] + [ + ['Field Report', 'field_report'], + ['Field Report Template', 'field_report_template'], + ['RFI Status', 'rfi_status'], + ['Role', 'role'] + ] + end, + + download_object_list: lambda do |_connection| + [ + ['Document', 'attachment'], + ['Field Report Export', 'field_reports/export'], + ['Sheet Packet', 'sheets/packet'] + ] end, object_list: lambda do |_connection| From 1504f03655a70b1ac76c0b928189a7b6052c5a83 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:35:59 -0400 Subject: [PATCH 73/96] add missing closing curly bracket to `download object` action --- custom_connectors/oauth2/plangrid.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 12309ae4..2373dcf2 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2349,6 +2349,7 @@ { name: 'content', label: 'File Contents' } ] end + } }, triggers: { From 36ff76513b0047590ed24491caa5253914b30be2 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:40:03 -0400 Subject: [PATCH 74/96] adjust `new or updated object` trigger for documents to use the `/documents`/ endpoint --- custom_connectors/oauth2/plangrid.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 2373dcf2..5bed6467 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2487,6 +2487,9 @@ elsif input['object'] == 'field_report' get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). params(limit: limit, skip: skip, updated_after: updated_after) + elsif input['object'] == 'attachment' + get("/projects/#{input['project_uid']}/documents"). + params(limit: limit, skip: skip, updated_after: updated_after) else get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). params(limit: limit, skip: skip, updated_after: updated_after) @@ -2506,6 +2509,10 @@ field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge), 'project_uid' => input['project_uid']) end + elsif input['object'] == 'attachment' + response['data'].select { |o| o['type'] == 'file' }&.map do |document| + get("/projects/#{input['project_uid']}/attachments/#{document['uid']}") + end&.map { |o| o.merge('project_uid' => input['project_uid']) } else response['data']&.map { |o| o.merge('project_uid' => input['project_uid']) } end From 71bb491546c0e23637edb6a9fe91e46953ebb880 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:41:28 -0400 Subject: [PATCH 75/96] add `submittal item` to sample output method --- custom_connectors/oauth2/plangrid.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 5bed6467..15eafaaf 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2587,6 +2587,8 @@ } ] } + when 'submittals/items' + get("/projects/#{project_uid}/submittals/items")&.dig('data', 0)&.merge('project_uid' => project_uid) else get("/projects/#{project_uid}/#{object.pluralize}")&.dig('data', 0)&.merge('project_uid' => project_uid) end From c46bf997ca89d8e4bb477165e7fc207e8fc7ebab Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Sat, 9 May 2020 21:43:39 -0400 Subject: [PATCH 76/96] update `field_report_template` output to include project ID and cadence --- custom_connectors/oauth2/plangrid.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 15eafaaf..05b6f73f 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -592,12 +592,14 @@ when 'field_report_template' [ { name: 'uid', label: 'Field Report Template ID' }, + { name: 'project_uid', label: 'Project ID' }, { name: 'name' }, { name: 'field_reports', label: 'Field Reports', type: 'object', properties: [ { name: 'url' } ] }, + { name: 'cadence' }, { name: 'is_pdf', label: 'Is PDF', type: 'boolean' }, { name: 'pdf_url', label: 'PDF URL' }, { name: 'template_type', label: 'Template Type' }, From bc376ebb86ed75fe9a16b89aa7eb89c1706c1668 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Tue, 12 May 2020 11:55:00 -0400 Subject: [PATCH 77/96] - remove `lead_time_days` from submittal objects - update label for `design_review_due_date` to `Reviewer due date` - update label for `general_contractor_due_date to `Manager due date` --- custom_connectors/oauth2/plangrid.rb | 53 ++++++++++++---------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 05b6f73f..205e842b 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -827,7 +827,6 @@ { name: 'custom_id' }, { name: 'version' }, { name: 'ball_in_court_status' }, - { name: 'lead_time_days', type: 'integer' }, { name: 'submittals_due_date', type: 'date_time' }, { name: 'required_on_job_date', type: 'date_time' }, { name: 'transmission_status' }, @@ -838,8 +837,8 @@ { name: 'total_count', type: 'integer'} ]}, { name: 'visible_file_group_uid' }, - { name: 'design_review_due_date', type: 'date_time' }, - { name: 'general_contractor_review_due_date', type: 'date_time' }, + { name: 'design_review_due_date', type: 'date_time', label: 'Reviewer due date' }, + { name: 'general_contractor_review_due_date', type: 'date_time', label: 'Manager due date' }, { name: 'latest_review', type: 'object', properties: [ { name: 'uid', label: 'Review ID' }, { name: 'created_at', type: 'date_time' }, @@ -858,8 +857,8 @@ ]} ]}, { name: 'latest_review_response_uid' }, - { name: 'received_from_design_at', type: 'date_time' }, - { name: 'sent_to_design_at', type: 'date_time' }, + { name: 'received_from_design_at', type: 'date_time', label: 'Received from reviewer at' }, + { name: 'sent_to_design_at', type: 'date_time', label: 'Sent to reviewer at' }, { name: 'received_from_sub_at', type: 'date_time' }, { name: 'returned_to_sub_at', type: 'date_time' }, { name: 'managers', type: 'array', of: 'object', properties: [ @@ -920,8 +919,8 @@ { name: 'uid' }, { name: 'url' } ]}, - { name: 'design_review_due_date', type: 'date_time' }, - { name: 'general_contractor_review_due_date', type: 'date_time' }, + { name: 'design_review_due_date', type: 'date_time', label: 'Reviewer due date' }, + { name: 'general_contractor_review_due_date', type: 'date_time', label: 'Manager due date' }, { name: 'reviewers', type: 'array', of: 'object', properties: [ { name: 'type' }, { name: 'uid' }, @@ -1208,14 +1207,12 @@ { name: 'ball_in_court_status', hint: "Reference to the role of the user from whom the next step is expected." \ " Can be 'manager', 'submitter', or 'reviewer'." }, - { name: 'design_review_due_date', type: 'date', - hint: 'Due date for the design review.' }, + { name: 'design_review_due_date', type: 'date', label: 'Reviewer due date', + hint: 'The date when the review from reviewers\' is due.' }, { name: 'file_group_uid', hint: 'UID of the file group to associate with this submittal package.' }, - { name: 'general_contractor_review_due_date', type: 'date', - hint: "Due date of the general contractor's review." }, - { name: 'lead_time_days', type: 'integer', - hint: 'Number of days of lead time provided for this submittal package.' }, + { name: 'general_contractor_review_due_date', type: 'date', label: 'Manager due date', + hint: 'The date when the review from manager\'s is due.' }, { name: 'notes' }, { name: 'required_on_job_date', type: 'date', hint: 'The date when the submitted material is required on the job.' }, @@ -1253,14 +1250,12 @@ hint: 'ID of the submittal package to which this item should be associated.' }, { name: 'submittal_due_date', type: 'date', hint: 'Date when the submittal is due.' }, - { name: 'lead_time_days', type: 'integer', - hint: 'The number of days of lead time provided for this submittal item.' }, { name: 'required_on_job_date', type: 'date', hint: 'The date when the submitted material is required on the job.' }, - { name: 'design_review_due_date', type: 'date', - hint: 'The date when the design review is due.' }, - { name: 'general_contractor_review_due_date', type: 'date', - hint: 'The date when the general contractor\'s review is due.' }, + { name: 'design_review_due_date', type: 'date', label: 'Reviewer due date', + hint: 'The date when the review from reviewers\' is due.' }, + { name: 'general_contractor_review_due_date', type: 'date', label: 'Manager due date', + hint: 'The date when the review from manager\'s is due.' }, { name: 'managers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of manager.', properties: [ @@ -1545,14 +1540,12 @@ { name: 'ball_in_court_status', hint: 'Reference to the role of the user from whom the next step is expected.' \ ' Can be \'manager\', \'submitter\', or \'reviewer\'.' }, - { name: 'design_review_due_date', type: 'date', - hint: 'Due date for the design review.' }, + { name: 'design_review_due_date', type: 'date', label: 'Reviewer due date', + hint: 'The date when the review from reviewers\' is due.' }, { name: 'file_group_uid', hint: 'UID of the file group to associate with this submittal package.' }, - { name: 'general_contractor_review_due_date', type: 'date', - hint: 'Due date of the general contractor\'s review.' }, - { name: 'lead_time_days', type: 'integer', - hint: 'Number of days of lead time provided for this submittal package.' }, + { name: 'general_contractor_review_due_date', type: 'date', label: 'Manager review due date', + hint: 'The date when the review from manager\'s is due.' }, { name: 'notes' }, { name: 'required_on_job_date', type: 'date', hint: 'The date when the submitted material is required on the job.' }, @@ -1590,14 +1583,12 @@ hint: 'ID of the submittal package to which this item should be associated.' }, { name: 'submittal_due_date', type: 'date', hint: 'Date when the submittal is due.' }, - { name: 'lead_time_days', type: 'integer', - hint: 'The number of days of lead time provided for this submittal item.' }, { name: 'required_on_job_date', type: 'date', hint: 'The date when the submitted material is required on the job.' }, - { name: 'design_review_due_date', type: 'date', - hint: 'The date when the design review is due.' }, - { name: 'general_contractor_review_due_date', type: 'date', - hint: 'The date when the general contractor\'s review is due.' }, + { name: 'design_review_due_date', type: 'date', label: 'Reviewer due date', + hint: 'The date when the review from reviewers is due.' }, + { name: 'general_contractor_review_due_date', type: 'date', label: 'Manager review due date', + hint: 'The date when the review from manager\'s is due.' }, { name: 'managers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of manager.', properties: [ From 8bc918461b9154a6603a6f22ca3630ff1984caba Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Tue, 12 May 2020 11:56:52 -0400 Subject: [PATCH 78/96] - update picklist for `get objects` - update picklist for `object_list` (new objects trigger) - update picklist for `object_list_new` (new or updated objects trigger) --- custom_connectors/oauth2/plangrid.rb | 47 +++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 205e842b..c7f67eb1 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2662,9 +2662,23 @@ end, get_objects: lambda do |_connection| - [["Project", "project"], ["RFI", "rfi"], ["Task", "issue"], ["User", "user"], - ["Snapshot", "snapshot"], ["Sheet", "sheet"], ["Sheet Packet", "sheet_packet"], - ["Photo", "photo"], ["Document", "attachment"], ["Task_list", "issue_list"]] + [ + ['Project', 'project'], + ['Document', 'attachment'], + ['Field Report Export', 'field_reports/export'], + ['Photo', 'photo'], + ['RFI', 'rfi'], + ['Sheet', 'sheet'], + ['Sheet Packet', 'sheet_packet'], + ['Snapshot', 'snapshot'], + ['Submittal Package', 'submittals/package'], + ['Submittal Item', 'submittals/item'], + ['Submittal Package File Group', 'submittals_file_group'], + ['Submittal Package Review Status', 'submittals_review_status'], + ['Task', 'issue'], + ['Task List', 'issue_list'], + ['User', 'user'] + ] end, search_objects: lambda do |_connection| @@ -2685,13 +2699,32 @@ end, object_list: lambda do |_connection| - [["Project", "project"], ["Sheet", "sheet"], ["Document", "attachment"], ["Task", "issue"], ["RFI", "rfi"], - ["Annotation", "annotation"], ["Photo", "photo"], ["Snapshot", "snapshot"], ["Field Report", "field_report"]] + [ + ['Project', 'project'], + ['Annotation', 'annotation'], + ['Document', 'attachment'], + ['Field Report', 'field_report'], + ['Photo', 'photo'], + ['RFI', 'rfi'], + ['Sheet', 'sheet'], + ['Snapshot', 'snapshot'], + ['Task', 'issue'] + ] end, object_list_new: lambda do |_connection| - [["Project", "project"], ["Task", "issue"], ["RFI", "rfi"], ["Sheet", "sheet"], ["Field Report", "field_report"], - ["Document", "attachment"], ["Annotation", "annotation"]] + [ + ['Project', 'project'], + ['Annotation', 'annotation'], + ['Document', 'attachment'], + ['Field Report', 'field_report'], + ['Field Report Template', 'field_report_template'], + ['RFI', 'rfi'], + ['Sheet', 'sheet'], + ['Submittal Package', 'submittals/package'], + ['Submittal Item', 'submittals/item'], + ['Task', 'issue'] + ] end, project_list: lambda do |_connection| From 72473f3a1a91c311c688e2c841e9daaf02a89d29 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 20:58:27 -0400 Subject: [PATCH 79/96] update to latest version of connector code as of july 2 2020 --- custom_connectors/oauth2/plangrid.rb | 5482 ++++++++++++++------------ 1 file changed, 2871 insertions(+), 2611 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index c7f67eb1..0a4de31b 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1,1723 +1,2226 @@ { - title: 'PlanGrid', - connection: { - fields: [ - { - name: 'client_id', - label: 'Client ID', - optional: false, - hint: 'To create client id, you need to register an application' \ - ' under Admin Console => Project => Oauth => Create Oauth app' - }, - { - name: 'client_secret', - label: 'Client secret', - control_type: 'password', - optional: false, - hint: 'To create client id, you need to register an application' \ - ' under Admin Console => Project => Oauth => Create Oauth app' - } - ], - authorization: { - type: 'oauth2', - authorization_url: lambda do |connection| - 'https://io.plangrid.com/oauth/authorize?response_type=' \ - "code&client_id=#{connection['client_id']}&" \ - 'scope=write:projects%20read:profile' - end, - acquire: lambda do |connection, auth_code, redirect_uri| - response = post('https://io.plangrid.com/oauth/token'). - payload(client_id: connection['client_id'], - client_secret: connection['client_secret'], - grant_type: 'authorization_code', - code: auth_code, - redirect_uri: redirect_uri). - request_format_www_form_urlencoded - [response, nil, nil] - end, - refresh_on: [401, 403], - refresh: lambda do |_connection, refresh_token| - post('https://io.plangrid.com/oauth/token'). - payload(grant_type: 'refresh_token', - refresh_token: refresh_token). - request_format_www_form_urlencoded - end, - apply: lambda do |_connection, access_token| - if current_url.include?('https://io.plangrid.com') - headers(Authorization: "Bearer #{access_token}", - Accept: 'application/vnd.plangrid+json; version=1') + title: 'PlanGrid', + + connection: { + authorization: { + type: 'oauth2', + + authorization_url: lambda do + "https://io.plangrid.com/oauth/authorize?response_type=code&scope=write:projects%20read:profile" + end, + + token_url: lambda do + "https://io.plangrid.com/oauth/token" + end, + + refresh_on: [401, 403], + + apply: lambda do |_connection, access_token| + if current_url.include?('https://io.plangrid.com') + headers(Authorization: "Bearer #{access_token}", + Accept: 'application/vnd.plangrid+json; version=1') + end end + }, + + base_uri: lambda do |_connection| + 'https://io.plangrid.com' end }, - base_uri: lambda do |_connection| - 'https://io.plangrid.com' - end - }, - test: ->(_connection) { get('/me') }, + test: ->(_connection) { get('/me') }, - object_definitions: { - get_input_schema: { - fields: lambda do |_connection, config_fields| - case config_fields['object'] - when 'rfi_status' - [ - { name: 'limit', type: 'integer', control_type: 'integer', - hint: 'Number of RFI statuses to retrieve. Maximum value of 50.' }, - { name: 'skip', type: 'integer', control_type: 'integer', - hint: 'Number of RFI statuses to skip in the set of results.' } - ] - when 'field_report' - [ - { name: 'template_uid', label: 'Field Report Template ID', - hint: 'Only retrieve field reports for the specified template ID.'}, - { name: 'report_date_min', type: 'date', - label: 'Report Start Date', - hint: 'Only retrieve field reports between a date range starting with this date in UTC format.' }, - { name: 'report_date_max', type: 'date', - label: 'Report End Date', - hint: 'Only retrieve field reports between a date range ending with this date in UTC format.' }, - { name: 'updated_after', label: 'Updated After', type: 'date_time', - hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, - { name: 'skip', type: 'integer', - hint: 'Number of records to skip.' }, - { name: 'limit', type: 'integer', - hint: 'Number of records to retrieve.' }, - { - name: 'sort_by', label: 'Sort by column', control_type: 'select', - pick_list: - %w[report_date updated_at]&.map { |e| [e.labelize, e] }, - toggle_hint: 'Select column', - toggle_field: { - name: 'sort_by', label: 'Sort by column', type: 'string', control_type: 'text', - toggle_hint: 'Enter column', - hint: 'Allowed values report_date or updated_at.' - } - }, - { - name: 'sort_order', label: 'Sort by order', control_type: 'select', - pick_list: [%w[Ascending asc], %w[Descending desc]], - toggle_hint: 'Select order', - toggle_field: { - name: 'sort_by', label: 'Sort by order', type: 'string', control_type: 'text', - toggle_hint: 'Enter order', - hint: 'Allowed values Ascending or Descending.' + object_definitions: { + get_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'rfi_status' + [ + { name: 'limit', type: 'integer', control_type: 'integer', + hint: 'Number of RFI statuses to retrieve. Maximum value of 50.' }, + { name: 'skip', type: 'integer', control_type: 'integer', + hint: 'Number of RFI statuses to skip in the set of results.' } + ] + when 'field_report' + [ + { name: 'report_date_min', type: 'date', + label: 'Report Start Date', + hint: 'Only retrieve field reports between a date range starting with this date in UTC format.' }, + { name: 'report_date_max', type: 'date', + label: 'Report End Date', + hint: 'Only retrieve field reports between a date range ending with this date in UTC format.' }, + { name: 'updated_after', label: 'Updated After', type: 'date_time', + hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, + { + name: 'sort_by', label: 'Sort by column', control_type: 'select', + pick_list: + %w[report_date updated_at]&.map { |e| [e.labelize, e] }, + toggle_hint: 'Select column', + toggle_field: { + name: 'sort_by', label: 'Sort by column', type: 'string', control_type: 'text', + toggle_hint: 'Enter column', + hint: 'Allowed values report_date or updated_at.' + } + }, + { + name: 'sort_order', label: 'Sort by order', control_type: 'select', + pick_list: [%w[Ascending asc], %w[Descending desc]], + toggle_hint: 'Select order', + toggle_field: { + name: 'sort_by', label: 'Sort by order', type: 'string', control_type: 'text', + toggle_hint: 'Enter order', + hint: 'Allowed values Ascending or Descending.' + } + }, + { + name: 'output_schema', + control_type: 'schema-designer', + extends_schema: true, + label: 'PDF field values', + hint: 'Manually define the values expected of your PDF field values in the field report.', + optional: true } - }, - { - name: 'output_schema', - control_type: 'schema-designer', - extends_schema: true, - label: 'PDF field values', - hint: 'Manually define the values expected of your PDF field values in the field report.', - optional: true - } - ] - when 'field_report_template' - [ - { name: 'updated_after', label: 'Updated After', type: 'date_time', - hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, - { name: 'updated_before', label: 'Updated Before', type: 'date_time', - hint: 'Only retrieve field reports created/updated before specified UTC date and time.' }, - { name: 'skip', type: 'integer', - hint: 'Number of records to skip.' }, - { name: 'limit', type: 'integer', - hint: 'Number of records to retrieve.' } - ] - when 'field_reports/export' - [{ name: 'uid', label: 'Export ID', optional: false }] - when 'role', 'project' - [] - when 'submittals/item' - [{ name: 'uids', label: 'Submittal Item ID', optional: false }] - when 'submittals/package' - [{ name: 'uid', label: 'Submittal Package ID', optional: false, - hint: 'ID can be found at the end of the url.' }] - when 'submittals_file_group' - [ - { name: 'uid', label: 'Submittal Package ID', optional: false, - hint: 'ID can be found at the end of the url.' }, - { name: 'created_after', type: 'date_time', - hint: 'Only return file groups created after the specified date.' } - ] - else - [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false, - hint: 'ID can be found at the end of the url.' }] + ] + when 'role', 'project' + [] + when 'field_report_template' + [ + { name: 'updated_after', label: 'Updated after', type: 'date_time', + hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, + { name: 'updated_before', label: 'Updated before', type: 'date_time', + hint: 'Only retrieve field reports created/updated before specified UTC date and time.' }, + { name: 'skip', type: 'integer', control_type: 'integer', hint: 'Number of records to skip.' }, + { name: 'limit', type: 'integer', control_type: 'integer', hint: 'Number of records to retrieve. Maximum value of 50.' } + ] + when 'field_report_export' + [{ name: 'uid', label: 'Export ID', optional: false }] + when 'submittal_item' + [ + { name: 'updated_after', label: 'Updated after', type: 'date_time', + hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, + { name: 'skip', type: 'integer', control_type: 'integer', hint: 'Number of records to skip.' }, + { name: 'limit', type: 'integer', control_type: 'integer', hint: 'Number of records to retrieve. Maximum value of 50.' }, + { name: 'uids', label: 'Submittal item ID', optional: true, hint: 'A comma separated list of submittal item IDs.' } + ] + when 'submittal_package', 'submittal_review_status', 'submittal_history' + [{ name: 'uid', label: 'Submittal package ID', optional: false, + hint: 'ID can be found at the end of the url.' }] + when 'submittal_file_group' + [ + { name: 'uid', label: 'Submittal package ID', optional: false, + hint: 'ID can be found at the end of the url.' }, + { name: 'created_after', type: 'date_time', + hint: 'Only return file groups created after the specified date.' } + ] + else + [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false, + hint: 'ID can be found at the end of the url.' }] + end end - end - }, + }, - get_output_schema: { - fields: lambda do |_connection, config_fields| - case config_fields['object'] - when 'project' - [ - { - name: 'uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project ID', - sticky: true, - toggle_hint: 'Select project', - toggle_field: { + get_output_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'project' + [ + { name: 'uid', - type: 'string', - control_type: 'text', - sticky: true, + control_type: 'select', + pick_list: 'project_list', label: 'Project ID', - toggle_hint: 'Enter project ID', - hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } - }, - { name: 'name', label: 'Project Name', sticky: true }, - { name: 'custom_id', label: 'Project Code', sticky: true }, - { name: 'organization_id', label: 'Organization ID' }, - { - name: 'type', control_type: 'select', - label: 'Project Type', sticky: true, - pick_list: 'project_types', - toggle_hint: 'Select project type', - toggle_field: { - name: 'type', - label: 'Project type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Project type with possible values of general,' \ - ' manufacturing, power, water-sewer-waste, industrial-' \ - 'petroleum, transportation, hazardous-waste, telecom, ' \ - 'education-k-12, education-higher, gov-federal, ' \ - 'gov-state-local, or other' + sticky: true, + toggle_hint: 'Select project', + toggle_field: { + name: 'uid', + type: 'string', + control_type: 'text', + sticky: true, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + }, + { name: 'name', label: 'Project Name', sticky: true }, + { name: 'custom_id', label: 'Project Code', sticky: true }, + { name: 'organization_id', label: 'Organization ID' }, + { + name: 'type', control_type: 'select', + label: 'Project Type', sticky: true, + pick_list: 'project_types', + toggle_hint: 'Select project type', + toggle_field: { + name: 'type', + label: 'Project type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Project type with possible values of general,' \ + ' manufacturing, power, water-sewer-waste, industrial-' \ + 'petroleum, transportation, hazardous-waste, telecom, ' \ + 'education-k-12, education-higher, gov-federal, ' \ + 'gov-state-local, or other' + } + }, + { name: 'status', label: 'Project Status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project Owner' }, + { name: 'start_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project Start Date', + hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'end_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project End Date', + hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'street_1', sticky: true, + label: 'Street Line 1' }, + { name: 'street_2', sticky: true, label: 'Street line 2' }, + { name: 'city', sticky: true, label: 'Town or City' }, + { name: 'region', sticky: true, label: 'State, Province, or Region' }, + { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, + { name: 'country', + sticky: true, + hint: 'Project address country in 2-letter ISO 3166 code.' }, + { name: 'latitude' }, + { name: 'longitude' }, + { name: 'updated_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + label: 'Updated at' } + ] + when 'attachment' + [ + { name: 'uid', label: 'Document ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'name', label: 'Document Name' }, + { name: 'folder' }, + { name: 'url' }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'deleted', type: 'boolean', control_type: 'checkbox' } + ] + when 'issue' + [ + { name: 'uid', label: 'Task ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'number', type: 'integer' }, + { name: 'title' }, + { + name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending", "closed".' + } + }, + { + name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work", "other".' + } + }, + { + name: 'assignees', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'Assignee ID' }, + { name: 'type' } + ] + }, + { + name: 'followers', label: 'Watchers', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'Follower ID' }, + { name: 'type' } + ] + }, + { name: 'room', label: 'Location' }, + { name: 'start_date', label: 'Start Date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, + { name: 'closed_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'string', label: 'Stamp', + hint: 'One to two character stamp associated with task.' }, + { + name: 'issue_list', label: 'Task List', type: 'object', properties: [ + { name: 'uid', label: 'Task List ID' }, + { name: 'url' } + ] + }, + { name: 'description' }, + { name: 'cost_impact', label: 'Cost Impact', type: 'integer' }, + { + name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'currency_code', label: 'Currency Code', + hint: 'The ISO-4217 currency code of the cost_impact,' \ + ' Currently only supports USD. maybe null if cost_impact is ' \ + 'not specified' }, + { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, + { + name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', + control_type: 'checkbox' + }, + { + name: 'current_annotation', type: 'object', properties: [ + { name: 'uid', label: 'Annotation ID' }, + { name: 'color' }, + { name: 'stamp' }, + { name: 'visibility' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { + name: 'sheet', type: 'object', properties: [ + { name: 'uid', label: 'Sheet ID' }, + { name: 'url' } + ] + } + ] + }, + { + name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'updated_at', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + type: 'date_time' }, + { + name: 'updated_by', type: 'object', properties: [ + { name: 'uid' }, + { name: 'url' }, + { name: 'email' } + ] } - }, - { name: 'status', label: 'Project Status', sticky: true }, - { name: 'owner', sticky: true, label: 'Project Owner' }, - { name: 'start_date', type: 'date', - sticky: true, - render_input: 'date_conversion', - parse_output: 'date_conversion', - label: 'Project Start Date', - hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, - { name: 'end_date', type: 'date', - sticky: true, - render_input: 'date_conversion', - parse_output: 'date_conversion', - label: 'Project End Date', - hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, - { name: 'street_1', sticky: true, - label: 'Street Line 1' }, - { name: 'street_2', sticky: true, label: 'Street line 2' }, - { name: 'city', sticky: true, label: 'Town or City' }, - { name: 'region', sticky: true, label: 'State, Province, or Region' }, - { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, - { name: 'country', - sticky: true, - hint: 'Project address country in 2-letter ISO 3166 code.' }, - { name: 'latitude' }, - { name: 'longitude' }, - { name: 'updated_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - label: 'Updated at' } - ] - when 'attachment' - [ - { name: 'uid', label: 'Document ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'name', label: 'Document Name' }, - { name: 'folder' }, - { name: 'url' }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { - name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] - }, - { name: 'deleted', type: 'boolean', control_type: 'checkbox' } - ] - when 'issue' - [ - { name: 'uid', label: 'Task ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'number', type: 'integer' }, - { name: 'title' }, - { - name: 'status', control_type: 'select', pick_list: - %w[open in_review pending closed].select { |op| [op.labelize, op] }, - toggle_hint: 'Select status', - toggle_field: { - name: 'status', - label: 'Status', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are : "open", "in_review", "pending", "closed".' + ] + when 'file_upload' + [ + { name: 'uid' }, + { + name: 'aws_post_form_arguments', type: 'object', + properties: [ + { name: 'action' }, + { name: 'fields', type: 'array', of: 'object', properties: [ + { name: 'name' }, + { name: 'value' } + ] } + ] + }, + { name: "project_uid", label: "Project ID" }, + { name: 'webhook_url' } + ] + when 'annotation' + [ + { name: 'uid', label: 'Annotation ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'color' }, + { name: 'stamp' }, + { name: 'visibility' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { + name: 'sheet', type: 'object', properties: [ + { name: 'uid', label: 'Sheet ID' }, + { name: 'url' } + ] } - }, - { - name: 'type', control_type: 'select', - pick_list: [ - %w[issue issue], - %w[Planned\ work planned_work], - %w[other other] - ], - toggle_hint: 'Select type', - toggle_field: { - name: 'type', - label: 'Type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: "issue", "planned_work", "other".' + ] + when 'snapshot' + [ + { name: 'uid', label: 'Snapshot ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'title' }, + { name: 'url' }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { + name: 'sheet', type: 'object', properties: [ + { name: 'uid', label: 'Sheet ID' }, + { name: 'url' } + ] + }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' } - }, - { - name: 'assignees', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'Assignee ID' }, - { name: 'type' } - ] - }, - { - name: 'followers', label: 'Watchers', type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'Follower ID' }, - { name: 'type' } - ] - }, - { name: 'room', label: 'Location' }, - { name: 'start_date', label: 'Start Date', - type: 'date_time', - render_input: 'date_conversion', - parse_output: 'date_conversion' }, - { name: 'closed_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'due_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'string', label: 'Stamp', - hint: 'One to two character stamp associated with task.' }, - { - name: 'issue_list', label: 'Task List', type: 'object', properties: [ - { name: 'uid', label: 'Task List ID' }, - { name: 'url' } - ] - }, - { name: 'description' }, - { name: 'cost_impact', label: 'Cost Impact', type: 'integer' }, - { - name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', - control_type: 'checkbox' - }, - { name: 'currency_code', label: 'Currency Code', - hint: 'The ISO-4217 currency code of the cost_impact,' \ - ' Currently only supports USD. maybe null if cost_impact is ' \ - 'not specified' }, - { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, - { - name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', - control_type: 'checkbox' - }, - { - name: 'current_annotation', type: 'object', properties: [ - { name: 'uid', label: 'Annotation ID' }, - { name: 'color' }, - { name: 'stamp' }, - { name: 'visibility' }, - { - name: 'deleted', type: 'boolean', - control_type: 'checkbox' - }, - { - name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'Sheet ID' }, - { name: 'url' } - ] - } - ] - }, - { - name: 'comments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] - }, - { - name: 'photos', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, - { name: 'url' } - ] - }, - { - name: 'deleted', type: 'boolean', - control_type: 'checkbox' - }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { - name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] - }, - { name: 'updated_at', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - type: 'date_time' }, - { - name: 'updated_by', type: 'object', properties: [ - { name: 'uid' }, - { name: 'url' }, - { name: 'email' } - ] - } - ] - when 'file_upload' - [ - { name: 'uid' }, - { - name: 'aws_post_form_arguments', type: 'object', - properties: [ - { name: 'action' }, - { name: 'fields', type: 'array', of: 'object', properties: [ + ] + when 'photo' + [ + { name: 'uid', label: 'Photo ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'title' }, + { name: 'url', label: 'URL' }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'deleted', type: 'boolean' } + ] + when 'field_report' + [ + { name: 'uid', label: 'Field Report ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'title' }, + { name: 'description' }, + { name: 'report_date', label: 'Report Date', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'status' }, + { + name: 'field_report_type', label: 'Field Report Type', type: 'object', properties: [ + { name: 'name' }, + { name: 'status' }, + { name: 'uid', label: 'Field Report ID' }, + { name: 'project_uid' }, + { name: 'template_type' } + ] + }, + { name: 'pdf_url', label: 'PDF URL' }, + { + name: 'pdf_form_values', label: 'PDF Form Values', type: 'array', of: 'object', + properties: [ { name: 'name' }, { name: 'value' } - ] } - ] - }, - { name: "project_uid", label: "Project ID" }, - { name: 'webhook_url' } - ] - when 'annotation' - [ - { name: 'uid', label: 'Annotation ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'color' }, - { name: 'stamp' }, - { name: 'visibility' }, - { - name: 'deleted', type: 'boolean', - control_type: 'checkbox' - }, - { - name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'Sheet ID' }, + ] + }, + { + name: 'pdf_form_fields', label: 'PDF Field Values', type: 'object', properties: call('dynamic_pdf_output_schema', config_fields['output_schema']) + }, + { + name: 'pg_form_values', type: 'object', properties: [ + { + name: 'pg_worklog_entries', label: 'Work Log Entries', type: 'array', of: 'object', + properties: [ + { name: 'trade' }, + { name: 'timespan' }, + { name: 'headcount', type: 'integer' }, + { name: 'description' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'uid' } + ] + }, + { + name: 'pg_materials_entries', label: 'Material Entries', type: 'array', of: 'object', + properties: [ + { name: 'unit', type: 'integer' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, + { name: 'description' }, + { name: 'deleted', type: "boolean", control_type: 'checkbox' }, + { name: 'uid' } + ] + }, + { + name: 'pg_equipment_entries', label: 'Equipment Entries', type: 'array', of: 'object', + properties: [ + { name: 'timespan' }, + { name: 'quantity', type: 'integer' }, + { name: 'item' }, + { name: 'description' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'uid' } + ] + } + ] + }, + { + name: 'custom_items', label: 'Custom form items', type: 'array', + of: 'object', properties: [ + { name: 'section_label', label: 'Section name' }, + { name: 'item_label' }, + { name: 'value_name' }, + { name: 'notes' }, + { name: 'text_val', label: 'Text value' }, + { name: 'choice_val', label: 'Choice value' }, + { name: 'number_val', label: 'Number value', type: 'number' }, + { name: 'date_val', label: 'Date value', type: 'date_time', control_type: 'date_time' }, + { name: 'array_val', label: 'Array value', type: 'array', of: 'object', properties: [{ name: "value" }] }, + { name: 'toggle_val', label: 'Toggle value', type: 'integer', control_type: 'integer' } + ] + }, + { + name: 'attachments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'snapshots', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'email' }, + { name: 'uid', label: 'UID' }, + { name: 'url' } + ] + }, + { name: 'updated_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'weather', type: 'object', properties: [ + { name: 'humidity', type: 'number' }, + { name: 'precipitation_accumulation', type: 'number' }, + { name: 'precipitation_accumulation_unit' }, + { name: 'speed_unit' }, + { name: 'summary_key' }, + { name: 'temperature_max', type: 'integer' }, + { name: 'temperature_min' }, + { name: 'temperature_unit' }, + { name: 'wind_bearing', type: 'integer' }, + { name: 'wind_gust', type: 'number' }, + { name: 'wind_speed', type: 'number' } + ] + } + ] + when 'rfi' + [ + { name: 'uid', label: 'RFI ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'number', type: 'integer' }, + { + name: 'status', type: 'object', properties: [ + { name: 'uid', label: 'Status ID' }, + { name: 'label' }, + { name: 'color' } + ] + }, + { + name: 'locked', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'title' }, + { name: 'question' }, + { name: 'answer' }, + { name: 'sent_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { name: 'due_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'assigned_to', type: 'array', of: 'object', + properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'updated_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { + name: 'updated_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'created_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { + name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { + name: 'photos', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'attachments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'snapshots', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + }, + { + name: 'comments', type: 'object', properties: [ + { name: 'total_count', type: 'integer' }, + { name: 'url' } + ] + } + ] + when 'rfi_status' + [ + { name: 'uid', label: 'RFI status ID' }, + { name: 'label' }, + { name: 'color' }, + { name: "project_uid", label: "Project ID" } + ] + when 'user', 'user_invite' + [ + { name: 'uid', label: 'User ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'email' }, + { name: 'first_name', label: 'First Name' }, + { name: 'last_name', label: 'Last Name' }, + { name: 'language' }, + { + name: 'role', type: 'object', properties: [ + { name: 'uid', label: 'role ID' }, + { name: 'url' } + ] + }, + { name: 'removed', label: 'Removed?', type: 'boolean' } + ] + when 'sheet' + [ + { name: 'uid', label: 'Sheet ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'name' }, + { name: 'version_name', label: 'Version Name' }, + { name: 'description' }, + { name: 'tags', type: 'array', of: 'string', hint: 'An array of strings representing the' \ + ' tags added to this sheet.' }, + { + name: 'published_by', type: 'object', properties: [ + { name: 'uid', label: 'UID' }, + { name: 'url' }, + { name: 'email' } + ] + }, + { name: 'published_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'UTC date and time in ISO-8601 format.' }, + { + name: 'deleted', type: 'boolean', + control_type: 'checkbox' + }, + { name: 'uploaded_file_name', label: 'Uploaded file name' }, + { name: 'history_set_uid', label: 'History set ID' } + ] + when 'sheet_packet' + [ + { name: 'uid', label: 'Sheet Packet ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'status' }, + { name: 'file_url', label: 'File URL' }, + { + name: 'resource', type: 'object', properties: [ + { name: 'uid', label: 'Resource ID' }, + { name: 'url' } + ] + } + ] + when 'issue_list' + [ + { name: "uid", label: "Task List ID" }, + { name: "project_uid", label: "Project ID" }, + { name: "name", label: "Name" }, + { name: "deleted", label: "Deleted", type: "boolean", control_type: 'checkbox' } + ] + when 'role' + [ + { name: 'uid', label: 'Role ID' }, + { name: 'label', label: 'Role' }, + { name: "project_uid", label: "Project ID" } + ] + when 'sheet_upload' + [ + { name: 'uid', label: 'Sheet Version Upload ID' }, + { name: 'complete_url', label: 'Upload Completion URL' }, + { name: 'status' }, + { name: "project_uid", label: "Project ID" }, + { + name: 'file_upload_requests', label: 'File Upload Requests', + type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'File Upload ID' }, + { name: 'upload_status', label: 'File Upload Status' }, + { name: 'url', label: 'File Upload URL' } + ] + } + ] + when 'version_upload' + [ + { name: 'uid', label: 'Sheet Version ID' }, + { name: "project_uid", label: "Project ID" }, + { name: 'status', label: 'Status' } + ] + when 'field_report_template' + [ + { name: 'uid', label: 'Field report template ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'name' }, + { name: 'field_reports', label: 'Field reports', type: 'object', properties: [ { name: 'url' } - ] - } - ] - when 'snapshot' - [ - { name: 'uid', label: 'Snapshot ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'title' }, - { name: 'url' }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { - name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] - }, - { - name: 'sheet', type: 'object', properties: [ - { name: 'uid', label: 'Sheet ID' }, + ] }, + { name: 'cadence' }, + { name: 'is_pdf', label: 'Is PDF', type: 'boolean' }, + { name: 'pdf_url', label: 'PDF URL' }, + { name: 'template_type' }, + { name: 'status' }, + { name: 'group_permissions', label: 'Group permissions', type: 'array', of: 'object', properties: [ + { name: 'permissions', type: 'array', of: 'object', properties: [{ name: "value" }] }, + { name: 'role_key' }, + { name: 'role_name' }, + { name: 'role_uid', label: 'Role ID' } + ] }, + { name: 'user_permissions', label: 'User permissions', type: 'array', of: 'object', properties: [ + { name: 'permissions', type: 'array', of: 'object', properties: [{ name: "value" }] }, + { name: 'user_id', label: 'User ID' } + ] }, + { name: 'created_by', type: 'object', properties: [ + { name: 'email' }, + { name: 'uid', type: 'Creator ID' }, { name: 'url' } - ] - }, - { - name: 'deleted', type: 'boolean', - control_type: 'checkbox' - } - ] - when 'photo' - [ - { name: 'uid', label: 'Photo ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'title' }, - { name: 'url', label: 'URL' }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { - name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, + ] }, + { name: 'updated_at', type: 'date_time', control_type: 'date_time' } + ] + when 'field_report_export' + [ + { name: 'uid', label: 'Export ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'status' }, + { name: 'file_url' }, + { name: 'resource_url' }, + { name: 'resource', type: 'object', properties: [ + { name: 'uid', label: 'Resource ID' }, + { name: 'url' } + ] } + ] + when 'submittal_package' + [ + { name: 'uid', label: 'Submittal package ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'name' }, + { name: 'spec_section', label: 'Specification section' }, + { name: 'spec_section_name', label: 'Specification section name' }, + { name: 'custom_id' }, + { name: 'version' }, + { name: 'ball_in_court_status' }, + { name: 'submittal_due_date', type: 'date', control_type: 'date' }, + { name: 'required_on_job_date', type: 'date', control_type: 'date' }, + { name: 'transmission_status' }, + { name: 'is_voided', type: 'boolean' }, + { name: 'items', type: 'object', properties: [ + { name: 'uids', label: 'Item IDs', type: 'array', of: 'object', properties: [{ name: "value" }] }, { name: 'url' }, - { name: 'email' } - ] - }, - { name: 'deleted', type: 'boolean' } - ] - when 'field_report' - [ - { name: 'uid', label: 'Field Report ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'title' }, - { name: 'description' }, - { name: 'report_date', label: 'Report Date', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'status' }, - { - name: 'field_report_type', label: 'Field Report Type', type: 'object', properties: [ - { name: 'name' }, - { name: 'status' }, - { name: 'uid', label: 'Field Report ID' }, - { name: 'project_uid' }, - { name: 'template_type' } - ] - }, - { name: 'pdf_url', label: 'PDF URL' }, - { - name: 'pdf_form_values', label: 'PDF Form Values', type: 'array', of: 'object', - properties: [ - { name: 'name' }, - { name: 'value' } - ] - }, - { - name: 'pdf_form_fields', label: 'PDF Field Values', type: 'object' - }, - { - name: 'pg_form_values', type: 'object', properties: [ - { - name: 'pg_worklog_entries', label: 'Work Log Entries', type: 'array', of: 'object', - properties: [ - { name: 'trade' }, - { name: 'timespan' }, - { name: 'headcount', type: 'integer' }, - { name: 'description' }, - { - name: 'deleted', type: 'boolean', - control_type: 'checkbox' - }, - { name: 'uid' } - ] - }, - { - name: 'pg_materials_entries', label: 'Material Entries', type: 'array', of: 'object', - properties: [ - { name: 'unit', type: 'integer' }, - { name: 'quantity', type: 'integer' }, - { name: 'item' }, - { name: 'description' }, - { name: 'deleted', type: "boolean", control_type: 'checkbox' }, - { name: 'uid' } - ] - }, - { - name: 'pg_equipment_entries', label: 'Equipment Entries', type: 'array', of: 'object', - properties: [ - { name: 'timespan' }, - { name: 'quantity', type: 'integer' }, - { name: 'item' }, - { name: 'description' }, - { - name: 'deleted', type: 'boolean', - control_type: 'checkbox' - }, - { name: 'uid' } - ] - } - ] - }, - { - name: 'custom_items', label: 'Custom Form Items', type: 'array', - of: 'object', properties: [ - { name: 'section_label', label: 'Section Name' }, - { name: 'item_label', label: 'Item Label' }, - { name: 'value_name', label: 'Value Name' }, - { name: 'notes' }, - { name: 'text_val', label: 'Text Value' }, - { name: 'choice_val', label: 'Choice Value' }, - { name: 'number_val', label: 'Number Value', type: 'number' }, - { name: 'date_val', label: 'Date Value', type: 'date_time' }, - { name: 'array_val', label: 'Array Value', type: 'array', - of: 'string' }, - { name: 'toggle_val', label: 'Toggle Value', type: 'integer' } - ] - }, - { - name: 'attachments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + { name: 'total_count', type: 'integer', control_type: 'integer' } + ] }, + { name: 'visible_file_group_uid', label: 'Visible file group ID' }, + { name: 'design_review_due_date', type: 'date', control_type: 'date', label: 'Reviewer due date' }, + { name: 'general_contractor_review_due_date', type: 'date_time', label: 'Manager due date' }, + { name: 'latest_review', type: 'object', properties: [ + { name: 'uid', label: 'Review ID' }, + { name: 'created_at', type: 'date_time', control_type: 'date_time' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'Creator ID' }, + { name: 'url' } + ] }, + { name: 'file_group_uid', label: 'File group ID' }, + { name: 'is_official_review', type: 'boolean' }, + { name: 'package_version', type: 'integer', control_type: 'integer' }, + { name: 'review_response_uid' }, + { name: 'reviewed_by', type: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Reviewer ID' }, + { name: 'url' } + ] } + ] }, + { name: 'latest_review_response_uid', label: 'Latest review response ID' }, + { name: 'received_from_design_at', type: 'date_time', control_type: 'date_time' }, + { name: 'sent_to_design_at', type: 'date_time', control_type: 'date_time' }, + { name: 'received_from_sub_at', type: 'date_time', control_type: 'date_time' }, + { name: 'returned_to_sub_at', type: 'date_time', control_type: 'date_time' }, + { name: 'managers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Manager ID' }, { name: 'url' } - ] - }, - { - name: 'photos', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + ] }, + { name: 'reviewers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Reviewer ID' }, { name: 'url' } - ] - }, - { - name: 'snapshots', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + ] }, + { name: 'submitters', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Submitter ID' }, { name: 'url' } - ] - }, - { - name: 'created_by', type: 'object', properties: [ - { name: 'email' }, - { name: 'uid', label: 'UID' }, + ] }, + { name: 'unioned_watchers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Unioned watcher ID' }, { name: 'url' } - ] - }, - { name: 'updated_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { - name: 'weather', type: 'object', properties: [ - { name: 'humidity', type: 'number' }, - { name: 'precipitation_accumulation', type: 'number' }, - { name: 'precipitation_accumulation_unit' }, - { name: 'speed_unit' }, - { name: 'summary_key' }, - { name: 'temperature_max', type: 'integer' }, - { name: 'temperature_min' }, - { name: 'temperature_unit' }, - { name: 'wind_bearing', type: 'integer' }, - { name: 'wind_gust', type: 'number' }, - { name: 'wind_speed', type: 'number' } - ] - } - ] - when 'field_report_template' - [ - { name: 'uid', label: 'Field Report Template ID' }, - { name: 'project_uid', label: 'Project ID' }, - { name: 'name' }, - { name: 'field_reports', label: 'Field Reports', - type: 'object', properties: [ + ] }, + { name: 'watchers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Watcher ID' }, { name: 'url' } - ] - }, - { name: 'cadence' }, - { name: 'is_pdf', label: 'Is PDF', type: 'boolean' }, - { name: 'pdf_url', label: 'PDF URL' }, - { name: 'template_type', label: 'Template Type' }, - { name: 'status' }, - { name: 'group_permissions', label: 'Group Permissions', - type: 'array', of: 'object', properties: [ - { name: 'permissions', type: 'array', of: 'string' }, - { name: 'role_name', label: 'Role Name' }, - { name: 'role_uid', label: 'Role UID' } - ] - }, - { name: 'user_permissions', label: 'User Permissions', - type: 'array', of: 'object', properties: [ - { name: 'permissions', type: 'array', of:' string' }, - { name: 'user_id', label: 'User UID'} - ] - }, - { name: 'created_by', label: 'Created By', type: 'object', - properties: [ - { name: 'email' }, - { name: 'uid' }, + ] }, + { name: 'created_at', type: 'date_time', control_type: 'date_time' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'Creator ID' }, { name: 'url' } - ] - }, - { name: 'updated_at', label: 'Updated At', type: 'date_time' } - ] - when 'field_reports/export' - [ - { name: 'uid', label: 'Export ID' }, - { name: 'project_uid', label: 'Project ID' }, - { name: 'status' }, - { name: 'file_url' }, - { name: 'resource_url' } - ] - when 'rfi' - [ - { name: 'uid', label: 'RFI ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'number', type: 'integer' }, - { - name: 'status', type: 'object', properties: [ - { name: 'uid', label: 'Status ID' }, - { name: 'label' }, - { name: 'color' } - ] - }, - { - name: 'locked', type: 'boolean', - control_type: 'checkbox' - }, - { name: 'title' }, - { name: 'question' }, - { name: 'answer' }, - { name: 'sent_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - hint: 'Date when the RFI was sent. See ' \ - "Timestamps and " \ - 'Timezones for accepted date formats' }, - { name: 'due_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { - name: 'assigned_to', type: 'array', of: 'object', - properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] - }, - { name: 'updated_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - hint: 'Date when the RFI was sent. See ' \ - "Timestamps and " \ - 'Timezones for accepted date formats' }, - { - name: 'updated_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] - }, - { name: 'created_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { - name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] - }, - { - name: 'photos', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + ] }, + { name: 'published_at', type: 'date_time', control_type: 'date_time' }, + { name: 'updated_at', type: 'date_time', control_type: 'date_time' }, + { name: 'updated_by', type: 'object', properties: [ + { name: 'uid', label: 'Updater ID' }, { name: 'url' } - ] - }, - { - name: 'attachments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + ] }, + { name: 'lead_time_days', type: 'integer', control_type: 'integer' }, + { name: 'project', type: 'object', properties: [ + { name: 'uid', label: 'Project ID' }, { name: 'url' } - ] - }, - { - name: 'snapshots', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + ] } + ] + when 'submittal_item' + [ + { name: 'uid', label: 'Submittal item ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'name' }, + { name: 'description' }, + { name: 'spec_bullet', label: 'Specification bullet' }, + { name: 'spec_doc', label: 'Specification document' }, + { name: 'spec_heading', label: 'Specification heading' }, + { name: 'spec_page', label: 'Specification page' }, + { name: 'spec_section', label: 'Specification section' }, + { name: 'spec_section_name', label: 'Specification section name' }, + { name: 'spec_subsection_name', label: 'Specification subsection name' }, + { name: 'lead_time_days', type: 'integer' }, + { name: 'required_on_job_date', type: 'date_time', control_type: 'date_time' }, + { name: 'submittal_due_date', type: 'date_time', control_type: 'date_time' }, + { name: 'submittal_type' }, + { name: 'package', type: 'object', properties: [ + { name: 'uid', label: 'Package ID' }, { name: 'url' } - ] - }, - { - name: 'comments', type: 'object', properties: [ - { name: 'total_count', type: 'integer' }, + ] }, + { name: 'design_review_due_date', type: 'date_time', label: 'Reviewer due date' }, + { name: 'general_contractor_review_due_date', type: 'date_time', label: 'Manager due date' }, + { name: 'reviewers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: "Reviewer ID" }, { name: 'url' } - ] - } - ] - when 'rfi_status' - [ - { name: 'uid', label: 'RFI status ID' }, - { name: 'label' }, - { name: 'color' }, - { name: "project_uid", label: "Project ID" } - ] - when 'user', 'user_invite' - [ - { name: 'uid', label: 'User ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'email' }, - { name: 'first_name', label: 'First Name' }, - { name: 'last_name', label: 'Last Name' }, - { name: 'language' }, - { - name: 'role', type: 'object', properties: [ - { name: 'uid', label: 'role ID' }, + ] }, + { name: 'managers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Manager ID' }, { name: 'url' } - ] - }, - { name: 'removed', label: 'Removed?', type: 'boolean' } - ] - when 'sheet' - [ - { name: 'uid', label: 'Sheet ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'name' }, - { name: 'version_name', label: 'Version Name' }, - { name: 'description' }, - { name: 'tags', type: 'array', of: 'string', hint: 'An array of strings representing the' \ - ' tags added to this sheet.' }, - { - name: 'published_by', type: 'object', properties: [ - { name: 'uid', label: 'UID' }, - { name: 'url' }, - { name: 'email' } - ] - }, - { name: 'published_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - hint: 'UTC date and time in ISO-8601 format.' }, - { - name: 'deleted', type: 'boolean', - control_type: 'checkbox' - }, - { name: 'uploaded_file_name', label: 'Uploaded file name' }, - { name: 'history_set_uid', label: 'History set ID' } - ] - when 'sheet_packet' - [ - { name: 'uid', label: 'Sheet Packet ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'status' }, - { name: 'file_url', label: 'File URL' }, - { - name: 'resource', type: 'object', properties: [ - { name: 'uid', label: 'Resource ID' }, + ] }, + { name: 'submitters', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Submitter ID' }, { name: 'url' } - ] - } - ] - when 'issue_list' - [ - { name: "uid", label: "Task List ID" }, - { name: "project_uid", label: "Project ID" }, - { name: "name", label: "Name" }, - { name: "deleted", label: "Deleted", type: "boolean", control_type: 'checkbox' } - ] - when 'role' - [ - { name: 'uid', label: 'Role ID' }, - { name: 'label', label: 'Role' }, - { name: "project_uid", label: "Project ID" } - ] - when 'sheet_upload' - [ - { name: 'uid', label: 'Sheet Version Upload ID' }, - { name: 'complete_url', label: 'Upload Completion URL' }, - { name: 'status' }, - { name: "project_uid", label: "Project ID" }, - { - name: 'file_upload_requests', label: 'File Upload Requests', - type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'File Upload ID' }, - { name: 'upload_status', label: 'File Upload Status' }, - { name: 'url', label: 'File Upload URL' } - ] - } - ] - when 'version_upload' - [ - { name: 'uid', label: 'Sheet Version ID' }, - { name: "project_uid", label: "Project ID" }, - { name: 'status', label: 'Status' } - ] - when 'submittals/package' - [ - { name: 'uid', label: 'Submittal Package ID' }, - { name: 'project_uid', label: 'Project ID' }, - { name: 'name' }, - { name: 'spec_section' }, - { name: 'spec_section_name' }, - { name: 'custom_id' }, - { name: 'version' }, - { name: 'ball_in_court_status' }, - { name: 'submittals_due_date', type: 'date_time' }, - { name: 'required_on_job_date', type: 'date_time' }, - { name: 'transmission_status' }, - { name: 'is_voided', type: 'boolean' }, - { name: 'items', type: 'object', properties: [ - { name: 'uids', type: 'array', of: 'string' }, - { name: 'url' }, - { name: 'total_count', type: 'integer'} - ]}, - { name: 'visible_file_group_uid' }, - { name: 'design_review_due_date', type: 'date_time', label: 'Reviewer due date' }, - { name: 'general_contractor_review_due_date', type: 'date_time', label: 'Manager due date' }, - { name: 'latest_review', type: 'object', properties: [ - { name: 'uid', label: 'Review ID' }, - { name: 'created_at', type: 'date_time' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, - { name: 'url' } - ]}, - { name: 'file_group_uid' }, - { name: 'is_official_review' }, - { name: 'package_version' }, - { name: 'review_response_uid' }, - { name: 'reviewed_by', type: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, - { name: 'url' } - ]} - ]}, - { name: 'latest_review_response_uid' }, - { name: 'received_from_design_at', type: 'date_time', label: 'Received from reviewer at' }, - { name: 'sent_to_design_at', type: 'date_time', label: 'Sent to reviewer at' }, - { name: 'received_from_sub_at', type: 'date_time' }, - { name: 'returned_to_sub_at', type: 'date_time' }, - { name: 'managers', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, - { name: 'url' } - ]}, - { name: 'reviewers', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, - { name: 'url' } - ]}, - { name: 'submitters', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, - { name: 'url' } - ]}, - { name: 'unioned_watchers', type: 'array', of: 'object', properties: [ + ] }, + { name: 'watchers', type: 'array', of: 'object', properties: [ { name: 'type' }, - { name: 'uid' }, + { name: 'uid', label: 'Watcher ID' }, { name: 'url' } - ]}, - { name: 'watchers', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, + ] }, + { name: 'created_at' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'Creator ID' }, { name: 'url' } - ]}, - { name: 'created_at', type: 'date_time' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, - { name: 'url' } - ]}, - { name: 'published_at', type: 'date_time' }, - { name: 'updated_at', type: 'date_time' }, - { name: 'updated_by', type: 'object', properties: [ - { name: 'uid' }, - { name: 'url' } - ]} - ] - when 'submittals/item' - [ - { name: 'uid', label: 'Submittal Item ID' }, - { name: 'project_uid', label: 'Project ID' }, - { name: 'name' }, - { name: 'description' }, - { name: 'spec_bullet' }, - { name: 'spec_doc' }, - { name: 'spec_heading' }, - { name: 'spec_page' }, - { name: 'spec_section' }, - { name: 'spec_section_name' }, - { name: 'spec_subsection_name' }, - { name: 'lead_time_days', type:'integer' }, - { name: 'required_on_job_date', type: 'date_time' }, - { name: 'submittal_due_date', type: 'date_time' }, - { name: 'submittals_type' }, - { name: 'package', type: 'object', properties: [ - { name: 'uid' }, - { name: 'url' } - ]}, - { name: 'design_review_due_date', type: 'date_time', label: 'Reviewer due date' }, - { name: 'general_contractor_review_due_date', type: 'date_time', label: 'Manager due date' }, - { name: 'reviewers', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, + ] }, + { name: 'design_reviewer', type: 'object', properties: [ + { name: 'uid', label: 'Design reviewer ID' }, { name: 'url' } - ]}, - { name: 'managers', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, + ] }, + { name: 'general_contractor_manager', type: 'object', properties: [ + { name: 'uid', label: 'General contractor manager ID' }, { name: 'url' } - ]}, - { name: 'submitters', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, + ] }, + { name: 'project', type: 'object', properties: [ + { name: 'uid', label: 'Project ID' }, { name: 'url' } - ]}, - { name: 'watchers', type: 'array', of: 'object', properties: [ - { name: 'type' }, - { name: 'uid' }, + ] }, + { name: 'subcontractor', type: 'object', properties: [ + { name: 'uid', label: 'Subcontractor ID' }, { name: 'url' } - ]}, - { name: 'created_at' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid' }, - { name: 'url' } - ]} - ] - when 'submittals_file_group' - [ - { name: 'package_uid', label: 'Submittal Package ID' }, - { name: 'project_uid', label: 'Project ID' }, - { name: 'data', label: 'File Groups', - type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'File Group ID' }, - { name: 'files', type: 'array', of: 'object', properties: [ - { name: 'document_uid', label: 'Document ID' }, - { name: 'name' }, - { name: 'url' }, - { name: 'created_at', type: 'date_time' }, - { name: 'file_group_uid' } - ]}, - { name: 'package', type: 'object', properties: [ - { name: 'uid' }, - { name: 'url' } - ]}, - { name: 'upload_completed', type: 'boolean'} - ] - }, - { name: 'total_count' }, - { name: 'next_page_url' } - ] - when 'submittals_review_status' - [ - { name: 'package_uid', label: 'Submittal Package ID' }, - { name: 'project_uid', label: 'Project ID' }, - { name: 'data', label: 'Review Status', - type: 'array', of: 'object', properties: [ - { name: 'uid', label: 'Review ID' }, - { name: 'review_response_uid', label: 'Review Response ID' }, - { name: 'is_official_review', type: 'boolean' }, - { name: 'package_version', type: 'integer' }, - { name: 'file_group_uid', label: 'File Group ID' }, - { name: 'created_at' }, - { name: 'created_by', type: 'object', properties: [ - { name: 'uid', label: 'User ID' }, - { name: 'url' } - ]} - ] - }, - { name: 'total_count' }, - { name: 'next_page_url' } - ] + ] } + ] + when 'submittal_file_group' + [ + { name: 'package_uid', label: 'Submittal package ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'data', label: 'File Groups', + type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'File group ID' }, + { name: 'files', type: 'array', of: 'object', properties: [ + { name: 'document_uid', label: 'Document ID' }, + { name: 'name' }, + { name: 'url' }, + { name: 'created_at', type: 'date_time', control_type: 'date_time' }, + { name: 'file_group_uid', label: 'File group ID' } + ] }, + { name: 'package', type: 'object', properties: [ + { name: 'uid', label: 'Package ID' }, + { name: 'url' } + ] }, + { name: 'upload_completed', type: 'boolean' }, + { name: 'source' } + ] }, + { name: 'total_count', type: 'integer', control_type: 'integer' }, + { name: 'next_page_url' } + ] + when 'submittal_history' + [ + { name: 'package_uid', label: 'Submittal package ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'data', label: 'History', + type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'History ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'package_uid', label: 'Submittal package ID' }, + { name: 'event_type' }, + { name: 'created_at', type: 'date_time', control_type: 'date_time' }, + { name: 'creator_name' }, + { name: 'creator_uid', label: 'Creator ID' }, + { name: 'event_data', type: 'object', properties: [ + { name: 'file_group_uid', label: 'File group ID' }, + { name: 'files', type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'File ID' }, + { name: 'name' }, + { name: 'url' } + ] }, + { name: 'design_reviewer_name' }, + { name: 'design_reviewer_uid', label: 'Design reviewer ID' }, + { name: 'notes' }, + { name: 'package_uid', label: 'Package ID' }, + { name: 'reviewers', type: 'array', of: 'object', properties: [ + { name: 'type' }, + { name: 'uid', label: 'Reviewer ID' }, + { name: 'url' } + ] }, + { name: 'updated_at', type: 'date_time', control_type: 'date_time' }, + { name: 'updater_name' }, + { name: 'updater_uid', label: 'Updater ID' }, + { name: 'updated_by' }, + { name: 'is_voided_flag', type: 'boolean' }, + { name: 'ball_in_court_status' }, + { name: 'transmission_status' }, + { name: 'submitter_name' }, + { name: 'new_values', type: 'object', properties: [ + { name: 'name' }, + { name: 'custom_id' }, + { name: 'ball_in_court_status' }, + { name: 'transmission_status' }, + { name: 'spec_section' }, + { name: 'spec_section_name' }, + { name: 'notes' }, + { name: 'file_group_uid', label: 'File group ID' }, + { name: 'design_review_due_date', type: 'date', control_type: 'date' }, + { name: 'general_contractor_review_due_date', type: 'date', control_type: 'date' }, + { name: 'submittal_due_date', type: 'date', control_type: 'date' }, + { name: 'required_on_job_date', type: 'date', control_type: 'date' } + ] }, + { name: 'old_values', type: 'object', properties: [ + { name: 'name' }, + { name: 'custom_id' }, + { name: 'ball_in_court_status' }, + { name: 'transmission_status' }, + { name: 'spec_section' }, + { name: 'spec_section_name' }, + { name: 'notes' }, + { name: 'file_group_uid', label: 'File group ID' }, + { name: 'design_review_due_date', type: 'date', control_type: 'date' }, + { name: 'general_contractor_review_due_date', type: 'date', control_type: 'date' }, + { name: 'submittal_due_date', type: 'date', control_type: 'date' }, + { name: 'required_on_job_date', type: 'date', control_type: 'date' } + ] } + ] } + ] }, + { name: 'total_count', type: 'integer', control_type: 'integer' }, + { name: 'next_page_url' } + ] + when 'submittal_review_status' + [ + { name: 'package_uid', label: 'Submittal package ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'data', label: 'Review status', + type: 'array', of: 'object', properties: [ + { name: 'uid', label: 'Review ID' }, + { name: 'review_response_uid', label: 'Review response ID' }, + { name: 'is_official_review', type: 'boolean' }, + { name: 'package_version', type: 'integer', control_type: 'integer' }, + { name: 'file_group_uid', label: 'File group ID' }, + { name: 'created_at' }, + { name: 'created_by', type: 'object', properties: [ + { name: 'uid', label: 'User ID' }, + { name: 'url' } + ] }, + { name: 'reviewed_by', type: 'object', properties: [ + { name: 'uid', label: 'Reviewer ID' }, + { name: 'url' }, + { name: 'type' } + ] } + ] }, + { name: 'total_count', type: 'integer', control_type: 'integer' }, + { name: 'next_page_url' } + ] + end end - end - }, + }, - create_input_schema: { - fields: lambda do |_connection, config_fields| - case config_fields['object'] - when 'project' - [ - { name: 'name', label: 'Project Name', sticky: true, optional: false }, - { name: 'custom_id', label: 'Project Code', sticky: true }, - { - name: 'type', control_type: 'select', - label: 'Project Type', sticky: true, - pick_list: 'project_types', - toggle_hint: 'Select project type', - toggle_field: { - name: 'type', - label: 'Project type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Project type with possible values of general,' \ - ' manufacturing, power, water-sewer-waste, industrial-' \ - 'petroleum, transportation, hazardous-waste, telecom, ' \ - 'education-k-12, education-higher, gov-federal, ' \ - 'gov-state-local, or other' - } - }, - { name: 'status', label: 'Project Status', sticky: true }, - { name: 'owner', sticky: true, label: 'Project Owner' }, - { name: 'start_date', type: 'date', - sticky: true, - render_input: 'date_conversion', - parse_output: 'date_conversion', - label: 'Project Start Date', - hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, - { name: 'end_date', type: 'date', - sticky: true, - render_input: 'date_conversion', - parse_output: 'date_conversion', - label: 'Project End Date', - hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, - { name: 'street_1', sticky: true, - label: 'Street Line 1' }, - { name: 'street_2', sticky: true, label: 'Street line 2' }, - { name: 'city', sticky: true, label: 'Town or City' }, - { name: 'region', sticky: true, label: 'State, Province, or Region' }, - { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, - { name: 'country', - sticky: true, - hint: 'Project address country in 2-letter ISO 3166 code.' }, - { - name: 'add_to_organization', type: 'boolean', sticky: true, - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'add_to_organization', - label: 'Add to Organization', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } - } - ] - when 'rfi' - [ - { - name: 'locked', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'locked', - label: 'Locked', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' + create_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'project' + [ + { name: 'name', label: 'Project Name', sticky: true, optional: false }, + { name: 'custom_id', label: 'Project Code', sticky: true }, + { + name: 'type', control_type: 'select', + label: 'Project Type', sticky: true, + pick_list: 'project_types', + toggle_hint: 'Select project type', + toggle_field: { + name: 'type', + label: 'Project type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Project type with possible values of general,' \ + ' manufacturing, power, water-sewer-waste, industrial-' \ + 'petroleum, transportation, hazardous-waste, telecom, ' \ + 'education-k-12, education-higher, gov-federal, ' \ + 'gov-state-local, or other' + } + }, + { name: 'status', label: 'Project Status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project Owner' }, + { name: 'start_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project Start Date', + hint: 'Project start date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'end_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project End Date', + hint: 'Project end date. ISO-8601 date format (YYYY-MM-DD).' }, + { name: 'street_1', sticky: true, + label: 'Street Line 1' }, + { name: 'street_2', sticky: true, label: 'Street line 2' }, + { name: 'city', sticky: true, label: 'Town or City' }, + { name: 'region', sticky: true, label: 'State, Province, or Region' }, + { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, + { name: 'country', + sticky: true, + hint: 'Project address country in 2-letter ISO 3166 code.' }, + { + name: 'add_to_organization', type: 'boolean', sticky: true, + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'add_to_organization', + label: 'Add to Organization', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } - }, - { name: 'title', optional: false }, - { name: 'question' }, - { name: 'answer' }, - { name: 'sent_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - hint: 'Date when the RFI was sent. See ' \ - "Timestamps and " \ - 'Timezones for accepted date formats' }, - { name: 'due_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, - { name: 'status', label: 'Status', - hint: "Uid's of the RFI's initial status. Defaults to the first RFI status in the project" } - ] - when 'issue' - [ - { name: 'title' }, - { - name: 'status', control_type: 'select', pick_list: - %w[open in_review pending closed].select { |op| [op.labelize, op] }, - toggle_hint: 'Select status', - toggle_field: { - name: 'status', - label: 'Status', + ] + when 'rfi' + [ + { + name: 'locked', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'locked', + label: 'Locked', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'title', optional: false }, + { name: 'question' }, + { name: 'answer' }, + { name: 'sent_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { name: 'due_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, + { name: 'status', label: 'Status', + hint: "Uid's of the RFI's initial status. Defaults to the first RFI status in the project" } + ] + when 'issue' + [ + { name: 'title' }, + { + name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending", "closed".' + } + }, + { + name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work", "other".' + } + }, + { name: 'room', label: 'Location' }, + { name: 'start_date', label: 'Start Date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'description' }, + { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, + { + name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_cost_impact', + label: 'Has cost impact?', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, + { + name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_schedule_impact', + label: 'Has schedule impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, + { name: 'issue_list_uid', label: 'Task List ID', sticky: true } + ] + when 'sheet_packet' + [ + { name: 'sheet_uids', label: 'Sheet IDs', optional: false, type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are : "open", "in_review", "pending", "closed".' + hint: 'A comma separated list of sheet IDs.' }, + { + name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'include_annotations', + label: 'Include annotations?', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + ] + when 'issue_list' + [ + { name: 'name', optional: false } + ] + when 'sheet_upload' + [ + { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, + { name: 'version_name', label: 'Version Name', optional: false } + ] + when 'user_invite' + [ + { name: 'email', optional: false }, + { name: 'role_uid', label: 'Role ID', sticky: true, + hint: 'Unique identifier of role to assign user on project team' }, + { name: 'first_name' }, + { name: 'last_name' }, + { name: 'language' } + ] + when 'submittal_package' + [ + { name: 'name', optional: false, hint: 'The name of the submittal package.' }, + { name: 'custom_id', label: 'Custom ID', optional: false, hint: 'A custom ID for the submittal package.' }, + { name: 'item_uids', optional: false, label: 'Submittal item IDs', + hint: 'The IDs of the specific submittal items to include in the submittal package. Separate each item with a comma.' }, + { name: 'spec_section', label: 'Specification section', hint: 'Reference to specification section of submittal package.' }, + { name: 'spec_section_name', label: 'Specification section name', hint: 'Reference to specification section name of submittal package.' }, + { name: 'transmission_status', type: 'string', control_type: 'select', label: 'Transmission status', optional: true, + pick_list: 'transmission_status_type', toggle_hint: 'Select status type', + toggle_field: { + name: 'transmission_status', + label: 'Transmission status', + optional: true, + type: 'string', + control_type: 'text', + toggle_hint: 'Enter status value', + hint: 'Status of submittal package. Possible values are: Awaiting Submission, Requested, Revise & Resubmit, Awaiting GC Review, In GC Review, ' \ + 'Awaiting Design Review, In Design Review, Approved, Published.' + } }, + { name: 'notes' }, + { name: 'file_group_uid', label: 'File group ID', hint: 'UID of the file group to associate with this submittal package.' }, + { name: 'ball_in_court_status', type: 'string', control_type: 'select', label: 'Role type', + pick_list: 'role_type', toggle_hint: 'Select role type', + toggle_field: { + name: 'ball_in_court_status', + label: 'Role type', + type: 'string', + control_type: 'text', + optional: true, + toggle_hint: 'Enter role type', + hint: "Reference to the role of the user from whom the next step is expected. Possible values are: manager, submitter, reviewer." + } }, + { name: 'design_review_due_date', type: 'date', control_type: 'date', label: 'Reviewer due date', + hint: "The date when the review from reviewer's is due." }, + { name: 'general_contractor_review_due_date', type: 'date', control_type: 'date', label: 'Manager due date', + hint: "The date when the review from manager's is due." }, + { name: 'required_on_job_date', type: 'date', control_type: 'date', hint: 'The date when the submitted material is required on the job.' }, + { name: 'submittal_due_date', type: 'date', control_type: 'date', hint: 'Due date for this submittal package.' }, + { name: 'managers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of manager.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Manager ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'reviewers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of reviewer.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Reviewer ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'submitters', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of submitter.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Submitter ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'watchers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of watcher.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Watcher ID', hint: 'ID of either the user or group.' } + ] } + ] + when 'submittal_item' + [ + { name: 'name', optional: false, hint: 'Name of the submittal item.' }, + { name: 'description', hint: 'Description of the submittal item.' }, + { name: 'spec_bullet', label: 'Specification bullet', hint: 'Reference to specification bullet of submittal item.' }, + { name: 'spec_doc', label: 'Specification document', hint: 'Reference to specification document of submittal item.' }, + { name: 'spec_heading', label: 'Specification heading', hint: 'Reference to specification heading of submittal item.' }, + { name: 'spec_page', label: 'Specification page', hint: 'Reference to specification page of submittal item.' }, + { name: 'spec_section', label: 'Specification section', hint: 'Reference to specification section of submittal item.' }, + { name: 'spec_section_name', label: 'Specification section name', hint: 'Reference to specification section name of submittal item.' }, + { name: 'spec_subsection_name', label: 'Specification subsection name', hint: 'Reference to specification subsection of submittal item.' }, + { name: 'package_uid', hint: 'ID of the submittal package to which this item should be associated.' }, + { name: 'design_review_due_date', type: 'date', control_type: 'date', label: 'Reviewer due date', hint: "The date when the review from reviewer's is due." }, + { name: 'general_contractor_review_due_date', type: 'date', control_type: 'date', label: 'Manager due date', + hint: "The date when the review from manager's is due." }, + { name: 'submittal_due_date', type: 'date', control_type: 'date', hint: 'Date when the submittal is due.' }, + { name: 'required_on_job_date', type: 'date', control_type: 'date', hint: 'The date when the submitted material is required on the job.' }, + { name: 'managers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of manager.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Manager ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'reviewers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of reviewer.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Reviewer ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'submitters', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of submitter.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Submitter ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'watchers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of watcher.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Watcher ID', hint: 'ID of either the user or group.' } + ] } + ] + when 'field_report_export' + [ + { name: 'field_report_uids', label: 'Field Report IDs', optional: false, + hint: 'A comma separated list of field report IDs.' }, + { + name: 'timezone', + control_type: 'select', + pick_list: 'timezones', + optional: false, + toggle_hint: 'Select timezone', + toggle_field: { + name: 'timezone', + type: 'string', + label: 'Timezone', + control_type: 'text', + optional: false, + toggle_hint: 'Enter timezone', + hint: 'A valid timezone. See full list here.' + } + }, + { + name: 'file_type', + control_type: 'select', + pick_list: 'field_report_export_file_type', + sticky: true, + hint: 'Select the file type of the export', } - }, - { - name: 'type', control_type: 'select', - pick_list: [ - %w[issue issue], - %w[Planned\ work planned_work], - %w[other other] - ], - toggle_hint: 'Select type', - toggle_field: { - name: 'type', - label: 'Type', + ] + else + [] + end.concat( + if config_fields['object'] != 'project' + [ + { + name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + hint: 'If your project is not in top 50, use project ID toggle', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + } + ] + else + [] + end + ) + end + }, + + update_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'project' + [ + { name: 'name', label: 'Project Name', sticky: true }, + { name: 'custom_id', label: 'Project Code', sticky: true }, + { + name: 'type', control_type: 'select', + label: 'Project Type', sticky: true, + pick_list: 'project_types', + toggle_hint: 'Select project type', + toggle_field: { + name: 'type', + label: 'Project type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Project type with possible values of general,' \ + ' manufacturing, power, water-sewer-waste, industrial-' \ + 'petroleum, transportation, hazardous-waste, telecom, ' \ + 'education-k-12, education-higher, gov-federal, ' \ + 'gov-state-local, or other' + } + }, + { name: 'status', label: 'Project Status', sticky: true }, + { name: 'owner', sticky: true, label: 'Project Owner' }, + { name: 'start_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project Start Date', + hint: 'Project start date. ISO-8601 date format (DD-MM-YYYY).' }, + { name: 'end_date', type: 'date', + sticky: true, + render_input: 'date_conversion', + parse_output: 'date_conversion', + label: 'Project End Date', + hint: 'Project end date. ISO-8601 date format (DD-MM-YYYY).' }, + { name: 'street_1', sticky: true, + label: 'Street Line 1' }, + { name: 'street_2', sticky: true, label: 'Street line 2' }, + { name: 'city', sticky: true, label: 'Town or City' }, + { name: 'region', sticky: true, label: 'State, Province, or Region' }, + { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, + { name: 'country', + sticky: true, + hint: 'Project address country in 2-letter ISO 3166 code.' } + ] + when 'rfi' + [ + { + name: 'locked', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'locked', + label: 'Locked', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'title', optional: false }, + { name: 'question' }, + { name: 'answer' }, + { name: 'sent_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp', + hint: 'Date when the RFI was sent. See ' \ + "Timestamps and " \ + 'Timezones for accepted date formats' }, + { name: 'due_at', type: 'date_time', + render_input: 'render_iso8601_timestamp', + parse_output: 'parse_iso8601_timestamp' }, + { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, + { name: 'status', label: 'Status', + hint: "Uid's of the RFI's initial status. Defaults to the first RFI status in the project" } + ] + when 'issue' + [ + { name: 'title' }, + { + name: 'status', control_type: 'select', pick_list: + %w[open in_review pending closed].select { |op| [op.labelize, op] }, + toggle_hint: 'Select status', + toggle_field: { + name: 'status', + label: 'Status', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are : "open", "in_review", "pending", "closed".' + } + }, + { + name: 'type', control_type: 'select', + pick_list: [ + %w[issue issue], + %w[Planned\ work planned_work], + %w[other other] + ], + toggle_hint: 'Select type', + toggle_field: { + name: 'type', + label: 'Type', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: "issue", "planned_work", "other".' + } + }, + { name: 'room', label: 'Location' }, + { name: 'start_date', label: 'Start Date', + type: 'date_time', + render_input: 'date_conversion', + parse_output: 'date_conversion' }, + { name: 'due_at', type: 'date_time', + render_input: 'date_time_conversion', + parse_output: 'date_time_conversion' }, + { name: 'description' }, + { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, + { + name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_cost_impact', + label: 'Has cost impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer', + hint: "The task's schedule impact in seconds, if it has one." }, + { + name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'has_schedule_impact', + label: 'Has schedule impact', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, + { name: 'issue_list_uid', label: 'Task List ID', sticky: true } + ] + when 'sheet_packet' + [ + { name: 'sheet_uids', label: 'Sheet IDs', optional: false, type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: "issue", "planned_work", "other".' - } - }, - { name: 'room', label: 'Location' }, - { name: 'start_date', label: 'Start Date', - type: 'date_time', - render_input: 'date_conversion', - parse_output: 'date_conversion' }, - { name: 'due_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'description' }, - { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, - { - name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'has_cost_impact', - label: 'Has cost impact?', + hint: 'A comma separated list of sheet IDs.' }, + { + name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, + control_type: 'checkbox', toggle_hint: 'Select from options list', + toggle_field: { + name: 'include_annotations', + label: 'Include annotations?', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } + }, + ] + when 'issue_list' + [ + { name: 'name', optional: false } + ] + when 'sheet_upload' + [ + { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, + { name: 'version_name', label: 'Version Name', optional: false } + ] + when 'photo' + [ + { name: 'title', label: 'Photo title', + hint: 'New title of the photo', sticky: true } + ] + when 'submittal_package' + [ + { name: 'name', hint: 'The name of the submittal package.' }, + { name: 'custom_id', hint: 'A custom ID for the submittal package.' }, + { name: 'ball_in_court_status', type: 'string', control_type: 'select', label: 'Role type', + pick_list: 'role_type', toggle_hint: 'Select role type', + toggle_field: { + name: 'ball_in_court_status', + label: 'Role type', + type: 'string', + control_type: 'text', + optional: true, + toggle_hint: 'Enter role type', + hint: "Reference to the role of the user from whom the next step is expected. Possible values are: manager, submitter, reviewer." + } }, + { name: 'spec_section', label: 'Specification section', hint: 'Reference to specification section of submittal package.' }, + { name: 'spec_section_name', label: 'Specification section name', hint: 'Reference to specification section name of submittal package.' }, + { name: 'transmission_status', type: 'string', control_type: 'select', label: 'Transmission status', optional: true, + pick_list: 'transmission_status_type', toggle_hint: 'Select status type', + toggle_field: { + name: 'transmission_status', + label: 'Transmission status', + optional: true, + type: 'string', + control_type: 'text', + toggle_hint: 'Enter status value', + hint: 'Status of submittal package. Possible values are: Awaiting Submission, Requested, Revise & Resubmit, Awaiting GC Review, In GC Review, ' \ + 'Awaiting Design Review, In Design Review, Approved, Published.' + } }, + { name: 'notes' }, + { + name: 'is_official_review', + label: 'Offical review', type: 'string', control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } - }, - { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer' }, - { - name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'has_schedule_impact', - label: 'Has schedule impact', + toggle_hint: 'Enter value', + hint: 'Boolean indicating whether the submittal package is official or not. Allowed values are true, false.', + toggle_field: { + name: 'is_official_review', type: 'boolean', + control_type: 'checkbox', + label: 'Offical review', + optional: true, + hint: 'Boolean indicating whether the submittal package is official or not.', + toggle_hint: 'Select from list' + } + }, + { + name: 'is_voided', + label: 'Is voided', type: 'string', control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' + toggle_hint: 'Enter value', + hint: 'Boolean indicating whether the submittal package has been voided or not. Allowed values are true, false.', + toggle_field: { + name: 'is_voided', type: 'boolean', + control_type: 'checkbox', + label: 'Is voided', + optional: true, + hint: 'Boolean indicating whether the submittal package has been voided or not.', + toggle_hint: 'Select from list' + } + }, + { name: 'file_group_uid', label: 'File group ID', hint: 'UID of the file group to associate with this submittal package.' }, + { name: 'item_uids', label: 'Submittal item IDs', hint: 'The UIDs of the specific items to include in the submittal package. Separate each item with a comma.' }, + { name: 'review_response_uid', label: 'Review response ID', hint: 'UID of the review response.' }, + { name: 'version', type: 'integer', control_type: 'integer', hint: 'The version number for the current submittal package.' }, + { name: 'design_review_due_date', type: 'date', control_type: 'date', label: 'Reviewer due date', hint: "The date when the review from reviewer's is due." }, + { name: 'general_contractor_review_due_date', type: 'date', control_type: 'date', label: 'Manager review due date', + hint: "The date when the review from manager's is due." }, + { name: 'required_on_job_date', type: 'date', control_type: 'date', hint: 'The date when the submitted material is required on the job.' }, + { name: 'submittal_due_date', type: 'date', control_type: 'date', hint: 'Due date for this submittal package.' }, + { name: 'reviewed_by', type: 'object', hint: 'An objects describing users reviewed the submittal package.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Reviewer ID', hint: 'ID of either the user or group.' }, + { name: 'url', hint: 'Url of either user or group.' } + ] }, + { name: 'managers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of manager.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Manager ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'reviewers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of reviewer.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Reviewer ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'submitters', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of submitter.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Submitter ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'watchers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of watcher.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Watcher ID', hint: 'ID of either the user or group.' } + ] } + ] + when 'submittal_item' + [ + { name: 'name', hint: 'Name of the submittal item.' }, + { name: 'description', hint: 'Description of the submittal item.' }, + { name: 'spec_bullet', label: 'Specification bullet', hint: 'Reference to specification bullet of submittal item.' }, + { name: 'spec_doc', label: 'Specification document', hint: 'Reference to specification document of submittal item.' }, + { name: 'spec_heading', label: 'Specification heading', hint: 'Reference to specification heading of submittal item.' }, + { name: 'spec_page', label: 'Specification page', hint: 'Reference to specification page of submittal item.' }, + { name: 'spec_section', label: 'Specification section', hint: 'Reference to specification section of submittal item.' }, + { name: 'spec_section_name', label: 'Specification section name', hint: 'Reference to specification section name of submittal item.' }, + { name: 'spec_subsection_name', label: 'Specification subsection name', hint: 'Reference to specification subsection of submittal item.' }, + { name: 'package_uid', label: 'Package ID', hint: 'ID of the submittal package to which this item should be associated.' }, + { name: 'submittal_due_date', type: 'date', control_type: 'date', hint: 'Date when the submittal is due.' }, + { name: 'required_on_job_date', type: 'date', control_type: 'date', hint: 'The date when the submitted material is required on the job.' }, + { name: 'design_review_due_date', type: 'date', control_type: 'date', label: 'Reviewer due date', hint: 'The date when the review from reviewers is due.' }, + { name: 'general_contractor_review_due_date', type: 'date', control_type: 'date', label: 'Manager review due date', + hint: "The date when the review from manager's is due." }, + { name: 'managers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of manager.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Manager ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'reviewers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of reviewer.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Reviewer ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'submitters', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of submitter.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Submitter ID', hint: 'ID of either the user or group.' } + ] }, + { name: 'watchers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of watcher.', + properties: [ + { name: 'type', hint: 'Possible values are: user or group.' }, + { name: 'uid', label: 'Watcher ID', hint: 'ID of either the user or group.' } + ] } + ] + else + [] + end.concat( + [ + { + name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + hint: 'If your project is not in top 50, use project ID toggle.', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } } - }, - { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, - { name: 'issue_list_uid', label: 'Task List ID', sticky: true } - ] - when 'sheet_packet' - [ - { name: 'sheet_uids', label: 'Sheet IDs', optional: false, - type: 'string', - hint: 'A comma separated list of sheet IDs.' }, - { - name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'include_annotations', - label: 'Include annotations?', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' + ] + ).concat( + if config_fields['object'] != 'project' + [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false }] + else + [] + end + ) + end + }, + + upload_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'attachment' + [ + { name: 'content_type', + hint: "Content type of the document's file. Example for pdf application/pdf", + optional: false }, + { name: 'file_content', optional: false }, + { name: 'name', optional: false, + label: 'Document name', + hint: 'Name of the document.' }, + { + name: 'folder', label: 'Project folder', sticky: true, + control_type: 'select', + pick_list: 'project_folders', + pick_list_params: { project_uid: 'project_uid' }, + toggle_hint: 'Select folder', + hint: 'Folder shows in select options only if at least one file exist in the folder', + toggle_field: { + name: 'folder', + label: 'Project folder', + type: 'string', + control_type: 'text', + toggle_hint: 'Use custom value', + hint: 'Folder in project to place the document ' \ + '(case-sensitive). Leave blank to select root folder' + } + }, + { + name: 'auto_version', type: 'boolean', sticky: true, + control_type: 'checkbox', + toggle_hint: 'Select from options list', + toggle_field: { + name: 'auto_version', + type: 'boolean', + control_type: 'text', + label: 'Auto version', + toggle_hint: 'Use custom value', + hint: 'Allowed values are: true, false' + } } - }, - ] - when 'issue_list' - [ - { name: 'name', optional: false } - ] - when 'sheet_upload' - [ - { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, - { name: 'version_name', label: 'Version Name', optional: false } - ] - when 'user_invite' - [ - { name: 'email', optional: false }, - { name: 'role_uid', label: 'Role ID', sticky: true, - hint: 'Unique identifier of role to assign user on project team' }, - { name: 'first_name' }, - { name: 'last_name' }, - { name: 'language' } - ] - when 'submittals/package' - [ - { name: 'name', optional: false, - hint: 'The name of the submittal package.' }, - { name: 'custom_id', optional: false, - hint: 'A custom ID for the submittal package.' }, - { name: 'item_uids', optional: false, label: 'Submittal Item IDs', - hint: 'The IDs of the specific submittal items to include in the submittal package. ' \ - 'Separate each item with a comma.' }, - { name: 'ball_in_court_status', - hint: "Reference to the role of the user from whom the next step is expected." \ - " Can be 'manager', 'submitter', or 'reviewer'." }, - { name: 'design_review_due_date', type: 'date', label: 'Reviewer due date', - hint: 'The date when the review from reviewers\' is due.' }, - { name: 'file_group_uid', - hint: 'UID of the file group to associate with this submittal package.' }, - { name: 'general_contractor_review_due_date', type: 'date', label: 'Manager due date', - hint: 'The date when the review from manager\'s is due.' }, - { name: 'notes' }, - { name: 'required_on_job_date', type: 'date', - hint: 'The date when the submitted material is required on the job.' }, - { name: 'submittal_due_date', type: 'date', - hint: 'Due date for this submittal package.' }, - { name: 'managers', type: 'array', of: 'object', - hint: 'An array of objects describing users assigned the role of manager.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'reviewers', type: 'array', of: 'object', - hint: 'An array of objects describing users assigned the role of reviewer.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'watchers', type: 'array', of: 'object', - hint: 'An array of objects describing users assigned the role of watcher.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - } - ] - when 'submittals/item' - [ - { name: 'name', optional: false, - hint: 'Name of the submittal item.' }, - { name: 'description', - hint: 'Description of the submittal package.' }, - { name: 'package_uid', - hint: 'ID of the submittal package to which this item should be associated.' }, - { name: 'submittal_due_date', type: 'date', - hint: 'Date when the submittal is due.' }, - { name: 'required_on_job_date', type: 'date', - hint: 'The date when the submitted material is required on the job.' }, - { name: 'design_review_due_date', type: 'date', label: 'Reviewer due date', - hint: 'The date when the review from reviewers\' is due.' }, - { name: 'general_contractor_review_due_date', type: 'date', label: 'Manager due date', - hint: 'The date when the review from manager\'s is due.' }, - { name: 'managers', type: 'array', of: 'object', - hint: 'An array of objects describing users assigned the role of manager.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'reviewers', type: 'array', of: 'object', - hint: 'A list describing users assigned the role of reviewer.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'submitters', type: 'array', of: 'object', - hint: 'A list describing users assigned the role of submitter.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'watchers', type: 'array', of: 'object', - hint: 'A list describing users assigned the role of watcher.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - } - ] - when 'field_reports/export' - [ - { name: 'field_report_uids', label: 'Field Report IDs', optional: false, - hint: 'A comma separated list of field report IDs.' }, - { - name: 'file_type', - control_type: 'select', - pick_list: 'field_report_export_file_type', - sticky: true, - hint: 'Select the file type of the export', - }, - { - name: 'timezone', - control_type: 'select', - pick_list: 'timezones', - sticky: true, - toggle_hint: 'Select timezone', - toggle_field: { - name: 'timezone', - type: 'string', - label: 'Timezone', - control_type: 'text', + ] + when 'photo' + [ + { name: 'content_type', optional: false, + hint: "Content type of the photo's file" }, + { name: 'file_content', optional: false }, + { name: 'title', optional: false, label: 'Photo title' } + ] + when 'file_upload' + [ + { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false }, + { name: 'file_upload_request_uid', label: 'File Upload ID', optional: false }, + { name: 'file_name', label: 'File Name', optional: false }, + { name: 'file_content', label: 'File Content', optional: false } + ] + when 'version_upload' + [ + { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false } + ] + else + [] + end.concat( + [ + { + name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', optional: false, - toggle_hint: 'Enter timezone', - hint: 'A valid timezone. See fill list ' \ - 'here.' + hint: 'If your project is not in top 50, use project ID toggle.', + toggle_hint: 'Select project', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } } - } - ] - else - [] - end.concat( + ] + ) + end + }, + + download_input_schema: { + fields: lambda do |_connection, config_fields| + case config_fields['object'] + when 'field_report_export' + [{ name: 'uid', label: 'Export ID', optional: false }] + when 'sheet_packet' + [{ name: 'uid', label: "Sheet packet ID", optional: false, hint: 'Ensure the status of the sheet packet export is complete before downloading.' }] + else + [{ name: 'uid', label: "#{config_fields['object'].labelize} ID", optional: false }] + end.concat( + [ + { + name: 'chunk_size', + optional: true, + label: 'Chunk size', + default: "10MB", + hint: "File contents will be transferred in chunks of this size. Enter the size with the unit, Eg. 50KB. Valid units are 'B', 'KB', 'MB'. Default chunk size is " \ + "10MB. Minimum is 32KB and maximum is 10MB. Use this when you want to optimize throughput. Bigger chunk size will increase throughput, " \ + "but may exceed API limit." + } + ] + ) + end + }, + + trigger_input: { + fields: lambda do |_connection, config_fields| if config_fields['object'] != 'project' [ { - name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', + name: 'project_uid', optional: false, label: 'Project', - optional: false, - hint: 'If your project is not in top 50, use project ID toggle', + control_type: 'select', pick_list: 'project_list', + hint: 'If your project is not in top 50, use project ID toggle.', toggle_hint: 'Select project', toggle_field: { name: 'project_uid', + label: 'Project ID', type: 'string', control_type: 'text', - optional: false, - label: 'Project ID', toggle_hint: 'Enter project ID', hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } + }, + { + name: 'output_schema', + control_type: 'schema-designer', + ngIf: 'input.object == "field_report"', + extends_schema: true, + label: 'PDF field values', + hint: 'Manually define the values expected of your PDF field values in the field report.', + optional: true } ] else [] end - ) - end - }, + end + }, + + custom_action_input: { + fields: lambda do |_connection, config_fields| + input_schema = parse_json(config_fields.dig('input', 'schema') || '[]') - update_input_schema: { - fields: lambda do |_connection, config_fields| - case config_fields['object'] - when 'project' - [ - { name: 'name', label: 'Project Name', sticky: true }, - { name: 'custom_id', label: 'Project Code', sticky: true }, - { - name: 'type', control_type: 'select', - label: 'Project Type', sticky: true, - pick_list: 'project_types', - toggle_hint: 'Select project type', - toggle_field: { - name: 'type', - label: 'Project type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Project type with possible values of general,' \ - ' manufacturing, power, water-sewer-waste, industrial-' \ - 'petroleum, transportation, hazardous-waste, telecom, ' \ - 'education-k-12, education-higher, gov-federal, ' \ - 'gov-state-local, or other' - } - }, - { name: 'status', label: 'Project Status', sticky: true }, - { name: 'owner', sticky: true, label: 'Project Owner' }, - { name: 'start_date', type: 'date', - sticky: true, - render_input: 'date_conversion', - parse_output: 'date_conversion', - label: 'Project Start Date', - hint: 'Project start date. ISO-8601 date format (DD-MM-YYYY).' }, - { name: 'end_date', type: 'date', - sticky: true, - render_input: 'date_conversion', - parse_output: 'date_conversion', - label: 'Project End Date', - hint: 'Project end date. ISO-8601 date format (DD-MM-YYYY).' }, - { name: 'street_1', sticky: true, - label: 'Street Line 1' }, - { name: 'street_2', sticky: true, label: 'Street line 2' }, - { name: 'city', sticky: true, label: 'Town or City' }, - { name: 'region', sticky: true, label: 'State, Province, or Region' }, - { name: 'postal_code', sticky: true, label: 'Zip or Postal Code' }, - { name: 'country', - sticky: true, - hint: 'Project address country in 2-letter ISO 3166 code.' } - ] - when 'rfi' - [ - { - name: 'locked', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'locked', - label: 'Locked', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } - }, - { name: 'title', optional: false }, - { name: 'question' }, - { name: 'answer' }, - { name: 'sent_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp', - hint: 'Date when the RFI was sent. See ' \ - "Timestamps and " \ - 'Timezones for accepted date formats' }, - { name: 'due_at', type: 'date_time', - render_input: 'render_iso8601_timestamp', - parse_output: 'parse_iso8601_timestamp' }, - { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, - { name: 'status', label: 'Status', - hint: "Uid's of the RFI's initial status. Defaults to the first RFI status in the project" } - ] - when 'issue' - [ - { name: 'title' }, - { - name: 'status', control_type: 'select', pick_list: - %w[open in_review pending closed].select { |op| [op.labelize, op] }, - toggle_hint: 'Select status', - toggle_field: { - name: 'status', - label: 'Status', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are : "open", "in_review", "pending", "closed".' - } - }, - { - name: 'type', control_type: 'select', - pick_list: [ - %w[issue issue], - %w[Planned\ work planned_work], - %w[other other] - ], - toggle_hint: 'Select type', - toggle_field: { - name: 'type', - label: 'Type', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: "issue", "planned_work", "other".' - } - }, - { name: 'room', label: 'Location' }, - { name: 'start_date', label: 'Start Date', - type: 'date_time', - render_input: 'date_conversion', - parse_output: 'date_conversion' }, - { name: 'due_at', type: 'date_time', - render_input: 'date_time_conversion', - parse_output: 'date_time_conversion' }, - { name: 'description' }, - { name: 'cost_impact', label: 'Cost Impact', type: 'number' }, - { - name: 'has_cost_impact', label: 'Has Cost Impact?', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'has_cost_impact', - label: 'Has cost impact', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } - }, - { name: 'schedule_impact', label: 'Schedule Impact', type: 'integer', - hint: "The task's schedule impact in seconds, if it has one." }, - { - name: 'has_schedule_impact', label: 'Has Schedule Impact?', type: 'boolean', - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'has_schedule_impact', - label: 'Has schedule impact', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } - }, - { name: 'assigned_to_uids', hint: "A comma separated list of user IDs." }, - { name: 'issue_list_uid', label: 'Task List ID', sticky: true } - ] - when 'sheet_packet' [ - { name: 'sheet_uids', label: 'Sheet IDs', optional: false, - type: 'string', - hint: 'A comma separated list of sheet IDs.' }, { - name: 'include_annotations', label: 'Include annotations?', type: 'boolean', sticky: true, - control_type: 'checkbox', toggle_hint: 'Select from options list', - toggle_field: { - name: 'include_annotations', - label: 'Include annotations?', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } - }, - ] - when 'issue_list' - [ - { name: 'name', optional: false } - ] - when 'sheet_upload' - [ - { name: 'num_files', label: 'Number of PDFs', type: 'integer', optional: false }, - { name: 'version_name', label: 'Version Name', optional: false } - ] - when 'photo' - [ - { name: 'title', label: 'Photo title', - hint: 'New title of the photo', sticky: true } - ] - when 'submittals/package' - [ - { name: 'name', - hint: 'The name of the submittal package.' }, - { name: 'custom_id', - hint: 'A custom ID for the submittal package.' }, - { name: 'item_uids', label: 'Submittal Item IDs', type: 'array', - hint: 'The UIDs of the specific items to include in the submittal package.' }, - { name: 'ball_in_court_status', - hint: 'Reference to the role of the user from whom the next step is expected.' \ - ' Can be \'manager\', \'submitter\', or \'reviewer\'.' }, - { name: 'design_review_due_date', type: 'date', label: 'Reviewer due date', - hint: 'The date when the review from reviewers\' is due.' }, - { name: 'file_group_uid', - hint: 'UID of the file group to associate with this submittal package.' }, - { name: 'general_contractor_review_due_date', type: 'date', label: 'Manager review due date', - hint: 'The date when the review from manager\'s is due.' }, - { name: 'notes' }, - { name: 'required_on_job_date', type: 'date', - hint: 'The date when the submitted material is required on the job.' }, - { name: 'submittal_due_date', type: 'date', - hint: 'Due date for this submittal package.' }, - { name: 'managers', type: 'array', of: 'object', - hint: 'An array of objects describing users assigned the role of manager.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'reviewers', type: 'array', of: 'object', - hint: 'An array of objects describing users assigned the role of reviewer.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'watchers', type: 'array', of: 'object', - hint: 'An array of objects describing users assigned the role of watcher.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - } - ] - when 'submittals/item' - [ - { name: 'name', - hint: 'Name of the submittal item.' }, - { name: 'description', - hint: 'Description of the submittal package.' }, - { name: 'package_uid', label: 'Submittal Package ID', - hint: 'ID of the submittal package to which this item should be associated.' }, - { name: 'submittal_due_date', type: 'date', - hint: 'Date when the submittal is due.' }, - { name: 'required_on_job_date', type: 'date', - hint: 'The date when the submitted material is required on the job.' }, - { name: 'design_review_due_date', type: 'date', label: 'Reviewer due date', - hint: 'The date when the review from reviewers is due.' }, - { name: 'general_contractor_review_due_date', type: 'date', label: 'Manager review due date', - hint: 'The date when the review from manager\'s is due.' }, - { name: 'managers', type: 'array', of: 'object', - hint: 'An array of objects describing users assigned the role of manager.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'reviewers', type: 'array', of: 'object', - hint: 'A list describing users assigned the role of reviewer.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - }, - { name: 'submitters', type: 'array', of: 'object', - hint: 'A list describing users assigned the role of submitter.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] + name: 'path', + optional: false, + hint: 'Base URI is https://io.plangrid.com' \ + ' - path will be appended to this URI. ' \ + 'Use absolute URI to override this base URI.' }, - { name: 'watchers', type: 'array', of: 'object', - hint: 'A list describing users assigned the role of watcher.', - properties: [ - { name: 'type', hint: 'Can be `user` or `group`.' }, - { name: 'uid', hint: 'ID of either the user or group' } - ] - } - ] - else - [] - end.concat( - [ + ( + if %w[get delete].include?(config_fields['verb']) + { + name: 'input', + type: 'object', + control_type: 'form-schema-builder', + sticky: input_schema.blank?, + label: 'URL parameters', + add_field_label: 'Add URL parameter', + properties: [ + { + name: 'schema', + extends_schema: true, + sticky: input_schema.blank? + }, + ( + if input_schema.present? + { + name: 'data', + type: 'object', + properties: call('make_schema_builder_fields_sticky', + input_schema) + } + end + ) + ].compact + } + else + { + name: 'input', + type: 'object', + properties: [ + { + name: 'schema', + extends_schema: true, + schema_neutral: true, + control_type: 'schema-designer', + sample_data_type: 'json_input', + sticky: input_schema.blank?, + label: 'Request body parameters', + add_field_label: 'Add request body parameter' + }, + ( + if input_schema.present? + { + name: 'data', + type: 'object', + properties: call('make_schema_builder_fields_sticky', + input_schema) + } + end + ) + ].compact + } + end + ), { - name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - hint: 'If your project is not in top 50, use project ID toggle.', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Enter project ID', - hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } + name: 'output', + control_type: 'schema-designer', + sample_data_type: 'json_http', + extends_schema: true, + schema_neutral: true, + sticky: true } ] - ).concat( - case config_fields['object'] - when 'submittals/package' - [{ name: 'uid', label: 'Submittal Package ID', optional: false }] - when 'submittals/item' - [{ name: 'uid', label: 'Submittal Item ID', optional: false }] - else - [{ name: 'uid', label: "#{config_fields['object'].labelize} ID", optional: false }] - end - ) - end + end + }, + + custom_action_output: { + fields: lambda do |_connection, config_fields| + parse_json(config_fields['output'] || '[]') + end + } }, - upload_input_schema: { - fields: lambda do |_connection, config_fields| - case config_fields['object'] - when 'attachment' - [ - { name: 'content_type', - hint: 'Content type of the document\'s file. Example for pdf application/pdf', - optional: false }, - { name: 'file_content', optional: false }, - { name: 'name', optional: false, - label: 'Document name', - hint: 'Name of the document.' }, - { - name: 'folder', label: 'Folder', sticky: true, - control_type: 'select', - pick_list: 'project_folders', - pick_list_params: { project_uid: 'project_uid' }, - toggle_hint: 'Select folder', - hint: 'Folder shows in select options only if at least one file exist in the folder', - toggle_field: { - name: 'folder', - label: 'Project folder', - type: 'string', - control_type: 'text', - toggle_hint: 'Use custom value', - hint: 'Folder in project to place the document ' \ - '(case-sensitive). Leave blank to select root folder' - } - }, - { - name: 'auto_version', type: 'boolean', sticky: true, - control_type: 'checkbox', - toggle_hint: 'Select from options list', - toggle_field: { - name: 'auto_version', - type: 'boolean', - control_type: 'text', - label: 'Auto version', - toggle_hint: 'Use custom value', - hint: 'Allowed values are: true, false' - } - } - ] - when 'photo' - [ - { name: 'content_type', optional: false, - hint: "Content type of the photo's file" }, - { name: 'file_content', optional: false }, - { name: 'title', optional: false, label: 'Photo title' } - ] - when 'file_upload' - [ - { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false }, - { name: 'file_upload_request_uid', label: 'File Upload ID', optional: false }, - { name: 'file_name', label: 'File Name', optional: false }, - { name: 'file_content', label: 'File Content', optional: false } - ] - when 'version_upload' - [ - { name: 'ver_upload_uid', label: 'Sheet Version Upload ID', optional: false } - ] - else - [] - end.concat( + actions: { + custom_action: { + description: "Custom action in Plangrid", + help: { + body: 'Build your own Plangrid action for any Plangrid REST endpoint.', + learn_more_url: 'https://developer.plangrid.com/docs/', + learn_more_text: 'The Plangrid API documentation' + }, + + config_fields: [{ + name: 'verb', + label: 'Request type', + hint: 'Select HTTP method of the request', + optional: false, + control_type: 'select', + pick_list: %w[get post patch delete].map { |verb| [verb.upcase, verb] } + }], + + input_fields: lambda do |object_definitions| + object_definitions['custom_action_input'] + end, + + execute: lambda do |_connection, input| + error("#{input['verb']} not supported") if %w[get post patch delete].exclude?(input['verb']) + data = input.dig('input', 'data').presence || {} + case input['verb'] + when 'get' + response = get(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + if response.is_a?(Array) + array_name = parse_json(input['output'] || '[]'). + dig(0, 'name') || 'array' + { array_name.to_s => response } + elsif response.is_a?(Hash) + response + else + error('API response is not a JSON') + end + when 'post' + post(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + when 'patch' + patch(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + when 'delete' + delete(input['path'], data). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end.compact + end + end, + + output_fields: lambda do |object_definitions| + object_definitions['custom_action_output'] + end + }, + + create_object: { + title: 'Create object', + description: lambda do |_, objects| + "Create #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Create object in PlanGrid", + + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'create_object_list', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| + object_definitions['create_input_schema'] + end, + + execute: lambda do |_connection, input| + payload = + input.except('project_uid', 'object').each_with_object({}) do |(key, val), hash| + hash[key] = if %w[due_at sent_at].include?(key) + val.to_time.utc.iso8601 + elsif %w[sheet_uids assigned_to_uids item_uids field_report_uids].include?(key) + val.split(",") + else + val + end + end + case input['object'] + when 'project' + post('/projects').payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + when 'sheet_packet', 'sheet_upload', 'user_invite', 'submittal_item', 'submittal_package' + path = input['object'].split("_") + response = post("/projects/#{input['project_uid']}/#{path.first.pluralize}/#{path.last.pluralize}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + response.dig('items', 'uids')&.map do |uid| + { "value" => uid } + end.inject(:merge) + response + when 'field_report_export' + post("/projects/#{input['project_uid']}/field_reports/export").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + else + post("/projects/#{input['project_uid']}/#{input['object'].pluralize}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end.merge('project_uid' => input['project_uid']) + end, + + output_fields: lambda do |object_definitions| + object_definitions['get_output_schema'] + end, + + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") + end + }, + + update_object: { + title: 'Update object', + description: lambda do |_, objects| + "Update #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Update object in PlanGrid", + + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'update_object_list', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| + object_definitions['update_input_schema'] + end, + + execute: lambda do |_connection, input| + payload = + input.except('project_uid', 'object').each_with_object({}) do |(key, val), hash| + hash[key] = if %w[due_at sent_at].include?(key) + val.to_time.utc.iso8601 + elsif key == 'item_uids' + val.split(",") + else + val + end + end + if input['object'] == 'project' + patch("/projects/#{input['project_uid']}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + elsif input['object'] == 'submittal_package' || input['object'] == 'submittal_item' + response = patch("/projects/#{input['project_uid']}/submittals/#{input['object'].split('_').last.pluralize}/#{input['uid']}").payload(payload.except('uid')). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + response.dig('items', 'uids')&.map do |uid| + { "value" => uid } + end.inject(:merge) + response + else + patch("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}").payload(payload.except('uid')). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end + end.merge('project_uid' => input['project_uid']) + end, + + output_fields: lambda do |object_definitions| + object_definitions['get_output_schema'] + end, + + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") + end + }, + + get_object: { + title: 'Get object by ID', + description: lambda do |_, objects| + "Get #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Get object by ID in PlanGrid", + + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'get_objects', + toggle_hint: 'Select object', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| [ { name: 'project_uid', @@ -1725,8 +2228,8 @@ pick_list: 'project_list', label: 'Project', optional: false, - hint: 'If your project is not in top 50, use project ID toggle.', toggle_hint: 'Select project', + hint: 'If your project is not in top 50, use project ID toggle.', toggle_field: { name: 'project_uid', type: 'string', @@ -1736,1040 +2239,797 @@ toggle_hint: 'Enter project ID', hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' } - } - ] - ) - end - }, - - download_input_schema: { - fields: lambda do |_connection, config_fields| - case config_fields['object'] - when 'field_reports/export' - [{ name: 'uid', label: 'Export ID', optional: false }] - when 'sheets/packet' - [{ name: 'uid', label: "Sheet Packet ID", optional: false, - hint: 'Ensure the status of the sheet packet export is `complete` before downloading.' }] - else - [{ name: 'uid', label: "#{config_fields['object'].labelize} ID", optional: false }] - end - end - }, - - trigger_input: { - fields: lambda do |_connection, config_fields| - if config_fields['object'] != 'project' - [ - { - name: 'project_uid', optional: false, - label: 'Project', - control_type: 'select', pick_list: 'project_list', - hint: 'If your project is not in top 50, use project ID toggle.', - toggle_hint: 'Select project', - toggle_field: { - name: 'project_uid', - label: 'Project ID', - type: 'string', - control_type: 'text', - toggle_hint: 'Enter project ID', - hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } - }, - { - name: 'output_schema', - control_type: 'schema-designer', - ngIf: 'input.object == "field_report"', - extends_schema: true, - label: 'PDF field values', - hint: 'Manually define the values expected of your PDF field values in the field report.', - optional: true - } - ] - else - [] - end - end - }, - - custom_action_input: { - fields: lambda do |_connection, config_fields| - input_schema = parse_json(config_fields.dig('input', 'schema') || '[]') - - [ - { - name: 'path', - optional: false, - hint: 'Base URI is https://io.plangrid.com' \ - ' - path will be appended to this URI. ' \ - 'Use absolute URI to override this base URI.' - }, - ( - if %w[get delete].include?(config_fields['verb']) - { - name: 'input', - type: 'object', - control_type: 'form-schema-builder', - sticky: input_schema.blank?, - label: 'URL parameters', - add_field_label: 'Add URL parameter', - properties: [ - { - name: 'schema', - extends_schema: true, - sticky: input_schema.blank? - }, - ( - if input_schema.present? - { - name: 'data', - type: 'object', - properties: call('make_schema_builder_fields_sticky', - input_schema) - } - end - ) - ].compact - } - else - { - name: 'input', - type: 'object', - properties: [ - { - name: 'schema', - extends_schema: true, - schema_neutral: true, - control_type: 'schema-designer', - sample_data_type: 'json_input', - sticky: input_schema.blank?, - label: 'Request body parameters', - add_field_label: 'Add request body parameter' - }, - ( - if input_schema.present? - { - name: 'data', - type: 'object', - properties: call('make_schema_builder_fields_sticky', - input_schema) - } - end - ) - ].compact - } - end - ), - { - name: 'output', - control_type: 'schema-designer', - sample_data_type: 'json_http', - extends_schema: true, - schema_neutral: true, - sticky: true - } - ] - end - }, - - custom_action_output: { - fields: lambda do |_connection, config_fields| - parse_json(config_fields['output'] || '[]') - end - } - }, - - actions: { - custom_action: { - description: "Custom action in Plangrid", - help: { - body: 'Build your own Plangrid action for any Plangrid REST endpoint.', - learn_more_url: 'https://developer.plangrid.com/docs/', - learn_more_text: 'The Plangrid API documentation' - }, - - config_fields: [{ - name: 'verb', - label: 'Request type', - hint: 'Select HTTP method of the request', - optional: false, - control_type: 'select', - pick_list: %w[get post patch delete].map { |verb| [verb.upcase, verb] } - }], - - input_fields: lambda do |object_definitions| - object_definitions['custom_action_input'] - end, + }, + ].concat(object_definitions['get_input_schema']) + end, - execute: lambda do |_connection, input| - error("#{input['verb']} not supported") if %w[get post patch delete].exclude?(input['verb']) - data = input.dig('input', 'data').presence || {} - case input['verb'] - when 'get' - response = get(input['path'], data). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end.compact - if response.is_a?(Array) - array_name = parse_json(input['output'] || '[]'). - dig(0, 'name') || 'array' - { array_name.to_s => response } - elsif response.is_a?(Hash) + execute: lambda do |_connection, input| + params = + input.except('project_uid', 'object').each_with_object({}) do |(key, val), hash| + hash[key] = %w[updated_after].include?(key) ? val.to_time.utc.iso8601 : val + end + case input['object'] + when 'project' + get("/projects/#{input['project_uid']}") + when 'sheet_packet' + get("/projects/#{input['project_uid']}/sheets/packets/#{input['uid']}") + when 'submittal_package' + response = get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}").merge('package_uid' => input['uid']) + response.dig('items', 'uids')&.map do |uid| + { "value" => uid } + end.inject(:merge) response + when 'submittal_file_group' + get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/file_groups"). + merge('package_uid' => input['uid']) + when 'submittal_history' + get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/history"). + merge('package_uid' => input['uid']) + when 'submittal_review_status' + get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/reviews"). + merge('package_uid' => input['uid']) + when 'field_report_export' + get("/projects/#{input['project_uid']}/field_reports/export/#{input['uid']}") else - error('API response is not a JSON') - end - when 'post' - post(input['path'], data). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end.compact - when 'patch' - patch(input['path'], data). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end.compact - when 'delete' - delete(input['path'], data). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end.compact - end - end, - - output_fields: lambda do |object_definitions| - object_definitions['custom_action_output'] - end - }, + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") + end.merge('project_uid' => input['project_uid']) + end, - create_object: { - title: 'Create object', - description: lambda do |_, objects| - "Create #{objects['object']&.downcase || 'object'} in PlanGrid" - end, - help: "Create object in PlanGrid", + output_fields: lambda do |object_definitions| + object_definitions['get_output_schema'] + end, - config_fields: [ - { - name: 'object', - optional: false, - label: 'Object', - control_type: 'select', - pick_list: 'create_object_list', - hint: 'Select the object from picklist.' - } - ], + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") + end + }, - input_fields: lambda do |object_definitions| - object_definitions['create_input_schema'] - end, + search_objects: { + title: 'Search objects', + description: lambda do |_, objects| + "Search #{objects['object']&.downcase&.pluralize || 'objects'} in PlanGrid" + end, + help: "Search objects in PlanGrid", - execute: lambda do |_connection, input| - if input['object'] == 'submittals/package' - input['item_uids'] = input['item_uids'].split(',') - end + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'search_objects', + toggle_hint: 'Select object', + hint: 'Select the object from picklist.' + } + ], - if input['object'] == 'field_reports/export' - input['field_report_uids'] = input['field_report_uids'].split(',') - end - - payload = - input.except('project_uid', 'object').each_with_object({}) do |(key, val), hash| - hash[key] = if %w[due_at sent_at].include?(key) - val.to_time.utc.iso8601 - elsif %w[sheet_uids assigned_to_uids].include?(key) - val.split(",") - else - val - end - end - case input['object'] - when 'project' - post('/projects').payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end - when 'sheet_packet', 'sheet_upload', 'user_invite' - path = input['object'].split("_") - post("/projects/#{input['project_uid']}/#{path.first.pluralize}/#{path.last.pluralize}").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end + input_fields: lambda do |object_definitions| + [ + { + name: 'project_uid', + control_type: 'select', + pick_list: 'project_list', + label: 'Project', + optional: false, + toggle_hint: 'Select project', + hint: 'If your project is not in top 50, use project ID toggle.', + toggle_field: { + name: 'project_uid', + type: 'string', + control_type: 'text', + optional: false, + label: 'Project ID', + toggle_hint: 'Enter project ID', + hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' + } + } + ].concat(object_definitions['get_input_schema']) + end, - when 'field_reports/export' - post("/projects/#{input['project_uid']}/field_reports/export").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") + execute: lambda do |_connection, input| + params = + input.except('project_uid', 'object', 'output_schema').each_with_object({}) do |(key, val), hash| + hash[key] = %w[updated_after updated_before].include?(key) ? val.to_time.utc.iso8601 : val end - else - post("/projects/#{input['project_uid']}/#{input['object'].pluralize}").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") + case input['object'] + when 'rfi_status' + { data: get("/projects/#{input['project_uid']}/rfis/statuses", params)['data'] } + when 'field_report' + results = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params)['data'] + results.map do |field_report| + field_report['custom_items']&.each do |items| + items['array_val']&.map do |val| + { "value" => val } + end.inject(:merge) + end + field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge)) + end.inject(:merge) + { data: results } + when 'submittal_item' + { data: get("/projects/#{input['project_uid']}/submittals/items", params)['data'] } + else + response = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params)['data'] + response&.each do |res| + %w(user_permissions group_permissions).each do |key| + res[key]&.each do |group| + group['permissions']&.map do |permission| + { "value" => permission } + end.inject(:merge) + end + end end - end.merge('project_uid' => input['project_uid']) - end, - - output_fields: lambda do |object_definitions| - object_definitions['get_output_schema'] - end, - - sample_output: lambda do |_connection, input| - call(:get_sample_output, input['object'], input['project_uid'] || "") - end - }, + { data: response } + end.merge('project_uid' => input['project_uid']) + end, - update_object: { - title: 'Update object', - description: lambda do |_, objects| - "Update #{objects['object']&.downcase || 'object'} in PlanGrid" - end, - help: "Update object in PlanGrid", + output_fields: lambda do |object_definitions| + [ + { + name: 'data', type: 'array', of: 'object', properties: object_definitions['get_output_schema'] + } + ] + end, - config_fields: [ - { - name: 'object', - optional: false, - label: 'Object', - control_type: 'select', - pick_list: 'update_object_list', - hint: 'Select the object from picklist.' - } - ], + sample_output: lambda do |_connection, input| + { "data" => Array.wrap(call(:get_sample_output, input['object'], input['project_uid'] || "")) } + end + }, - input_fields: lambda do |object_definitions| - object_definitions['update_input_schema'] - end, + upload_object: { + title: 'Upload object', + description: lambda do |_, objects| + "Upload #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Upload object in PlanGrid", - execute: lambda do |_connection, input| - payload = - input.except('project_uid', 'uid', 'object').each_with_object({}) do |(key, val), hash| - hash[key] = %w[due_at sent_at].include?(key) ? val.to_time.utc.iso8601 : val + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'upload_object_list', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| + object_definitions['upload_input_schema'] + end, + + execute: lambda do |_connection, input| + case input['object'] + when 'file_upload' + file_upload_info = post("/projects/#{input['project_uid']}/sheets/" \ + "uploads/#{input.delete('ver_upload_uid')}/" \ + "files/#{input.delete('file_upload_request_uid')}"). + headers('Content-Type': 'application/json'). + payload(file_name: input.delete('file_name')) + call(:get_upload_object, file_upload_info, input) + when 'photo', 'attachment' + file_upload_info = post("/projects/#{input['project_uid']}/#{input['object'].pluralize}/uploads"). + headers('Content-type': 'application/json'). + payload(input.except('project_uid', 'file_content', 'object')) + call(:get_upload_object, file_upload_info, input) + else + post("/projects/#{input['project_uid']}/sheets/uploads/#{input['ver_upload_uid']}/completions") end - if input['object'] == 'project' - patch("/projects/#{input['project_uid']}").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end - else - patch("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}").payload(payload). - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end - end.merge('project_uid' => input['project_uid']) - end, + end, - output_fields: lambda do |object_definitions| - object_definitions['get_output_schema'] - end, + output_fields: lambda do |object_definitions| + object_definitions['get_output_schema'] + end, - sample_output: lambda do |_connection, input| - call(:get_sample_output, input['object'], input['project_uid'] || "") - end + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") + end + }, +# Streaming is not compatible with SDK framework +# download_object: { +# title: 'Download object', +# description: lambda do |_, objects| +# "Download #{objects['object']&.downcase || 'object'} in PlanGrid" +# end, +# help: "Download object in PlanGrid", + +# config_fields: [ +# { +# name: 'object', +# optional: false, +# label: 'Object', +# control_type: 'select', +# pick_list: 'download_object_list', +# toggle_hint: 'Select object', +# hint: 'Select the object from picklist.' +# } +# ], + +# input_fields: lambda do |object_definitions| +# [ +# { +# name: 'project_uid', +# control_type: 'select', +# pick_list: 'project_list', +# label: 'Project', +# optional: false, +# toggle_hint: 'Select project', +# hint: 'If your project is not in top 50, use project ID toggle.', +# toggle_field: { +# name: 'project_uid', +# type: 'string', +# control_type: 'text', +# optional: false, +# label: 'Project ID', +# toggle_hint: 'Enter project ID', +# hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' +# } +# }, +# ].concat(object_definitions['download_input_schema']) +# end, + +# execute: lambda do |_connection, input| +# if input["chunk_size"].present? +# size_in_bytes = call('chunksize_to_bytes', input["chunk_size"]).to_i +# end + +# if size_in_bytes.present? && !size_in_bytes.between?(32.kilobyte, 10.megabyte) +# raise(Workato::Adapters::OnException::BadInput, "Chunk size is not in the expected range.") +# end + +# record = case input['object'] +# when 'field_report_export' +# get("/projects/#{input['project_uid']}/field_reports/export/#{input['uid']}") +# when 'sheet_packet' +# get("/projects/#{input['project_uid']}/sheets/packets/#{input['uid']}") +# else +# get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") +# end + +# Workato::Types::InputStreamProxy.initialize_output("content", +# @shared_account, +# { 'url' => record['url'] || record['file_url'] }, +# size_in_bytes.presence) +# end, + +# output_fields: lambda do |_object_definitions| +# [ +# { name: 'content', label: 'File Contents' } +# ] +# end, + +# sample_output: lambda do |_connection, _input| +# { +# "content": "" +# } +# end +# } }, - get_object: { - title: 'Get object by ID', - description: lambda do |_, objects| - "Get #{objects['object']&.downcase || 'object'} in PlanGrid" - end, - help: "Get object by ID in PlanGrid", - - config_fields: [ - { - name: 'object', - optional: false, - label: 'Object', - control_type: 'select', - pick_list: 'get_objects', - toggle_hint: 'Select object', - hint: 'Select the object from picklist.' - } - ], + triggers: { + new_object: { + title: 'New object in PlanGrid', + description: lambda do |_, objects| + "New #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Triggers when an object is created", - input_fields: lambda do |object_definitions| - [ + config_fields: [ { - name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', + name: 'object', optional: false, - toggle_hint: 'Select project', - hint: 'If your project is not in top 50, use project ID toggle.', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Enter project ID', - hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } - }, - ].concat(object_definitions['get_input_schema']) - end, + label: 'Object', + control_type: 'select', + pick_list: 'object_list', + hint: 'Select the object from picklist.' + } + ], - execute: lambda do |_connection, input| - params = - input.except('project_uid', 'object').each_with_object({}) do |(key, val), hash| - hash[key] = %w[updated_after].include?(key) ? val.to_time.utc.iso8601 : val - end - case input['object'] - when 'project' - get("/projects/#{input['project_uid']}") - when 'field_reports/export' - get("/projects/#{input['project_uid']}/field_reports/export/#{input['uid']}") - when 'sheet_packet' - get("/projects/#{input['project_uid']}/sheets/packets/#{input['uid']}") - when 'submittals/item' - get("/projects/#{input['project_uid']}/submittals/items?uids=#{input['uids']}").dig('data',0) - when 'submittals_file_group' - get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/file_groups") - .merge('package_uid' => input['uid']) - when 'submittals_history' - get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/history") - .merge('package_uid' => input['uid']) - when 'submittals_review_status' - get("/projects/#{input['project_uid']}/submittals/packages/#{input['uid']}/reviews") - .merge('package_uid' => input['uid']) - else - get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") - end.merge('project_uid' => input['project_uid']) - end, + input_fields: lambda do |object_definitions| + object_definitions['trigger_input'].concat( + [ + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + ) + end, + poll: lambda do |_connection, input, closure| + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 10 + skip = closure&.[]('skip') || 0 + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + elsif input['object'] == 'project' + get("/projects").params(limit: limit, skip: skip, updated_after: updated_after) + elsif input['object'] == 'issue' + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after, include_annotationless: true) + elsif input['object'] == 'field_report' + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after) + else + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(limit: limit, skip: skip, updated_after: updated_after) + end + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'next_page_url' => next_page_url } + else + { 'skip' => 0, + 'updated_after' => response['data']&. + last&.[]('created_at') || response['data']&.last&.[]('published_at') } + end + objects = if input['object'] == 'field_report' + response['data']&.map do |field_report| + field_report['custom_items']&.each do |items| + items['array_val']&.map do |val| + { "value" => val } + end.inject(:merge) + end + field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge), + 'project_uid' => input['project_uid']) + end + else + response['data']&.map { |o| o.merge('project_uid' => input['project_uid']) } + end + { + events: objects || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |object| + object['uid'] + end, + output_fields: lambda do |object_definitions| + object_definitions['get_output_schema'] + end, + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") + end + }, - output_fields: lambda do |object_definitions| - object_definitions['get_output_schema'] - end, + new_updated_object: { + title: 'New or updated object in PlanGrid', + description: lambda do |_, objects| + "New or updated #{objects['object']&.downcase || 'object'} in PlanGrid" + end, + help: "Triggers when an object is created or updated", - sample_output: lambda do |_connection, input| - call(:get_sample_output, input['object'], input['project_uid'] || "") - end + config_fields: [ + { + name: 'object', + optional: false, + label: 'Object', + control_type: 'select', + pick_list: 'object_list_new', + hint: 'Select the object from picklist.' + } + ], + + input_fields: lambda do |object_definitions| + object_definitions['trigger_input'].concat( + [ + { + name: 'since', + label: 'When first started, this recipe should pick up events from', + hint: 'When you start recipe for the first time, ' \ + 'it picks up trigger events from this specified date and time. ' \ + 'Leave empty to get records created or updated one hour ago', + sticky: true, + type: 'timestamp' + } + ] + ) + end, + poll: lambda do |_connection, input, closure| + updated_after = closure&.[]('updated_after') || + (input['since'] || 1.hour.ago).to_time.utc.iso8601 + limit = 10 + skip = closure&.[]('skip') || 0 + update_time = Time.now.utc.iso8601 + api_params = { limit: limit, skip: skip, updated_after: updated_after } + response = if (next_page_url = closure&.[]('next_page_url')).present? + get(next_page_url) + elsif input['object'] == 'project' + get("/projects").params(api_params) + elsif input['object'] == 'issue' + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(api_params.merge(include_annotationless: true)) + elsif input['object'] == 'field_report' + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(api_params) + elsif input['object'] == 'attachment' + get("/projects/#{input['project_uid']}/documents"). + params(api_params) + elsif input['object'] == 'submittal_item' || input['object'] == 'submittal_package' + get("/projects/#{input['project_uid']}/submittals/#{input['object'].split('_').last.pluralize}"). + params(api_params) + else + get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). + params(api_params) + end + object_update_time = ['annotation', 'sheet', 'attachment'].include? input['object'] + closure = if (next_page_url = response['next_page_url']).present? + { 'skip' => skip + limit, + 'next_page_url' => next_page_url } + else + { 'skip' => 0, + 'updated_after' => object_update_time ? update_time : response['data']&.last&.[]('updated_at') } + end + project_hash = { 'project_uid' => input['project_uid'] } + project_hash["updated_after"] = (closure["updated_after"] || updated_after) if ['annotation', 'sheet', 'attachment'].include? input['object'] + objects = if input['object'] == 'field_report' + response['data']&.map do |field_report| + field_report['custom_items']&.each do |items| + items['array_val']&.map do |val| + { "value" => val } + end.inject(:merge) + end + field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge), + 'project_uid' => input['project_uid']) + end + elsif input['object'] == 'attachment' + response['data'].select { |o| o['type'] == 'file' }&.map do |document| + get("/projects/#{input['project_uid']}/attachments/#{document['uid']}") + end&.map { |o| o.merge('project_uid' => input['project_uid']) } + elsif input['object'] == 'field_report_template' + response['data']&.each do |res| + %w(user_permissions group_permissions).each do |key| + res[key]&.each do |group| + group['permissions']&.map do |permission| + { "value" => permission } + end.inject(:merge) + end + end + res.merge('project_uid' => input['project_uid']) + end + elsif input['object'] == 'submittal_package' + response['data']&.map do |package| + package.dig('items', 'uids')&.map do |uid| + { "value" => uid } + end.inject(:merge) + package.merge('project_uid' => input['project_uid']) + end + else + response['data']&.map { |o| o.merge('project_uid' => input['project_uid']) } + end + { + events: objects || [], + next_poll: closure, + can_poll_more: response['next_page_url'].present? + } + end, + dedup: lambda do |object| + "#{object['uid']}@#{(object['updated_after'] || object['updated_at'])}" + end, + output_fields: lambda do |object_definitions| + object_definitions['get_output_schema'] + end, + sample_output: lambda do |_connection, input| + call(:get_sample_output, input['object'], input['project_uid'] || "") + end + }, }, - search_objects: { - title: 'Search objects', - description: lambda do |_, objects| - "Search #{objects['object']&.downcase&.pluralize || 'objects'} in PlanGrid" + methods: { + dynamic_pdf_output_schema: lambda do |schema_json| +## Only compatible in Workato platform right now +# fields = Workato::FormSchema.new(schema_json, wrapper: nil).schema +# if fields.present? +# Workato::Schema::Properties.new do |schema| +# schema.concat(fields) +# end +# else +# [] +# end +# fields + [] end, - help: "Search objects in PlanGrid", - config_fields: [ - { - name: 'object', - optional: false, - label: 'Object', - control_type: 'select', - pick_list: 'search_objects', - toggle_hint: 'Select object', - hint: 'Select the object from picklist.' - } - ], - - input_fields: lambda do |object_definitions| - [ + get_sample_output: lambda do |object, project_uid| + case object + when 'project' + get('/projects')&.dig('data', 0) + when 'field_report' + results = get("/projects/#{project_uid}/field_reports").dig('data', 0)&.merge('project_uid' => project_uid) + results['custom_items']&.each do |items| + items['array_val']&.map do |val| + { "value" => val } + end.inject(:merge) + end + results.merge('pdf_form_fields' => results['pdf_form_values']&.map { |a| { a['name'].gsub("-", "_") => a['value'] } }&.inject(:merge)) + when 'rfi_status' + get("/projects/#{project_uid}/rfis/statuses")&.dig('data', 0)&.merge('project_uid' => project_uid) + when 'user_invite' + get("/projects/#{project_uid}/users")&.dig('data', 0)&.merge('project_uid' => project_uid) + when 'sheet_packet' { - name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - hint: 'If your project is not in top 50, use project ID toggle.', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Enter project ID', - hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } + "data" => [ + { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + file_url: "https://packet-assets.plangrid.com/92cf7193-af0c-42fc-a3ab-7ef5149da720.pdf", + resource: { + uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", + url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/" \ + "packets/92cf7193-af0c-42fc-a3ab-7ef5149da720" + }, + status: "incomplete" + } + ] } - ].concat(object_definitions['get_input_schema']) + when 'sheet_upload' + { + "data" => [ + { + uid: "d050ed4d-425b-4cd2-a46a-1113be6ed37c", + complete_url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/d050ed4d-425b-4cd2-a46a-1113be6ed37c/completions", + status: "incomplete", + file_upload_requests: [ + { + uid: "cba96343-bfaf-4f95-805a-dd49169944c0", + upload_status: "issued", + url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/d050ed4d-425b-4cd2-a46a-1113be6ed37c/files/cba96343-bfaf-4f95-805a-dd49169944c0" + } + ] + } + ] + } + when 'version_upload' + { + "data" => [ + { + uid: "f23f1677-cb77-425f-bdd5-626a9fba8e83", + complete_url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/f23f1677-cb77-425f-bdd5-626a9fba8e83/completions", + status: "complete" + } + ] + } + when 'field_report_export' + { + "file_url": "https://plangrid-reports-prod-reportsresults-19fdmf8y8pfpb.s3.amazonaws.com/458aacad-a47f-4957-96d2-7a6c4e792bec/5182dc29-d13f-4f11-a87e-3e1f82c8cc82.pdf", + "resource": { + "uid": "075d9458-eb0d-4be8-b702-c0a73467612c", + "url": "https://io.plangrid.com/projects/458aacad-a47f-4957-96d2-7a6c4e792bec/field_reports/export/075d9458-eb0d-4be8-b702-c0a73467612c" + }, + "resource_url": "https://io.plangrid.com/projects/458aacad-a47f-4957-96d2-7a6c4e792bec/field_reports/export/075d9458-eb0d-4be8-b702-c0a73467612c", + "status": "complete", + "uid": "075d9458-eb0d-4be8-b702-c0a73467612c", + "project_uid": "458aacad-a47f-4957-96d2-7a6c4e792bec" + } + when 'submittal_item', 'submittal_package' + response = get("/projects/#{project_uid}/submittals/#{object.split('_').last.pluralize}")&.dig('data', 0)&.merge('project_uid' => project_uid) + response&.dig('items', 'uids')&.map do |uid| + { "value" => uid } + end.inject(:merge) + response + when 'submittal_history', 'submittal_file_group', 'submittal_review_status' + package_id = get("/projects/#{project_uid}/submittals/packages")&.dig('data', 0, 'uid') + if object == 'submittal_history' + get("/projects/#{project_uid}/submittals/packages/#{package_id}/history") + elsif object == 'submittal_review_status' + get("/projects/#{project_uid}/submittals/packages/#{package_id}/reviews") + else + get("/projects/#{project_uid}/submittals/packages/#{package_id}/file_groups") + end&.merge('project_uid' => project_uid) + else + response = get("/projects/#{project_uid}/#{object.pluralize}")&.dig('data', 0)&.merge('project_uid' => project_uid) + if object == 'field_report_template' + %w(user_permissions group_permissions).each do |key| + response[key]&.each do |group| + group['permissions']&.map do |permission| + { "value" => permission } + end.inject(:merge) + end + end + end + response + end end, - execute: lambda do |_connection, input| - params = - input.except('project_uid', 'object', 'output_schema').each_with_object({}) do |(key, val), hash| - hash[key] = %w[updated_after].include?(key) ? val.to_time.utc.iso8601 : val - end - case input['object'] - when 'rfi_status' - response = get("/projects/#{input['project_uid']}/rfis/statuses", params) - { data: response['data'], total_count: response['total_count'], next_page_url: response['next_page_url'] } - when 'field_report' - response = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params) - results = response['data'] - results.map do |field_report| - field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge)) + get_upload_object: lambda do |file_upload_info, input| + headers = file_upload_info&.dig('aws_post_form_arguments', 'fields')&. + each_with_object({}) do |obj, hash| + hash[obj['name']] = obj['value'] + end + post(file_upload_info&.dig('aws_post_form_arguments', 'action')). + payload(key: headers['key'], + policy: headers['policy'], + signature: headers['signature'], + AWSAccessKeyId: headers['AWSAccessKeyId'], + 'content-type': headers['Content-Type'], + 'success_action_redirect': headers['success_action_redirect'], + 'x-amz-server-side-encryption': + headers['x-amz-server-side-encryption'], + 'x-amz-storage-class': headers['x-amz-storage-class'], + file: input['file_content']). + request_format_multipart_form. + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") end - { data: results, total_count: response['total_count'], next_page_url: response['next_page_url'] } - else - response = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params) - { data: response['data'], total_count: response['total_count'], next_page_url: response['next_page_url'] } - end.merge('project_uid' => input['project_uid']) end, - output_fields: lambda do |object_definitions| - [ - { - name: 'data', label: 'Results', type: 'array', of: 'object', properties: object_definitions['get_output_schema'] - }, - { name: 'total_count', label: 'Total Count', type: 'integer' }, - { name: 'next_page_url', label: 'Next Page URL' } - ] + make_schema_builder_fields_sticky: lambda do |input| + input.map do |field| + if field[:properties].present? + field[:properties] = call("make_schema_builder_fields_sticky", + field[:properties]) + elsif field["properties"].present? + field["properties"] = call("make_schema_builder_fields_sticky", + field["properties"]) + end + field[:sticky] = true + field + end end, - sample_output: lambda do |_connection, input| - { "data" => Array.wrap(call(:get_sample_output, input['object'], input['project_uid'] || "")) } + chunksize_to_bytes: lambda do |input| + num_value = input.strip.match(/^(?\d+)\s?(?\w+)?$/) + num_value[:num].to_i * + case num_value[:unit]&.downcase + when 'kb' + 1024 + when 'mb' + 1024**2 + when 'gb' + 1024**3 + else + 1 + end end }, - upload_object: { - title: 'Upload object', - description: lambda do |_, objects| - "Upload #{objects['object']&.downcase || 'object'} in PlanGrid" + pick_lists: { + create_object_list: lambda do |_connection| + [["Project", "project"], ["Sheet packet", "sheet_packet"], ["Task list", "issue_list"], ["Task", "issue"], ["RFI", "rfi"], + ["Sheet version", "sheet_upload"], ["Invite user", "user_invite"], ['Field report export', 'field_report_export'], + ['Submittal item', 'submittal_item'], ['Submittal package', 'submittal_package']] end, - help: "Upload object in PlanGrid", - config_fields: [ - { - name: 'object', - optional: false, - label: 'Object', - control_type: 'select', - pick_list: 'upload_object_list', - hint: 'Select the object from picklist.' - } - ], + update_object_list: lambda do |_connection| + [["Project", "project"], ["Task List", "issue_list"], ["Task", "issue"], ["RFI", "rfi"], + ["Photo metadata", "photo"], ['Submittal item', 'submittal_item'], ['Submittal package', 'submittal_package']] + end, - input_fields: lambda do |object_definitions| - object_definitions['upload_input_schema'] + upload_object_list: lambda do |_connection| + [["Document", "attachment"], ["Photo", "photo"], ["File to sheet version", "file_upload"], + ["Complete version", "version_upload"]] end, - execute: lambda do |_connection, input| - case input['object'] - when 'file_upload' - file_upload_info = post("/projects/#{input['project_uid']}/sheets/" \ - "uploads/#{input.delete('ver_upload_uid')}/" \ - "files/#{input.delete('file_upload_request_uid')}"). - headers('Content-Type': 'application/json'). - payload(file_name: input.delete('file_name')) - call(:get_upload_object, file_upload_info, input) - when 'photo', 'attachment' - file_upload_info = post("/projects/#{input['project_uid']}/#{input['object'].pluralize}/uploads"). - headers('Content-type': 'application/json'). - payload(input.except('project_uid', 'file_content', 'object')) - call(:get_upload_object, file_upload_info, input) - else - post("/projects/#{input['project_uid']}/sheets/uploads/#{input['ver_upload_uid']}/completions") - end + get_objects: lambda do |_connection| + [["Project", "project"], ["RFI", "rfi"], ["Task", "issue"], ["User", "user"], ["Snapshot", "snapshot"], ["Sheet", "sheet"], ["Sheet Packet", "sheet_packet"], + ["Photo", "photo"], ["Document", "attachment"], ["Task_list", "issue_list"], ['Field report export', 'field_report_export'], ['Submittal package', 'submittal_package'], + ['Submittal package history', 'submittal_history'], ['Submittal package file group', 'submittal_file_group'], + ['Submittal package review status', 'submittal_review_status']] end, - output_fields: lambda do |object_definitions| - object_definitions['get_output_schema'] + search_objects: lambda do |_connection| + [["RFI status", "rfi_status"], ["Role", "role"], ["Field Report", "field_report"], ['Field report template', 'field_report_template'], + ['Submittal item', 'submittal_item']] end, - sample_output: lambda do |_connection, input| - call(:get_sample_output, input['object'], input['project_uid'] || "") - end - }, + download_object_list: lambda do |_connection| + [['Document', 'attachment'], ['Field report export', 'field_report_export'], ['Sheet packet', 'sheet_packet']] + end, - download_object: { - title: 'Download object', - description: lambda do |_, objects| - "Download #{objects['object']&.downcase || 'object'} in PlanGrid" + object_list: lambda do |_connection| + [["Project", "project"], ["Sheet", "sheet"], ["Document", "attachment"], ["Task", "issue"], ["RFI", "rfi"], + ["Annotation", "annotation"], ["Photo", "photo"], ["Snapshot", "snapshot"], ["Field Report", "field_report"]] end, - help: "Download object in PlanGrid", - config_fields: [ - { - name: 'object', - optional: false, - label: 'Object', - control_type: 'select', - pick_list: 'download_object_list', - toggle_hint: 'Select object', - hint: 'Select the object from picklist.' - } - ], + object_list_new: lambda do |_connection| + [["Project", "project"], ["Task", "issue"], ["RFI", "rfi"], ["Sheet", "sheet"], ["Field Report", "field_report"], ["Document", "attachment"], ["Annotation", "annotation"], + ['Field report template', 'field_report_template'], ['Submittal package', 'submittal_package'], ['Submittal item', 'submittal_item']] + end, - input_fields: lambda do |object_definitions| - [ - { - name: 'project_uid', - control_type: 'select', - pick_list: 'project_list', - label: 'Project', - optional: false, - toggle_hint: 'Select project', - hint: 'If your project is not in top 50, use project ID toggle.', - toggle_field: { - name: 'project_uid', - type: 'string', - control_type: 'text', - optional: false, - label: 'Project ID', - toggle_hint: 'Enter project ID', - hint: 'Provide project ID. For example, 0bbb5bdb-3f87-4b46-9975-90e797ee9ff9' - } - }, - ].concat(object_definitions['download_input_schema']) + project_list: lambda do |_connection| + get('/projects')&.[]('data')&.pluck('name', 'uid') end, - execute: lambda do |_connection, input| - case input['object'] - when 'field_reports/export' - record = get("/projects/#{input['project_uid']}/field_reports/export/#{input['uid']}") - file_content = get(record['url'] || record['file_url']). - response_format_raw. - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end - { content: file_content } - else - record = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") - file_content = get(record['url'] || record['file_url']). - response_format_raw. - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end - { content: file_content } + project_types: lambda do |_connection| + ['general', 'manufacturing', 'power', 'water-sewer-waste', + 'industrial-petroleum', 'transportation', 'hazardous-waste', + 'telecom', 'education-k-12', 'education-higher', 'gov-federal', + 'gov-state-local', 'other'].map { |type| [type.labelize, type] } + end, + + project_folders: lambda do |_connection, project_uid:| + if project_uid.length == 36 + folders = get("/projects/#{project_uid}/attachments")['data']&. + pluck('folder')&.uniq + folders.size > 0 ? folders&.map { |folder| [folder || 'Root', folder || ''] } : [['Root', '']] end end, - output_fields: lambda do |object_definitions| + transmission_status_type: lambda do |_connection| [ - { name: 'content', label: 'File Contents' } + ["Awaiting submission", "Awaiting Submission"], + ["Requested", "Requested"], + ["Revise & resubmit", "Revise & Resubmit"], + ["Awaiting GC review", "Awaiting GC Review"], + ["In GC review", "In GC Review"], + ["Awaiting design review", "Awaiting Design Review"], + ["In design review", "In Design Review"], + ["Approved", "Approved"], + ["Published", "Published"] ] - end - } - }, - - triggers: { - new_object: { - title: 'New object in PlanGrid', - description: lambda do |_, objects| - "New #{objects['object']&.downcase || 'object'} in PlanGrid" end, - help: "Triggers when an object is created", - config_fields: [ - { - name: 'object', - optional: false, - label: 'Object', - control_type: 'select', - pick_list: 'object_list', - hint: 'Select the object from picklist.' - } - ], - - input_fields: lambda do |object_definitions| - object_definitions['trigger_input'].concat( - [ - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] - ) - end, - poll: lambda do |_connection, input, closure| - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 10 - skip = closure&.[]('skip') || 0 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - elsif input['object'] == 'project' - get("/projects").params(limit: limit, skip: skip, updated_after: updated_after) - elsif input['object'] == 'issue' - get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). - params(limit: limit, skip: skip, updated_after: updated_after, include_annotationless: true) - elsif input['object'] == 'field_report' - get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). - params(limit: limit, skip: skip, updated_after: updated_after) - else - get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). - params(limit: limit, skip: skip, updated_after: updated_after) - end - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'next_page_url' => next_page_url } - else - { 'skip' => 0, - 'updated_after' => response['data']&. - last&.[]('created_at') || response['data']&.last&.[]('published_at') } - end - objects = if input['object'] == 'field_report' - response['data']&.map do |field_report| - field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge), - 'project_uid' => input['project_uid']) - end - else - response['data']&.map { |o| o.merge('project_uid' => input['project_uid']) } - end - { - events: objects || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? - } - end, - dedup: lambda do |object| - object['uid'] + timezones: lambda do |_connection| + %w[Africa/Abidjan Africa/Accra Africa/Addis_Ababa Africa/Algiers Africa/Asmara Africa/Bamako Africa/Bangui Africa/Banjul Africa/Bissau Africa/Blantyre Africa/Brazzaville + Africa/Bujumbura Africa/Cairo Africa/Casablanca Africa/Ceuta Africa/Conakry Africa/Dakar Africa/Dar_es_Salaam Africa/Djibouti Africa/Douala Africa/El_Aaiun + Africa/Freetown Africa/Gaborone Africa/Harare Africa/Johannesburg Africa/Juba Africa/Kampala Africa/Khartoum Africa/Kigali Africa/Kinshasa Africa/Lagos + Africa/Lome Africa/Luanda Africa/Lubumbashi Africa/Lusaka Africa/Malabo Africa/Maputo Africa/Maseru Africa/Mbabane Africa/Mogadishu Africa/Monrovia Africa/Nairobi + Africa/Ndjamena Africa/Niamey Africa/Nouakchott Africa/Ouagadougou Africa/Porto-Novo Africa/Sao_Tome Africa/Timbuktu Africa/Tripoli Africa/Tunis Africa/Windhoek + America/Adak America/Anchorage America/Anguilla America/Antigua America/Araguaina America/Argentina/Buenos_Aires America/Argentina/Catamarca + America/Argentina/ComodRivadavia America/Argentina/Cordoba America/Argentina/Jujuy America/Argentina/La_Rioja America/Argentina/Mendoza America/Argentina/Rio_Gallegos + America/Argentina/Salta America/Argentina/San_Juan America/Argentina/San_Luis America/Argentina/Tucuman America/Argentina/Ushuaia America/Aruba America/Asuncion + America/Atikokan America/Atka America/Bahia America/Bahia_Banderas America/Barbados America/Belem America/Belize America/Blanc-Sablon America/Boa_Vista America/Bogota + America/Boise America/Buenos_Aires America/Cambridge_Bay America/Campo_Grande America/Cancun America/Caracas America/Catamarca America/Cayenne America/Cayman + America/Chicago America/Chihuahua America/Coral_Harbour America/Cordoba America/Costa_Rica America/Creston America/Cuiaba America/Curacao America/Danmarkshavn + America/Dawson America/Dawson_Creek America/Denver America/Detroit America/Dominica America/Edmonton America/Eirunepe America/El_Salvador America/Ensenada + America/Fort_Nelson America/Fort_Wayne America/Fortaleza America/Glace_Bay America/Godthab America/Goose_Bay America/Grand_Turk America/Grenada America/Guadeloupe + America/Guatemala America/Guayaquil America/Guyana America/Halifax America/Havana America/Hermosillo America/Indiana/Indianapolis America/Indiana/Knox + America/Indiana/Marengo America/Indiana/Petersburg America/Indiana/Tell_City America/Indiana/Vevay America/Indiana/Vincennes America/Indiana/Winamac + America/Inuvik America/Iqaluit America/Jamaica America/Jujuy America/Juneau America/Kentucky/Louisville America/Kentucky/Monticello America/Knox_IN America/Kralendijk + America/La_Paz America/Lima America/Los_Angeles America/Louisville America/Lower_Princes America/Maceio America/Managua America/Manaus America/Marigot + America/Matamoros America/Mazatlan America/Mendoza America/Menominee America/Merida America/Metlakatla America/Mexico_City America/Miquelon America/Moncton + America/Monterrey America/Montevideo America/Montreal America/Montserrat America/Nassau America/New_York America/Nipigon America/Nome America/Noronha + America/North_Dakota/Beulah America/North_Dakota/Center America/North_Dakota/New_Salem America/Ojinaga America/Panama America/Pangnirtung America/Paramaribo + America/Phoenix America/Port_of_Spain America/Port-au-Prince America/Porto_Acre America/Porto_Velho America/Puerto_Rico America/Punta_Arenas America/Rainy_River + America/Rankin_Inlet America/Recife America/Regina America/Resolute America/Rio_Branco America/Rosario America/Santa_Isabel America/Santarem America/Santiago + America/Santo_Domingo America/Sao_Paulo America/Scoresbysund America/Shiprock America/Sitka America/St_Barthelemy America/St_Johns America/St_Kitts America/St_Lucia + America/St_Thomas America/St_Vincent America/Swift_Current America/Tegucigalpa America/Thule America/Thunder_Bay America/Tijuana America/Toronto America/Tortola + America/Vancouver America/Virgin America/Whitehorse America/Winnipeg America/Yakutat America/Yellowknife Antarctica/Casey Antarctica/Davis Antarctica/DumontDUrville + Antarctica/Macquarie Antarctica/Mawson Antarctica/McMurdo Antarctica/Palmer Antarctica/Rothera Antarctica/South_Pole Antarctica/Syowa Antarctica/Troll Antarctica/Vostok + Arctic/Longyearbyen Asia/Aden Asia/Almaty Asia/Amman Asia/Anadyr Asia/Aqtau Asia/Aqtobe Asia/Ashgabat Asia/Ashkhabad Asia/Atyrau Asia/Baghdad Asia/Bahrain Asia/Baku + Asia/Bangkok Asia/Barnaul Asia/Beirut Asia/Bishkek Asia/Brunei Asia/Calcutta Asia/Chita Asia/Choibalsan Asia/Chongqing Asia/Chungking Asia/Colombo Asia/Dacca + Asia/Damascus Asia/Dhaka Asia/Dili Asia/Dubai Asia/Dushanbe Asia/Famagusta Asia/Gaza Asia/Harbin Asia/Hebron Asia/Ho_Chi_Minh Asia/Hong_Kong Asia/Hovd Asia/Irkutsk + Asia/Istanbul Asia/Jakarta Asia/Jayapura Asia/Jerusalem Asia/Kabul Asia/Kamchatka Asia/Karachi Asia/Kashgar Asia/Kathmandu Asia/Katmandu Asia/Khandyga Asia/Kolkatain + Asia/Krasnoyarsk Asia/Kuala_Lumpur Asia/Kuching Asia/Kuwait Asia/Macao Asia/Macau Asia/Magadan Asia/Makassar Asia/Manila Asia/Muscat Asia/Nicosia Asia/Novokuznetsk + Asia/Novosibirsk Asia/Omsk Asia/Oral Asia/Phnom_Penh Asia/Pontianak Asia/Pyongyang Asia/Qatar Asia/Qyzylorda Asia/Rangoon Asia/Riyadh Asia/Saigon Asia/Sakhalin + Asia/Samarkand Asia/Seoul Asia/Shanghai Asia/Singapore Asia/Srednekolymsk Asia/Taipei Asia/Tashkent Asia/Tbilisi Asia/Tehran Asia/Tel_Aviv Asia/Thimbu Asia/Thimphu + Asia/Tokyo Asia/Tomsk Asia/Ujung_Pandang Asia/Ulaanbaatar Asia/Urumqi Asia/Ust-Nera Asia/Vientiane Asia/Vladivostok Asia/Yakutsk Asia/Yangon Asia/Yekaterinburg + Asia/Yerevan Atlantic/Azores Atlantic/Bermuda Atlantic/Canary Atlantic/Cape_Verde Atlantic/Faeroe Atlantic/Faroe Atlantic/Jan_Mayen Atlantic/Madeira Atlantic/Reykjavik + Atlantic/South_Georgia Atlantic/St_Helena Atlantic/Stanley Australia/ACT Australia/Adelaide Australia/Brisbane Australia/Broken_Hill Australia/Canberra Australia/Currie + Australia/Darwin Australia/Eucla Australia/Hobart Australia/LHI Australia/Lindeman Australia/Lord_Howe Australia/Melbourne Australia/North Australia/NSW Australia/Perth + Australia/Queensland Australia/South Australia/Sydney Australia/Tasmania Australia/Victoria Australia/West Australia/Yancowinna Brazil/Acre Brazil/DeNoronha Brazil/East + Brazil/West Canada/Atlantic Canada/Central Canada/Eastern Canada/Mountain Canada/Newfoundland Canada/Pacific Canada/Saskatchewan Canada/Yukon CET Chile/Continental + Chile/EasterIsland CST6CDT Cuba EET Egypt Eire EST EST5EDT Etc/GMT Etc/GMT-0 Etc/GMT-1 Etc/GMT-2 Etc/GMT-3 Etc/GMT-4 Etc/GMT-5 Etc/GMT-6 Etc/GMT-7 Etc/GMT-8 Etc/GMT-9 + Etc/GMT-10 Etc/GMT-11 Etc/GMT-12 Etc/GMT-13 Etc/GMT-14 Etc/GMT+0 Etc/GMT+1 Etc/GMT+2 Etc/GMT+3 Etc/GMT+4 Etc/GMT+5 Etc/GMT+6 Etc/GMT+7 Etc/GMT+8 Etc/GMT+9 Etc/GMT+10 + Etc/GMT+11 Etc/GMT+12 Etc/GMT0 Etc/Greenwich Etc/UCT Etc/Universal Etc/UTC Etc/Zulu Europe/Amsterdam Europe/Andorra Europe/Astrakhan Europe/Athens Europe/Belfast + Europe/Belgrade Europe/Berlin Europe/Bratislava Europe/Brussels Europe/Bucharest Europe/Budapest Europe/Busingen Europe/Chisinau Europe/Copenhagen Europe/Dublin + Europe/Gibraltar Europe/Guernsey Europe/Helsinki Europe/Isle_of_Man Europe/Istanbul Europe/Jersey Europe/Kaliningrad Europe/Kiev Europe/Kirov Europe/Lisbon + Europe/Ljubljana Europe/London Europe/Luxembourg Europe/Madrid Europe/Malta Europe/Mariehamn Europe/Minsk Europe/Monaco Europe/Moscow Europe/Oslo Europe/Paris + Europe/Podgorica Europe/Prague Europe/Riga Europe/Rome Europe/Samara Europe/San_Marino Europe/Sarajevo Europe/Saratov Europe/Simferopol Europe/Skopje Europe/Sofia + Europe/Stockholm Europe/Tallinn Europe/Tirane Europe/Tiraspol Europe/Ulyanovsk Europe/Uzhgorod Europe/Vaduz Europe/Vatican Europe/Vienna Europe/Vilnius Europe/Volgograd + Europe/Warsaw Europe/Zagreb Europe/Zaporozhye Europe/Zurich GB GB-Eire GMT GMT-0 GMT+0 GMT0 Greenwich Hongkong HST Iceland Indian/Antananarivo Indian/Chagos + Indian/Christmas Indian/Cocos Indian/Comoro Indian/Kerguelen Indian/Mahe Indian/Maldives Indian/Mauritius Indian/Mayotte Indian/Reunion Iran Israel Jamaica Japan + Libya MET Mexico/BajaNorte Mexico/BajaSur Mexico/General MST MST7MDT Navajo NZ NZ-CHAT Pacific/Apia Pacific/Auckland Pacific/Bougainville Pacific/Chatham Pacific/Chuuk + Pacific/Easter Pacific/Efate Pacific/Enderbury Pacific/Fakaofo Pacific/Fiji Pacific/Funafuti Pacific/Galapagos Pacific/Gambier Pacific/Guadalcanal Pacific/Guam + Pacific/Honolulu Pacific/Kiritimati Pacific/Kosrae Pacific/Kwajalein Pacific/Majuro Pacific/Marquesas Pacific/Midway Pacific/Nauru Pacific/Niue Pacific/Norfolk + Pacific/Noumea Pacific/Pago_Pago Pacific/Palau Pacific/Pitcairn Pacific/Pohnpei Pacific/Ponape Pacific/Port_Moresby Pacific/Rarotonga Pacific/Saipan Pacific/Samoa + Pacific/Tahiti Pacific/Tarawa Pacific/Tongatapu Pacific/Truk Pacific/Wake Pacific/Wallis Pacific/Yap Poland Portugal PRC PST8PDT ROC ROK Singapore Turkey UCT Universal + US/Alaska US/Aleutian US/Arizona US/Central US/East-Indiana US/Eastern US/Hawaii US/Indiana-Starke US/Michigan US/Mountain US/Pacific US/Pacific-New US/Samoa UTC + Africa/Libreville America/Indianapolis America/Martinique Kwajalein W-SU WET Zulu]&.map { |zone| [zone, zone] } end, - output_fields: lambda do |object_definitions| - object_definitions['get_output_schema'] - end, - sample_output: lambda do |_connection, input| - call(:get_sample_output, input['object'], input['project_uid'] || "") - end - }, - new_updated_object: { - title: 'New or updated object in PlanGrid', - description: lambda do |_, objects| - "New or updated #{objects['object']&.downcase || 'object'} in PlanGrid" + field_report_export_file_type: lambda do |_connection| + [ + ['PDF', 'pdf'], + ['XLSX', 'xlsx'] + ] end, - help: "Triggers when an object is created or updated", - - config_fields: [ - { - name: 'object', - optional: false, - label: 'Object', - control_type: 'select', - pick_list: 'object_list_new', - hint: 'Select the object from picklist.' - } - ], - input_fields: lambda do |object_definitions| - object_definitions['trigger_input'].concat( - [ - { - name: 'since', - label: 'When first started, this recipe should pick up events from', - hint: 'When you start recipe for the first time, ' \ - 'it picks up trigger events from this specified date and time. ' \ - 'Leave empty to get records created or updated one hour ago', - sticky: true, - type: 'timestamp' - } - ] - ) - end, - poll: lambda do |_connection, input, closure| - updated_after = closure&.[]('updated_after') || - (input['since'] || 1.hour.ago).to_time.utc.iso8601 - limit = 10 - skip = closure&.[]('skip') || 0 - update_time = Time.now.utc.iso8601 - response = if (next_page_url = closure&.[]('next_page_url')).present? - get(next_page_url) - elsif input['object'] == 'project' - get("/projects").params(limit: limit, skip: skip, updated_after: updated_after) - elsif input['object'] == 'issue' - get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). - params(limit: limit, skip: skip, updated_after: updated_after, include_annotationless: true) - elsif input['object'] == 'field_report' - get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). - params(limit: limit, skip: skip, updated_after: updated_after) - elsif input['object'] == 'attachment' - get("/projects/#{input['project_uid']}/documents"). - params(limit: limit, skip: skip, updated_after: updated_after) - else - get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). - params(limit: limit, skip: skip, updated_after: updated_after) - end - object_update_time = ['annotation', 'sheet', 'attachment'].include? input['object'] - closure = if (next_page_url = response['next_page_url']).present? - { 'skip' => skip + limit, - 'next_page_url' => next_page_url } - else - { 'skip' => 0, - 'updated_after' => object_update_time ? update_time : response['data']&.last&.[]('updated_at') } - end - project_hash = { 'project_uid' => input['project_uid'] } - project_hash["updated_after"] = (closure["updated_after"] || updated_after) if ['annotation', 'sheet', 'attachment'].include? input['object'] - objects = if input['object'] == 'field_report' - response['data']&.map do |field_report| - field_report.merge('pdf_form_fields' => field_report['pdf_form_values']&.map { |a| { a['name'] => a['value'] } }&.inject(:merge), - 'project_uid' => input['project_uid']) - end - elsif input['object'] == 'attachment' - response['data'].select { |o| o['type'] == 'file' }&.map do |document| - get("/projects/#{input['project_uid']}/attachments/#{document['uid']}") - end&.map { |o| o.merge('project_uid' => input['project_uid']) } - else - response['data']&.map { |o| o.merge('project_uid' => input['project_uid']) } - end - { - events: objects || [], - next_poll: closure, - can_poll_more: response['next_page_url'].present? - } - end, - dedup: lambda do |object| - "#{object['uid']}@#{(object['updated_after'] || object['updated_at'])}" - end, - output_fields: lambda do |object_definitions| - object_definitions['get_output_schema'] - end, - sample_output: lambda do |_connection, input| - call(:get_sample_output, input['object'], input['project_uid'] || "") - end - }, - }, - - methods: { - get_sample_output: lambda do |object, project_uid| - case object - when 'project' - get('/projects')&.dig('data', 0) - when 'field_report' - results = get("/projects/#{project_uid}/field_reports").dig('data', 0)&.merge('project_uid' => project_uid) - when 'rfi_status' - get("/projects/#{project_uid}/rfis/statuses")&.dig('data', 0)&.merge('project_uid' => project_uid) - when 'user_invite' - get("/projects/#{project_uid}/users")&.dig('data', 0)&.merge('project_uid' => project_uid) - when 'sheet_packet' - { - "data" => [ - { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - file_url: "https://packet-assets.plangrid.com/92cf7193-af0c-42fc-a3ab-7ef5149da720.pdf", - resource: { - uid: "92cf7193-af0c-42fc-a3ab-7ef5149da720", - url: "https://io.plangrid.com/projects/da48fcc3-7af1-4fd6-a083-70195468718a/sheets/" \ - "packets/92cf7193-af0c-42fc-a3ab-7ef5149da720" - }, - status: "incomplete" - } - ] - } - when 'sheet_upload' - { - "data" => [ - { - uid: "d050ed4d-425b-4cd2-a46a-1113be6ed37c", - complete_url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/d050ed4d-425b-4cd2-a46a-1113be6ed37c/completions", - status: "incomplete", - file_upload_requests: [ - { - uid: "cba96343-bfaf-4f95-805a-dd49169944c0", - upload_status: "issued", - url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/d050ed4d-425b-4cd2-a46a-1113be6ed37c/files/cba96343-bfaf-4f95-805a-dd49169944c0" - } - ] - } - ] - } - when 'version_upload' - { - "data" => [ - { - uid: "f23f1677-cb77-425f-bdd5-626a9fba8e83", - complete_url: "https://io.plangrid.com/projects/5a77d1aa-44ef-4d0f-904a-839015d82dbb/sheets/uploads/f23f1677-cb77-425f-bdd5-626a9fba8e83/completions", - status: "complete" - } - ] - } - when 'submittals/items' - get("/projects/#{project_uid}/submittals/items")&.dig('data', 0)&.merge('project_uid' => project_uid) - else - get("/projects/#{project_uid}/#{object.pluralize}")&.dig('data', 0)&.merge('project_uid' => project_uid) - end - end, - - get_upload_object: lambda do |file_upload_info, input| - headers = file_upload_info&.dig('aws_post_form_arguments', 'fields')&. - each_with_object({}) do |obj, hash| - hash[obj['name']] = obj['value'] - end - post(file_upload_info&.dig('aws_post_form_arguments', 'action')). - payload(key: headers['key'], - policy: headers['policy'], - signature: headers['signature'], - AWSAccessKeyId: headers['AWSAccessKeyId'], - 'content-type': headers['Content-Type'], - 'success_action_redirect': headers['success_action_redirect'], - 'x-amz-server-side-encryption': - headers['x-amz-server-side-encryption'], - 'x-amz-storage-class': headers['x-amz-storage-class'], - file: input['file_content']). - request_format_multipart_form. - after_error_response(/.*/) do |_code, body, _header, message| - error("#{message}: #{body}") - end - end, - - make_schema_builder_fields_sticky: lambda do |input| - input.map do |field| - if field[:properties].present? - field[:properties] = call("make_schema_builder_fields_sticky", - field[:properties]) - elsif field["properties"].present? - field["properties"] = call("make_schema_builder_fields_sticky", - field["properties"]) - end - field[:sticky] = true - field + role_type: lambda do |_connection| + %w[manager submitter reviewer]&.map { |el| [el.labelize, el] } end - end - }, - - pick_lists: { - create_object_list: lambda do |_connection| - [ - ['Project', 'project'], - ['Field Report Export', 'field_reports/export'], - ['Invite User', 'user_invite'], - ['RFI', 'rfi'], - ['Task List', 'issue_list'], - ['Task', 'issue'], - ['Sheet Packet', 'sheet_packet'], - ['Sheet Version', 'sheet_upload'], - ['Submittal Item', 'submittals/item'], - ['Submittal Package', 'submittals/package'] - ] - end, - - update_object_list: lambda do |_connection| - [ - ['Project', 'project'], - ['Photo', 'photo'], - ['RFI', 'rfi'], - ['Task List', 'issue_list'], - ['Task', 'issue'], - ['Submittal Package', 'submittals/package'], - ['Submittal Item', 'submittals/item'] - ] - end, - - upload_object_list: lambda do |_connection| - [ - ['Document', 'attachment'], - ['Photo', 'photo'], - ['File to Sheet Version', 'file_upload'], - ['Complete Sheet Version', 'version_upload'] - ] - end, - - get_objects: lambda do |_connection| - [ - ['Project', 'project'], - ['Document', 'attachment'], - ['Field Report Export', 'field_reports/export'], - ['Photo', 'photo'], - ['RFI', 'rfi'], - ['Sheet', 'sheet'], - ['Sheet Packet', 'sheet_packet'], - ['Snapshot', 'snapshot'], - ['Submittal Package', 'submittals/package'], - ['Submittal Item', 'submittals/item'], - ['Submittal Package File Group', 'submittals_file_group'], - ['Submittal Package Review Status', 'submittals_review_status'], - ['Task', 'issue'], - ['Task List', 'issue_list'], - ['User', 'user'] - ] - end, - - search_objects: lambda do |_connection| - [ - ['Field Report', 'field_report'], - ['Field Report Template', 'field_report_template'], - ['RFI Status', 'rfi_status'], - ['Role', 'role'] - ] - end, - - download_object_list: lambda do |_connection| - [ - ['Document', 'attachment'], - ['Field Report Export', 'field_reports/export'], - ['Sheet Packet', 'sheets/packet'] - ] - end, - - object_list: lambda do |_connection| - [ - ['Project', 'project'], - ['Annotation', 'annotation'], - ['Document', 'attachment'], - ['Field Report', 'field_report'], - ['Photo', 'photo'], - ['RFI', 'rfi'], - ['Sheet', 'sheet'], - ['Snapshot', 'snapshot'], - ['Task', 'issue'] - ] - end, - - object_list_new: lambda do |_connection| - [ - ['Project', 'project'], - ['Annotation', 'annotation'], - ['Document', 'attachment'], - ['Field Report', 'field_report'], - ['Field Report Template', 'field_report_template'], - ['RFI', 'rfi'], - ['Sheet', 'sheet'], - ['Submittal Package', 'submittals/package'], - ['Submittal Item', 'submittals/item'], - ['Task', 'issue'] - ] - end, - - project_list: lambda do |_connection| - get('/projects')&.[]('data')&.pluck('name', 'uid') - end, - - project_types: lambda do |_connection| - ['general', 'manufacturing', 'power', 'water-sewer-waste', - 'industrial-petroleum', 'transportation', 'hazardous-waste', - 'telecom', 'education-k-12', 'education-higher', 'gov-federal', - 'gov-state-local', 'other'].map { |type| [type.labelize, type] } - end, - - download_object_list: lambda do |_connection| - [ - ['Document', 'attachment'], - ['Field Report Export', 'field_reports/export'], - ['Sheet Packet', 'sheets/packet'] - ] - end, - - project_folders: lambda do |_connection, project_uid:| - if project_uid.length == 36 - folders = get("/projects/#{project_uid}/attachments")['data']&. - pluck('folder')&.uniq - folders.size > 0 ? folders&.map { |folder| [folder || 'Root', folder || ''] } : [['Root', '']] - end - end, - - field_report_export_file_type: lambda do |_connection| - [ - [ 'PDF', 'pdf' ], - [ 'XLSL', 'xlsx' ] - ] - end, - - timezones: lambda do |_connection| - [ - ['America/Los_Angeles','America/Los_Angeles'], - ['America/Denver','America/Denver'], - ['America/Phoenix','America/Phoenix'], - ['America/Chicago','America/Chicago'], - ['America/Mexico_City','America/Mexico_City'], - ['America/New_York','America/New_York'] - ] - end - } -} + } + } \ No newline at end of file From c99f7d77c26d734ef2da5431396db2b761f1eeef Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:02:16 -0400 Subject: [PATCH 80/96] add configuration for client id and secret --- custom_connectors/oauth2/plangrid.rb | 76 +++++++++++++++++++--------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 0a4de31b..a9cd46e7 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1,32 +1,58 @@ { - title: 'PlanGrid', - - connection: { - authorization: { - type: 'oauth2', - - authorization_url: lambda do - "https://io.plangrid.com/oauth/authorize?response_type=code&scope=write:projects%20read:profile" - end, - - token_url: lambda do - "https://io.plangrid.com/oauth/token" - end, - - refresh_on: [401, 403], - - apply: lambda do |_connection, access_token| - if current_url.include?('https://io.plangrid.com') - headers(Authorization: "Bearer #{access_token}", - Accept: 'application/vnd.plangrid+json; version=1') - end - end + title: 'PlanGrid', + connection: { + fields: [ + { + name: 'client_id', + label: 'Client ID', + optional: false, + hint: 'To create client id, you need to register an application' \ + ' under Admin Console => Project => Oauth => Create Oauth app' }, - - base_uri: lambda do |_connection| - 'https://io.plangrid.com' + { + name: 'client_secret', + label: 'Client secret', + control_type: 'password', + optional: false, + hint: 'To create client id, you need to register an application' \ + ' under Admin Console => Project => Oauth => Create Oauth app' + } + ], + authorization: { + type: 'oauth2', + authorization_url: lambda do |connection| + 'https://io.plangrid.com/oauth/authorize?response_type=' \ + "code&client_id=#{connection['client_id']}&" \ + 'scope=write:projects%20read:profile' + end, + acquire: lambda do |connection, auth_code, redirect_uri| + response = post('https://io.plangrid.com/oauth/token'). + payload(client_id: connection['client_id'], + client_secret: connection['client_secret'], + grant_type: 'authorization_code', + code: auth_code, + redirect_uri: redirect_uri). + request_format_www_form_urlencoded + [response, nil, nil] + end, + refresh_on: [401, 403], + refresh: lambda do |_connection, refresh_token| + post('https://io.plangrid.com/oauth/token'). + payload(grant_type: 'refresh_token', + refresh_token: refresh_token). + request_format_www_form_urlencoded + end, + apply: lambda do |_connection, access_token| + if current_url.include?('https://io.plangrid.com') + headers(Authorization: "Bearer #{access_token}", + Accept: 'application/vnd.plangrid+json; version=1') + end end }, + base_uri: lambda do |_connection| + 'https://io.plangrid.com' + end + }, test: ->(_connection) { get('/me') }, From df4bf5a7ca7bf5485708aa6548464a901451d1d6 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:17:30 -0400 Subject: [PATCH 81/96] update get_input_schema to include advanced_rfi, advanced_rfi_search, advanced_rfi_status --- custom_connectors/oauth2/plangrid.rb | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index a9cd46e7..134e7cbf 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -60,7 +60,7 @@ get_input_schema: { fields: lambda do |_connection, config_fields| case config_fields['object'] - when 'rfi_status' + when 'rfi_status', 'advanced_rfi_status' [ { name: 'limit', type: 'integer', control_type: 'integer', hint: 'Number of RFI statuses to retrieve. Maximum value of 50.' }, @@ -138,6 +138,22 @@ { name: 'created_after', type: 'date_time', hint: 'Only return file groups created after the specified date.' } ] + when 'advanced_rfi' + [ + { name: 'uid', label: 'Advanced RFI ID', optional: false, + hint: 'ID can be found at the end of the url.' } + ] + when 'advanced_rfi_search' + [ + { name: 'status_uids', type: 'text', + hint: 'Comma separated string of status UIDs by which to filter the response.' }, + { name: 'updated_after', label: 'Updated After', type: 'date_time', + hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, + { name: 'skip', type: 'integer', + hint: 'Number of records to skip.' }, + { name: 'limit', type: 'integer', + hint: 'Number of records to retrieve.' } + ] else [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false, hint: 'ID can be found at the end of the url.' }] From 4c5663ce9b629ee7e5e277c8939d52856f1ace39 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:26:06 -0400 Subject: [PATCH 82/96] update get_output_schema to include advanced_rfi_status, advanced_rfi, advanced_rfi_search --- custom_connectors/oauth2/plangrid.rb | 107 ++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 134e7cbf..666a9e5a 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -695,6 +695,13 @@ { name: 'color' }, { name: "project_uid", label: "Project ID" } ] + when 'advanced_rfi_status' + [ + { name: 'uid', label: 'RFI status ID' }, + { name: 'label' }, + { name: 'bucket' }, + { name: "project_uid", label: "Project ID" } + ] when 'user', 'user_invite' [ { name: 'uid', label: 'User ID' }, @@ -1097,8 +1104,106 @@ { name: 'total_count', type: 'integer', control_type: 'integer' }, { name: 'next_page_url' } ] + when 'advanced_rfi', 'advanced_rfi_search' + [ + { label: "Answer due date", name: "answer_due_date", type: "date" }, + { label: "Answered at", name: "answered_at", type: "date_time" }, + { label: "Answered directly at", name: "answered_directly_at", type: "date_time" }, + { label: "Answered directly by", name: "answered_directly_by" }, + { + name: "ball_in_court", + type: "array", + of: "object", + label: "Ball in court", + properties: [ + { label: "Type", name: "type" }, + { label: "Uid", name: "uid" }, + { label: "URL", name: "url" } + ] + }, + { label: "Created at", type: "date_time", name: "created_at" }, + { + label: "Created by", + type: "object", + name: "created_by", + properties: [ + { + label: "Type", + name: "type" + }, + { + label: "Uid", + name: "uid" + }, + { + label: "URL", + name: "url" + } + ], + }, + { label: "Directions", name: "directions" }, + { label: "Distributed at", name: "distributed_at", type: "date_time" }, + { label: "Distributed by", name: "distributed_by" }, + { label: "Is returned", type: "boolean", name: "is_returned" }, + { + name: "managers", + type: "array", + of: "object", + label: "Managers", + properties: [ + { label: "Type", name: "type" }, + { label: "Uid", name: "uid" }, + { label: "URL", name: "url" } + ] + }, + { label: "Number", type: "number", name: "number" }, + { label: "Project uid", name: "project_uid" }, + { label: "Question", name: "question" }, + { label: "Revision", type: "number", name: "revision" }, + { label: "Sent for review at", name: "sent_for_review_at", type: "date_time" }, + { label: "Sent for review by", name: "sent_for_review_by" }, + { + label: "Status", + type: "object", + name: "status", + properties: [ + { label: "Bucket", name: "bucket" }, + { label: "Label", name: "label" }, + { label: "Uid", name: "uid" } + ], + }, + { label: "Status uid", name: "status_uid" }, + { label: "Sub number", name: "sub_number" }, + { label: "Submitted at", type: "date_time", name: "submitted_at" }, + { + label: "Submitter", + type: "object", + name: "submitter", + properties: [ + { label: "Type", name: "type" }, + { label: "Uid", name: "uid" }, + { label: "URL", name: "url" } + ], + }, + { label: "Title", name: "title" }, + { label: "Uid", name: "uid" }, + { label: "Updated at", type: "date_time", name: "updated_at" }, + { + label: "Updated by", + type: "object", + name: "updated_by", + properties: [ + { label: "Type", name: "type" }, + { label: "Uid", name: "uid" }, + { label: "URL", name: "url" } + ], + }, + { label: "User created at", type: "date_time", name: "user_created_at" }, + { label: "Voided at", name: "voided_at" }, + { label: "Voided by", name: "voided_by" } + ] + end end - end }, create_input_schema: { From 560e0414f4ac03c3feb54cab429ee5e27d046215 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:27:47 -0400 Subject: [PATCH 83/96] update create_input_schema to include advanced_rfi --- custom_connectors/oauth2/plangrid.rb | 59 ++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 666a9e5a..cc8b9942 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1531,6 +1531,65 @@ hint: 'Select the file type of the export', } ] + when 'advanced_rfi' + [ + { name: 'title', label: 'Title', optional: false, + hint: 'The title of your RFI.' }, + { name: 'status_uid', label: 'Status UID', optional: false, + hint: 'The UID of the Advanced RFI status. This can be obtained from the "Search Objects" action for Advanced RFI statuses. Note that RFIs can only be created in the "Draft" or "Draft with Manager" status types.' }, + { name: 'answer_due_date', label: 'Answer Due Date', optional: true, + hint: 'The due date for the RFI answer, must be in UTC format.' }, + { name: 'question', label: 'Question', optional: true, + hint: 'The question for the RFI.' }, + { name: 'directions', label: 'Directions', optional: true, + hint: 'Instructions to associate with your RFI.' }, + { name: 'managers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of manager.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group.' } + ] + }, + { name: 'reviewers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of reviewer.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group.' } + ] + }, + { name: 'references_added', type: 'array', of: 'object', + hint: 'An array of objects describing the references to associate with this RFI.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, + { name: 'uid', hint: 'ID of the reference to attach.' } + ] + }, + { name: 'number', label: 'Number', optional: true, + hint: 'The number of the RFI. Cannot be the same as any other RFI in the project.' }, + { name: 'revision', label: 'Revision Number', optional: true, + hint: 'The revision number of the RFI.' }, + { name: 'submitter', type: 'object', + hint: 'An object describing the submitter of the RFI.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group.' } + ] + }, + { name: 'watchers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of watcher.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group.' } + ] + }, + { name: 'sub_number', label: 'Sub Number', optional: true, + hint: 'An optional secondary revision number of the RFI.' } + ] else [] end.concat( From 70bb9b6d42e01cfb49f844a700e6d5c9cc944e49 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:28:43 -0400 Subject: [PATCH 84/96] update update_input_schema to include advanced_rfi --- custom_connectors/oauth2/plangrid.rb | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index cc8b9942..33544dd7 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1941,6 +1941,73 @@ { name: 'uid', label: 'Watcher ID', hint: 'ID of either the user or group.' } ] } ] + when 'advanced_rfi' + [ + { name: 'title', label: 'Title', optional: false, + hint: 'The title of your RFI.' }, + { name: 'status_uid', label: 'Status UID', optional: false, + hint: 'The UID of the Advanced RFI status. This can be obtained from the "Search Objects" action for Advanced RFI statuses. Note that RFIs can only be created in the "Draft" or "Draft with Manager" status types.' }, + { name: 'answer_due_date', label: 'Answer Due Date', optional: true, + hint: 'The due date for the RFI answer, must be in UTC format.' }, + { name: 'question', label: 'Question', optional: true, + hint: 'The question for the RFI.' }, + { name: 'directions', label: 'Directions', optional: true, + hint: 'Instructions to associate with your RFI.' }, + { name: 'managers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of manager.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group.' } + ] + }, + { name: 'reviewers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of reviewer.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group.' } + ] + }, + { name: 'references_added', type: 'array', of: 'object', + hint: 'An array of objects describing the references to associate with this RFI.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, + { name: 'uid', hint: 'ID of the reference to attach.' } + ] + }, + { name: 'references_removed', type: 'array', of: 'object', + hint: 'An array of objects describing the references to remove from this RFI.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, + { name: 'uid', hint: 'ID of the reference to remove.' } + ] + }, + { name: 'number', label: 'Number', optional: true, + hint: 'The number of the RFI. Cannot be the same as any other RFI in the project.' }, + { name: 'revision', label: 'Revision Number', optional: true, + hint: 'The revision number of the RFI.' }, + { name: 'submitter', type: 'object', + hint: 'An object describing the submitter of the RFI.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group.' } + ] + }, + { name: 'watchers', type: 'array', of: 'object', + hint: 'An array of objects describing users assigned the role of watcher.', + optional: 'true', + properties: [ + { name: 'type', hint: 'Can be `user` or `group`.' }, + { name: 'uid', hint: 'ID of either the user or group.' } + ] + }, + { name: 'sub_number', label: 'Sub Number', optional: true, + hint: 'An optional secondary revision number of the RFI.' } + ] else [] end.concat( From 14631b1f0cf6fbe454c195ec9e581e4a7e129742 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:42:25 -0400 Subject: [PATCH 85/96] update update_input_schema to include advanced_rfi --- custom_connectors/oauth2/plangrid.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 33544dd7..ef9f4cad 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1943,11 +1943,12 @@ ] when 'advanced_rfi' [ + { name: 'uid', label: 'RFI ID', optional: false }, { name: 'title', label: 'Title', optional: false, hint: 'The title of your RFI.' }, { name: 'status_uid', label: 'Status UID', optional: false, hint: 'The UID of the Advanced RFI status. This can be obtained from the "Search Objects" action for Advanced RFI statuses. Note that RFIs can only be created in the "Draft" or "Draft with Manager" status types.' }, - { name: 'answer_due_date', label: 'Answer Due Date', optional: true, + { name: 'answer_due_date', label: 'Answer Due Date', optional: true, hint: 'The due date for the RFI answer, must be in UTC format.' }, { name: 'question', label: 'Question', optional: true, hint: 'The question for the RFI.' }, From 679dc58ce46d56fd215b8ff70dd426edfaa47b61 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:44:14 -0400 Subject: [PATCH 86/96] remove 'uid' input from advanced_rfi in update_input_schema --- custom_connectors/oauth2/plangrid.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index ef9f4cad..267759fc 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -1943,7 +1943,6 @@ ] when 'advanced_rfi' [ - { name: 'uid', label: 'RFI ID', optional: false }, { name: 'title', label: 'Title', optional: false, hint: 'The title of your RFI.' }, { name: 'status_uid', label: 'Status UID', optional: false, From ed9be3c092e25e6c4cad09044e310bc0bba0612f Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:45:51 -0400 Subject: [PATCH 87/96] update create_object action to include advanced_rfi => /rfis2 endpoint --- custom_connectors/oauth2/plangrid.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 267759fc..0ecaaa97 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2388,6 +2388,11 @@ { "value" => uid } end.inject(:merge) response + when 'advanced_rfi' + post("/projects/#{input['project_uid']}/rfis2").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end when 'field_report_export' post("/projects/#{input['project_uid']}/field_reports/export").payload(payload). after_error_response(/.*/) do |_code, body, _header, message| From c2ab74b6e52499a04f489359331d18c589a80b2d Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:47:01 -0400 Subject: [PATCH 88/96] update update_object action to include advanced_rfi => /rfis2 endpoint --- custom_connectors/oauth2/plangrid.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 0ecaaa97..32cc91a0 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2453,6 +2453,11 @@ after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end + elsif input['object'] == 'advanced_rfi' + patch("/projects/#{input['project_uid']}/rfis2/#{input['uid']}").payload(payload). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end elsif input['object'] == 'submittal_package' || input['object'] == 'submittal_item' response = patch("/projects/#{input['project_uid']}/submittals/#{input['object'].split('_').last.pluralize}/#{input['uid']}").payload(payload.except('uid')). after_error_response(/.*/) do |_code, body, _header, message| From 131245e9fd2ac25be32717f2025abdae612cba8c Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:47:56 -0400 Subject: [PATCH 89/96] update get_object action to include advanced_rfi => /rfis2 endpoint --- custom_connectors/oauth2/plangrid.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 32cc91a0..d680f863 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2553,6 +2553,8 @@ merge('package_uid' => input['uid']) when 'field_report_export' get("/projects/#{input['project_uid']}/field_reports/export/#{input['uid']}") + when 'advanced_rfi' + get("/projects/#{input['project_uid']}/rfis2/#{input['uid']}") else get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") end.merge('project_uid' => input['project_uid']) From ef553a52dba45b07609bcca12910a2a46958d3b2 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:50:04 -0400 Subject: [PATCH 90/96] update search_objects endpoint to include advanced_rfi_status, advanced_rfi_search => /rfis2 endpoint --- custom_connectors/oauth2/plangrid.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index d680f863..0e58536b 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2619,6 +2619,12 @@ case input['object'] when 'rfi_status' { data: get("/projects/#{input['project_uid']}/rfis/statuses", params)['data'] } + when 'advanced_rfi_status' + response = get("/projects/#{input['project_uid']}/rfis2/statuses", params) + { data: response['data'], total_count: response['total_count'], next_page_url: response['next_page_url'] } + when 'advanced_rfi_search' + response = get("/projects/#{input['project_uid']}/rfis2", params) + { data: response['data'], total_count: response['total_count'], next_page_url: response['next_page_url'] } when 'field_report' results = get("/projects/#{input['project_uid']}/#{input['object'].pluralize}", params)['data'] results.map do |field_report| From b56be2b0c522d98ef4f758d7079ffdd0ab4c8e14 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:52:12 -0400 Subject: [PATCH 91/96] update new_object trigger to include advanced_rfi => /rfis2 endpoint --- custom_connectors/oauth2/plangrid.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 0e58536b..d594d1b9 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2845,6 +2845,9 @@ elsif input['object'] == 'field_report' get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). params(limit: limit, skip: skip, updated_after: updated_after) + elsif input['object'] == 'advanced_rfi' + get("/projects/#{input['project_uid']}/rfis2"). + params(limit: limit, skip: skip, updated_after: updated_after) else get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). params(limit: limit, skip: skip, updated_after: updated_after) From 01a801e363776e15f6b3f29566af063270d920a8 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:53:02 -0400 Subject: [PATCH 92/96] update new_updated_object trigger to include advanced_rfi => /rfis2 endpoint --- custom_connectors/oauth2/plangrid.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index d594d1b9..4365ac20 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -2946,6 +2946,9 @@ elsif input['object'] == 'submittal_item' || input['object'] == 'submittal_package' get("/projects/#{input['project_uid']}/submittals/#{input['object'].split('_').last.pluralize}"). params(api_params) + elsif input['object'] == 'advanced_rfi' + get("/projects/#{input['project_uid']}/rfis2"). + params(limit: limit, skip: skip, updated_after: updated_after) else get("/projects/#{input['project_uid']}/#{input['object'].pluralize}"). params(api_params) From 5242f6c1493752fd555cf151854df459058002c3 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:57:35 -0400 Subject: [PATCH 93/96] update methods.get_sample_output to include advanced_rfi_status, advanced_rfi, and advanced_rfi_search --- custom_connectors/oauth2/plangrid.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 4365ac20..28ada329 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -3045,6 +3045,10 @@ results.merge('pdf_form_fields' => results['pdf_form_values']&.map { |a| { a['name'].gsub("-", "_") => a['value'] } }&.inject(:merge)) when 'rfi_status' get("/projects/#{project_uid}/rfis/statuses")&.dig('data', 0)&.merge('project_uid' => project_uid) + when 'advanced_rfi_status' + get("/projects/#{project_uid}/rfis2/statuses")&.dig('data', 0)&.merge('project_uid' => project_uid) + when 'advanced_rfi', 'advanced_rfi_search' + get("/projects/#{project_uid}/rfis2")&.dig('data', 0)&.merge('project_uid' => project_uid) when 'user_invite' get("/projects/#{project_uid}/users")&.dig('data', 0)&.merge('project_uid' => project_uid) when 'sheet_packet' From 3bf156ecdc0c11655cd529dbf8d17247f16f80e5 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 21:59:35 -0400 Subject: [PATCH 94/96] update get_input_schema to include advanced_rfi, advanced_rfi_search --- custom_connectors/oauth2/plangrid.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 28ada329..37697d29 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -139,21 +139,21 @@ hint: 'Only return file groups created after the specified date.' } ] when 'advanced_rfi' - [ - { name: 'uid', label: 'Advanced RFI ID', optional: false, - hint: 'ID can be found at the end of the url.' } - ] + [ + { name: 'uid', label: 'Advanced RFI ID', optional: false, + hint: 'ID can be found at the end of the url.' } + ] when 'advanced_rfi_search' - [ - { name: 'status_uids', type: 'text', - hint: 'Comma separated string of status UIDs by which to filter the response.' }, - { name: 'updated_after', label: 'Updated After', type: 'date_time', - hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, - { name: 'skip', type: 'integer', - hint: 'Number of records to skip.' }, - { name: 'limit', type: 'integer', - hint: 'Number of records to retrieve.' } - ] + [ + { name: 'status_uids', type: 'text', + hint: 'Comma separated string of status UIDs by which to filter the response.' }, + { name: 'updated_after', label: 'Updated After', type: 'date_time', + hint: 'Only retrieve field reports created/updated after specified UTC date and time.' }, + { name: 'skip', type: 'integer', + hint: 'Number of records to skip.' }, + { name: 'limit', type: 'integer', + hint: 'Number of records to retrieve.' } + ] else [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false, hint: 'ID can be found at the end of the url.' }] From 7f934047d4040d56857187cbc481fd420bfc0b11 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Mon, 31 Aug 2020 22:03:40 -0400 Subject: [PATCH 95/96] update pick_lists to include advanced_rfi, advanced_rfi_search, advanced_rfi_status --- custom_connectors/oauth2/plangrid.rb | 95 +++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 16 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 37697d29..2aa8053c 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -3189,14 +3189,32 @@ pick_lists: { create_object_list: lambda do |_connection| - [["Project", "project"], ["Sheet packet", "sheet_packet"], ["Task list", "issue_list"], ["Task", "issue"], ["RFI", "rfi"], - ["Sheet version", "sheet_upload"], ["Invite user", "user_invite"], ['Field report export', 'field_report_export'], - ['Submittal item', 'submittal_item'], ['Submittal package', 'submittal_package']] + [ + ['Project', 'project'], + ['Field Report Export', 'field_reports/export'], + ['Invite User', 'user_invite'], + ['RFI', 'rfi'], + ['Advanced RFI', 'advanced_rfi'], + ['Task List', 'issue_list'], + ['Task', 'issue'], + ['Sheet Packet', 'sheet_packet'], + ['Sheet Version', 'sheet_upload'], + ['Submittal Item', 'submittals/item'], + ['Submittal Package', 'submittals/package'] + ] end, update_object_list: lambda do |_connection| - [["Project", "project"], ["Task List", "issue_list"], ["Task", "issue"], ["RFI", "rfi"], - ["Photo metadata", "photo"], ['Submittal item', 'submittal_item'], ['Submittal package', 'submittal_package']] + [ + ['Project', 'project'], + ['Photo', 'photo'], + ['RFI', 'rfi'], + ['Advanced RFI', 'advanced_rfi'], + ['Task List', 'issue_list'], + ['Task', 'issue'], + ['Submittal Package', 'submittals/package'], + ['Submittal Item', 'submittals/item'] + ] end, upload_object_list: lambda do |_connection| @@ -3205,29 +3223,74 @@ end, get_objects: lambda do |_connection| - [["Project", "project"], ["RFI", "rfi"], ["Task", "issue"], ["User", "user"], ["Snapshot", "snapshot"], ["Sheet", "sheet"], ["Sheet Packet", "sheet_packet"], - ["Photo", "photo"], ["Document", "attachment"], ["Task_list", "issue_list"], ['Field report export', 'field_report_export'], ['Submittal package', 'submittal_package'], - ['Submittal package history', 'submittal_history'], ['Submittal package file group', 'submittal_file_group'], - ['Submittal package review status', 'submittal_review_status']] + [ + ['Project', 'project'], + ['Document', 'attachment'], + ['Field Report Export', 'field_reports/export'], + ['Photo', 'photo'], + ['RFI', 'rfi'], + ['Advanced RFI', 'advanced_rfi'], + ['Sheet', 'sheet'], + ['Sheet Packet', 'sheet_packet'], + ['Snapshot', 'snapshot'], + ['Submittal Package', 'submittals/package'], + ['Submittal Item', 'submittals/item'], + ['Submittal Package File Group', 'submittals_file_group'], + ['Submittal Package Review Status', 'submittals_review_status'], + ['Task', 'issue'], + ['Task List', 'issue_list'], + ['User', 'user'] + ] end, search_objects: lambda do |_connection| - [["RFI status", "rfi_status"], ["Role", "role"], ["Field Report", "field_report"], ['Field report template', 'field_report_template'], - ['Submittal item', 'submittal_item']] + [ + ['Field Report', 'field_report'], + ['Field Report Template', 'field_report_template'], + ['RFI Status', 'rfi_status'], + ['Advanced RFI Status', 'advanced_rfi_status'], + ['Advanced RFI', 'advanced_rfi_search'], + ['Role', 'role'] + ] end, download_object_list: lambda do |_connection| - [['Document', 'attachment'], ['Field report export', 'field_report_export'], ['Sheet packet', 'sheet_packet']] + [ + ['Document', 'attachment'], + ['Field Report Export', 'field_reports/export'], + ['Sheet Packet', 'sheets/packet'] + ] end, object_list: lambda do |_connection| - [["Project", "project"], ["Sheet", "sheet"], ["Document", "attachment"], ["Task", "issue"], ["RFI", "rfi"], - ["Annotation", "annotation"], ["Photo", "photo"], ["Snapshot", "snapshot"], ["Field Report", "field_report"]] + [ + ['Project', 'project'], + ['Annotation', 'annotation'], + ['Document', 'attachment'], + ['Field Report', 'field_report'], + ['Photo', 'photo'], + ['RFI', 'rfi'], + ['Advanced RFI', 'advanced_rfi'], + ['Sheet', 'sheet'], + ['Snapshot', 'snapshot'], + ['Task', 'issue'] + ] end, object_list_new: lambda do |_connection| - [["Project", "project"], ["Task", "issue"], ["RFI", "rfi"], ["Sheet", "sheet"], ["Field Report", "field_report"], ["Document", "attachment"], ["Annotation", "annotation"], - ['Field report template', 'field_report_template'], ['Submittal package', 'submittal_package'], ['Submittal item', 'submittal_item']] + [ + ['Project', 'project'], + ['Annotation', 'annotation'], + ['Document', 'attachment'], + ['Field Report', 'field_report'], + ['Field Report Template', 'field_report_template'], + ['RFI', 'rfi'], + ['Advanced RFI', 'advanced_rfi'], + ['Sheet', 'sheet'], + ['Submittal Package', 'submittals/package'], + ['Submittal Item', 'submittals/item'], + ['Task', 'issue'] + ] end, project_list: lambda do |_connection| From ef47a93f09885b1d42605c6cdc10befada009fc1 Mon Sep 17 00:00:00 2001 From: Sophat Sam Date: Tue, 29 Sep 2020 15:40:40 -0400 Subject: [PATCH 96/96] add "Advanced RFI Answer" to get, create, and update actions --- custom_connectors/oauth2/plangrid.rb | 399 ++++++++++++++++++++------- 1 file changed, 292 insertions(+), 107 deletions(-) diff --git a/custom_connectors/oauth2/plangrid.rb b/custom_connectors/oauth2/plangrid.rb index 2aa8053c..fd3c28b7 100644 --- a/custom_connectors/oauth2/plangrid.rb +++ b/custom_connectors/oauth2/plangrid.rb @@ -61,12 +61,7 @@ fields: lambda do |_connection, config_fields| case config_fields['object'] when 'rfi_status', 'advanced_rfi_status' - [ - { name: 'limit', type: 'integer', control_type: 'integer', - hint: 'Number of RFI statuses to retrieve. Maximum value of 50.' }, - { name: 'skip', type: 'integer', control_type: 'integer', - hint: 'Number of RFI statuses to skip in the set of results.' } - ] + [] when 'field_report' [ { name: 'report_date_min', type: 'date', @@ -154,8 +149,18 @@ { name: 'limit', type: 'integer', hint: 'Number of records to retrieve.' } ] + when 'advanced_rfi_answer' + [ + { name: 'rfi_uid', label: 'RFI UID', type: 'string', optional: false }, + { name: 'updated_after', label: 'Updated After', type: 'date_time', + hint: 'Only retrieve advanced RFI answers created/updated after specified UTC date and time.' }, + { name: 'skip', type: 'integer', + hint: 'Number of records to skip.' }, + { name: 'limit', type: 'integer', + hint: 'Number of records to retrieve.' } + ] else - [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false, + [{ name: 'uid', label: "RFI ID", optional: false, hint: 'ID can be found at the end of the url.' }] end end @@ -693,19 +698,18 @@ { name: 'uid', label: 'RFI status ID' }, { name: 'label' }, { name: 'color' }, - { name: "project_uid", label: "Project ID" } + { name: 'project_uid', label: 'Project ID' } ] when 'advanced_rfi_status' [ { name: 'uid', label: 'RFI status ID' }, { name: 'label' }, - { name: 'bucket' }, - { name: "project_uid", label: "Project ID" } + { name: 'bucket' } ] when 'user', 'user_invite' [ { name: 'uid', label: 'User ID' }, - { name: "project_uid", label: "Project ID" }, + { name: 'project_uid', label: 'Project ID' }, { name: 'email' }, { name: 'first_name', label: 'First Name' }, { name: 'last_name', label: 'Last Name' }, @@ -721,7 +725,7 @@ when 'sheet' [ { name: 'uid', label: 'Sheet ID' }, - { name: "project_uid", label: "Project ID" }, + { name: 'project_uid', label: 'Project ID' }, { name: 'name' }, { name: 'version_name', label: 'Version Name' }, { name: 'description' }, @@ -748,7 +752,7 @@ when 'sheet_packet' [ { name: 'uid', label: 'Sheet Packet ID' }, - { name: "project_uid", label: "Project ID" }, + { name: 'project_uid', label: 'Project ID' }, { name: 'status' }, { name: 'file_url', label: 'File URL' }, { @@ -760,23 +764,23 @@ ] when 'issue_list' [ - { name: "uid", label: "Task List ID" }, - { name: "project_uid", label: "Project ID" }, - { name: "name", label: "Name" }, - { name: "deleted", label: "Deleted", type: "boolean", control_type: 'checkbox' } + { name: 'uid', label: 'Task List ID' }, + { name: 'project_uid', label: 'Project ID' }, + { name: 'name', label: 'Name' }, + { name: 'deleted', label: 'Deleted', type: 'boolean', control_type: 'checkbox' } ] when 'role' [ { name: 'uid', label: 'Role ID' }, { name: 'label', label: 'Role' }, - { name: "project_uid", label: "Project ID" } + { name: 'project_uid', label: 'Project ID' } ] when 'sheet_upload' [ { name: 'uid', label: 'Sheet Version Upload ID' }, { name: 'complete_url', label: 'Upload Completion URL' }, { name: 'status' }, - { name: "project_uid", label: "Project ID" }, + { name: 'project_uid', label: 'Project ID' }, { name: 'file_upload_requests', label: 'File Upload Requests', type: 'array', of: 'object', properties: [ @@ -789,7 +793,7 @@ when 'version_upload' [ { name: 'uid', label: 'Sheet Version ID' }, - { name: "project_uid", label: "Project ID" }, + { name: 'project_uid', label: 'Project ID' }, { name: 'status', label: 'Status' } ] when 'field_report_template' @@ -806,13 +810,13 @@ { name: 'template_type' }, { name: 'status' }, { name: 'group_permissions', label: 'Group permissions', type: 'array', of: 'object', properties: [ - { name: 'permissions', type: 'array', of: 'object', properties: [{ name: "value" }] }, + { name: 'permissions', type: 'array', of: 'object', properties: [{ name: 'value' }] }, { name: 'role_key' }, { name: 'role_name' }, { name: 'role_uid', label: 'Role ID' } ] }, { name: 'user_permissions', label: 'User permissions', type: 'array', of: 'object', properties: [ - { name: 'permissions', type: 'array', of: 'object', properties: [{ name: "value" }] }, + { name: 'permissions', type: 'array', of: 'object', properties: [{ name: 'value' }] }, { name: 'user_id', label: 'User ID' } ] }, { name: 'created_by', type: 'object', properties: [ @@ -849,7 +853,7 @@ { name: 'transmission_status' }, { name: 'is_voided', type: 'boolean' }, { name: 'items', type: 'object', properties: [ - { name: 'uids', label: 'Item IDs', type: 'array', of: 'object', properties: [{ name: "value" }] }, + { name: 'uids', label: 'Item IDs', type: 'array', of: 'object', properties: [{ name: 'value' }] }, { name: 'url' }, { name: 'total_count', type: 'integer', control_type: 'integer' } ] }, @@ -945,7 +949,7 @@ { name: 'general_contractor_review_due_date', type: 'date_time', label: 'Manager due date' }, { name: 'reviewers', type: 'array', of: 'object', properties: [ { name: 'type' }, - { name: 'uid', label: "Reviewer ID" }, + { name: 'uid', label: 'Reviewer ID' }, { name: 'url' } ] }, { name: 'managers', type: 'array', of: 'object', properties: [ @@ -1106,104 +1110,214 @@ ] when 'advanced_rfi', 'advanced_rfi_search' [ - { label: "Answer due date", name: "answer_due_date", type: "date" }, - { label: "Answered at", name: "answered_at", type: "date_time" }, - { label: "Answered directly at", name: "answered_directly_at", type: "date_time" }, - { label: "Answered directly by", name: "answered_directly_by" }, + { label: 'Project ID', name: 'project_uid' }, + { label: 'RFI ID', name: 'uid' }, + { name: 'answer' }, + { label: 'Answer due date', name: 'answer_due_date', type: 'date' }, + { label: 'Answered at', name: 'answered_at', type: 'date_time' }, + { label: 'Answered directly at', name: 'answered_directly_at', type: 'date_time' }, + { label: 'Answered directly by', name: 'answered_directly_by', type: 'object', + properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ] + }, { - name: "ball_in_court", - type: "array", - of: "object", - label: "Ball in court", + name: 'ball_in_court', + type: 'array', + of: 'object', + label: 'Ball in court', properties: [ - { label: "Type", name: "type" }, - { label: "Uid", name: "uid" }, - { label: "URL", name: "url" } + { label: 'Type', name: 'type' }, + { label: 'Uid', name: 'uid' }, + { label: 'URL', name: 'url' } ] }, - { label: "Created at", type: "date_time", name: "created_at" }, + { label: 'Created at', type: 'date_time', name: 'created_at' }, { - label: "Created by", - type: "object", - name: "created_by", + label: 'Created by', + type: 'object', + name: 'created_by', properties: [ { - label: "Type", - name: "type" + label: 'Type', + name: 'type' }, { - label: "Uid", - name: "uid" + label: 'Uid', + name: 'uid' }, { - label: "URL", - name: "url" + label: 'URL', + name: 'url' } ], }, - { label: "Directions", name: "directions" }, - { label: "Distributed at", name: "distributed_at", type: "date_time" }, - { label: "Distributed by", name: "distributed_by" }, - { label: "Is returned", type: "boolean", name: "is_returned" }, + { label: 'Directions', name: 'directions' }, + { label: 'Distributed at', name: 'distributed_at', type: 'date_time' }, + { label: 'Distributed by', name: 'distributed_by', type: 'object', + properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ] + }, + { label: 'Is returned', type: 'boolean', name: 'is_returned' }, { - name: "managers", - type: "array", - of: "object", - label: "Managers", + name: 'managers', + type: 'array', + of: 'object', + label: 'Managers', + properties: [ + { label: 'Type', name: 'type' }, + { label: 'Uid', name: 'uid' }, + { label: 'URL', name: 'url' } + ] + }, + { label: 'Number', type: 'number', name: 'number' }, + { label: 'Question', name: 'question' }, + { name: 'reviewers', type: 'array', of: 'object', + properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ] + }, + { label: 'Revision', type: 'number', name: 'revision' }, + { name: 'references', type: 'array', of: 'object', properties: [ - { label: "Type", name: "type" }, - { label: "Uid", name: "uid" }, - { label: "URL", name: "url" } + { name: 'created_at', type: 'date_time' }, + { name: 'created_by', type: 'object', + properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ] + }, + { name: 'reference_type' }, + { name: 'reference_uid' }, + { name: 'url' } + ] + }, + { label: 'Sent for review at', name: 'sent_for_review_at', type: 'date_time' }, + { label: 'Sent for review by', name: 'sent_for_review_by', type: 'object', + properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } ] }, - { label: "Number", type: "number", name: "number" }, - { label: "Project uid", name: "project_uid" }, - { label: "Question", name: "question" }, - { label: "Revision", type: "number", name: "revision" }, - { label: "Sent for review at", name: "sent_for_review_at", type: "date_time" }, - { label: "Sent for review by", name: "sent_for_review_by" }, { - label: "Status", - type: "object", - name: "status", + label: 'Status', + type: 'object', + name: 'status', properties: [ - { label: "Bucket", name: "bucket" }, - { label: "Label", name: "label" }, - { label: "Uid", name: "uid" } + { label: 'Bucket', name: 'bucket' }, + { label: 'Label', name: 'label' }, + { label: 'Uid', name: 'uid' } ], }, - { label: "Status uid", name: "status_uid" }, - { label: "Sub number", name: "sub_number" }, - { label: "Submitted at", type: "date_time", name: "submitted_at" }, + { label: 'Status ID', name: 'status_uid' }, + { label: 'Sub number', name: 'sub_number' }, + { label: 'Submitted at', type: 'date_time', name: 'submitted_at' }, { - label: "Submitter", - type: "object", - name: "submitter", + label: 'Submitter', + type: 'object', + name: 'submitter', properties: [ - { label: "Type", name: "type" }, - { label: "Uid", name: "uid" }, - { label: "URL", name: "url" } + { label: 'Type', name: 'type' }, + { label: 'Uid', name: 'uid' }, + { label: 'URL', name: 'url' } ], }, - { label: "Title", name: "title" }, - { label: "Uid", name: "uid" }, - { label: "Updated at", type: "date_time", name: "updated_at" }, + { label: 'Title', name: 'title' }, + { label: 'Updated at', type: 'date_time', name: 'updated_at' }, { - label: "Updated by", - type: "object", - name: "updated_by", + label: 'Updated by', + type: 'object', + name: 'updated_by', properties: [ - { label: "Type", name: "type" }, - { label: "Uid", name: "uid" }, - { label: "URL", name: "url" } + { label: 'Type', name: 'type' }, + { label: 'Uid', name: 'uid' }, + { label: 'URL', name: 'url' } ], }, - { label: "User created at", type: "date_time", name: "user_created_at" }, - { label: "Voided at", name: "voided_at" }, - { label: "Voided by", name: "voided_by" } + { label: 'User created at', type: 'date_time', name: 'user_created_at' }, + { label: 'Voided at', name: 'voided_at', type: 'date_time' }, + { label: 'Voided by', name: 'voided_by', type: 'object', + properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ] + }, + { name: 'watchers', type: 'array', of: 'object', + properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ] + } + ] + when 'advanced_rfi_answer' + [ + { label: 'Answer ID', type: 'string', name: 'uid' }, + { label: 'Created at', type: 'date_time', name: 'created_at' }, + { + label: 'Created by', + type: 'object', + name: 'created_by', + properties: [ + { + label: 'Type', + name: 'type' + }, + { + label: 'Uid', + name: 'uid' + }, + { + label: 'URL', + name: 'url' + } + ], + }, + { label: 'Is draft?', type: 'boolean', name: 'is_draft' }, + { label: 'Number of references on create', type: 'number', name: 'num_references_on_create' }, + { name: 'references', type: 'array', of: 'object', + properties: [ + { name: 'created_at', type: 'date_time' }, + { name: 'created_by', type: 'object', + properties: [ + { name: 'type' }, + { name: 'uid' }, + { name: 'url' } + ] + }, + { name: 'reference_type' }, + { name: 'reference_uid' }, + { name: 'url' } + ] + }, + { label: 'RFI ID', type: 'string', name: 'rfi_uid' }, + { label: 'Source', type: 'string', name: 'source' }, + { label: 'Text', type: 'string', name: 'text' }, + { label: 'Updated at', type: 'date_time', name: 'updated_at' }, + { + label: 'Updated by', + type: 'object', + name: 'updated_by', + properties: [ + { label: 'Type', name: 'type' }, + { label: 'Uid', name: 'uid' }, + { label: 'URL', name: 'url' } + ], + }, + { label: 'User created at', type: 'date_time', name: 'user_created_at' }, ] - end end + end }, create_input_schema: { @@ -1537,7 +1651,7 @@ hint: 'The title of your RFI.' }, { name: 'status_uid', label: 'Status UID', optional: false, hint: 'The UID of the Advanced RFI status. This can be obtained from the "Search Objects" action for Advanced RFI statuses. Note that RFIs can only be created in the "Draft" or "Draft with Manager" status types.' }, - { name: 'answer_due_date', label: 'Answer Due Date', optional: true, + { name: 'answer_due_date', label: 'Answer Due Date', type: 'date', optional: true, hint: 'The due date for the RFI answer, must be in UTC format.' }, { name: 'question', label: 'Question', optional: true, hint: 'The question for the RFI.' }, @@ -1545,7 +1659,7 @@ hint: 'Instructions to associate with your RFI.' }, { name: 'managers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of manager.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `user` or `group`.' }, { name: 'uid', hint: 'ID of either the user or group.' } @@ -1553,7 +1667,7 @@ }, { name: 'reviewers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of reviewer.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `user` or `group`.' }, { name: 'uid', hint: 'ID of either the user or group.' } @@ -1561,7 +1675,7 @@ }, { name: 'references_added', type: 'array', of: 'object', hint: 'An array of objects describing the references to associate with this RFI.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, { name: 'uid', hint: 'ID of the reference to attach.' } @@ -1573,7 +1687,7 @@ hint: 'The revision number of the RFI.' }, { name: 'submitter', type: 'object', hint: 'An object describing the submitter of the RFI.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `user` or `group`.' }, { name: 'uid', hint: 'ID of either the user or group.' } @@ -1581,7 +1695,7 @@ }, { name: 'watchers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of watcher.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `user` or `group`.' }, { name: 'uid', hint: 'ID of either the user or group.' } @@ -1590,6 +1704,28 @@ { name: 'sub_number', label: 'Sub Number', optional: true, hint: 'An optional secondary revision number of the RFI.' } ] + when 'advanced_rfi_answer' + [ + { label: 'Advanced RFI ID', type: 'string', name: 'rfi_uid', optional: false }, + { label: 'Is draft', type: 'boolean', name: 'is_draft', optional: true }, + { name: 'references_added', type: 'array', of: 'object', + hint: 'An array of objects describing the references to associate with this RFI.', + optional: true, + properties: [ + { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, + { name: 'uid', hint: 'ID of the reference to attach.' } + ] + }, + { name: 'references_removed', type: 'array', of: 'object', + hint: 'An array of objects describing the references to remove from this RFI.', + optional: true, + properties: [ + { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, + { name: 'uid', hint: 'ID of the reference to remove.' } + ] + }, + { label: 'Text', type: 'string', name: 'text', optional: false } + ] else [] end.concat( @@ -1943,11 +2079,11 @@ ] when 'advanced_rfi' [ - { name: 'title', label: 'Title', optional: false, + { name: 'title', label: 'Title', hint: 'The title of your RFI.' }, - { name: 'status_uid', label: 'Status UID', optional: false, + { name: 'status_uid', label: 'Status UID', hint: 'The UID of the Advanced RFI status. This can be obtained from the "Search Objects" action for Advanced RFI statuses. Note that RFIs can only be created in the "Draft" or "Draft with Manager" status types.' }, - { name: 'answer_due_date', label: 'Answer Due Date', optional: true, + { name: 'answer_due_date', label: 'Answer Due Date', type: 'date', optional: true, hint: 'The due date for the RFI answer, must be in UTC format.' }, { name: 'question', label: 'Question', optional: true, hint: 'The question for the RFI.' }, @@ -1955,7 +2091,7 @@ hint: 'Instructions to associate with your RFI.' }, { name: 'managers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of manager.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `user` or `group`.' }, { name: 'uid', hint: 'ID of either the user or group.' } @@ -1963,7 +2099,7 @@ }, { name: 'reviewers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of reviewer.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `user` or `group`.' }, { name: 'uid', hint: 'ID of either the user or group.' } @@ -1971,7 +2107,7 @@ }, { name: 'references_added', type: 'array', of: 'object', hint: 'An array of objects describing the references to associate with this RFI.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, { name: 'uid', hint: 'ID of the reference to attach.' } @@ -1979,7 +2115,7 @@ }, { name: 'references_removed', type: 'array', of: 'object', hint: 'An array of objects describing the references to remove from this RFI.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, { name: 'uid', hint: 'ID of the reference to remove.' } @@ -1991,7 +2127,7 @@ hint: 'The revision number of the RFI.' }, { name: 'submitter', type: 'object', hint: 'An object describing the submitter of the RFI.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `user` or `group`.' }, { name: 'uid', hint: 'ID of either the user or group.' } @@ -1999,7 +2135,7 @@ }, { name: 'watchers', type: 'array', of: 'object', hint: 'An array of objects describing users assigned the role of watcher.', - optional: 'true', + optional: true, properties: [ { name: 'type', hint: 'Can be `user` or `group`.' }, { name: 'uid', hint: 'ID of either the user or group.' } @@ -2008,6 +2144,28 @@ { name: 'sub_number', label: 'Sub Number', optional: true, hint: 'An optional secondary revision number of the RFI.' } ] + when 'advanced_rfi_answer' + [ + { label: 'Advanced RFI ID', type: 'string', name: 'rfi_uid', optional: false }, + { label: 'Is draft?', type: 'boolean', name: 'is_draft', optional: true }, + { name: 'references_added', type: 'array', of: 'object', + hint: 'An array of objects describing the references to associate with this RFI.', + optional: true, + properties: [ + { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, + { name: 'uid', hint: 'ID of the reference to attach.' } + ] + }, + { name: 'references_removed', type: 'array', of: 'object', + hint: 'An array of objects describing the references to remove from this RFI.', + optional: true, + properties: [ + { name: 'type', hint: 'Can be `document`, `photo`, or `snapshot`.' }, + { name: 'uid', hint: 'ID of the reference to remove.' } + ] + }, + { label: 'Text', type: 'string', name: 'text', optional: false } + ] else [] end.concat( @@ -2032,7 +2190,11 @@ } ] ).concat( - if config_fields['object'] != 'project' + if config_fields['object'] == 'advanced_rfi' + [{ name: 'uid', label: 'Advanced RFI ID', optional: false }] + elsif config_fields['object'] == 'advanced_rfi_answer' + [{ name: 'answer_uid', label: 'Answer ID', optional: false }] + elsif config_fields['object'] != 'project' [{ name: "uid", label: "#{config_fields['object'].labelize} ID", optional: false }] else [] @@ -2393,6 +2555,11 @@ after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end + when 'advanced_rfi_answer' + post("/projects/#{input['project_uid']}/rfis2/#{input['rfi_uid']}/answers").payload(payload.except('rfi_uid')). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end when 'field_report_export' post("/projects/#{input['project_uid']}/field_reports/export").payload(payload). after_error_response(/.*/) do |_code, body, _header, message| @@ -2458,6 +2625,12 @@ after_error_response(/.*/) do |_code, body, _header, message| error("#{message}: #{body}") end + elsif input['object'] == 'advanced_rfi_answer' + patch("/projects/#{input['project_uid']}/rfis2/#{input['rfi_uid']}/answers/#{input['answer_uid']}"). + payload(payload.except('rfi_uid', 'answer_uid')). + after_error_response(/.*/) do |_code, body, _header, message| + error("#{message}: #{body}") + end elsif input['object'] == 'submittal_package' || input['object'] == 'submittal_item' response = patch("/projects/#{input['project_uid']}/submittals/#{input['object'].split('_').last.pluralize}/#{input['uid']}").payload(payload.except('uid')). after_error_response(/.*/) do |_code, body, _header, message| @@ -2555,6 +2728,9 @@ get("/projects/#{input['project_uid']}/field_reports/export/#{input['uid']}") when 'advanced_rfi' get("/projects/#{input['project_uid']}/rfis2/#{input['uid']}") + when 'advanced_rfi_answer' + get("/projects/#{input['project_uid']}/rfis2/#{input['rfi_uid']}/answers") + &.dig('data',0) else get("/projects/#{input['project_uid']}/#{input['object'].pluralize}/#{input['uid']}") end.merge('project_uid' => input['project_uid']) @@ -2655,9 +2831,12 @@ output_fields: lambda do |object_definitions| [ + { name: 'project_uid', label: 'Project ID'}, { name: 'data', type: 'array', of: 'object', properties: object_definitions['get_output_schema'] - } + }, + { name: 'total_count', type: 'number' }, + { name: 'next_page_url' } ] end, @@ -3049,6 +3228,9 @@ get("/projects/#{project_uid}/rfis2/statuses")&.dig('data', 0)&.merge('project_uid' => project_uid) when 'advanced_rfi', 'advanced_rfi_search' get("/projects/#{project_uid}/rfis2")&.dig('data', 0)&.merge('project_uid' => project_uid) + when 'advanced_rfi_answer' + rfi_uid = get("/projects/#{project_uid}/rfis2")&.dig('data', 0).dig('uid') + get("/projects/#{project_uid}/rfis2/#{rfi_uid}/answers")&.dig('data', 0)&.merge('project_uid' => project_uid) when 'user_invite' get("/projects/#{project_uid}/users")&.dig('data', 0)&.merge('project_uid' => project_uid) when 'sheet_packet' @@ -3195,6 +3377,7 @@ ['Invite User', 'user_invite'], ['RFI', 'rfi'], ['Advanced RFI', 'advanced_rfi'], + ['Advanced RFI Answer', 'advanced_rfi_answer'], ['Task List', 'issue_list'], ['Task', 'issue'], ['Sheet Packet', 'sheet_packet'], @@ -3210,6 +3393,7 @@ ['Photo', 'photo'], ['RFI', 'rfi'], ['Advanced RFI', 'advanced_rfi'], + ['Advanced RFI Answer', 'advanced_rfi_answer'], ['Task List', 'issue_list'], ['Task', 'issue'], ['Submittal Package', 'submittals/package'], @@ -3230,6 +3414,7 @@ ['Photo', 'photo'], ['RFI', 'rfi'], ['Advanced RFI', 'advanced_rfi'], + ['Advanced RFI Answer', 'advanced_rfi_answer'], ['Sheet', 'sheet'], ['Sheet Packet', 'sheet_packet'], ['Snapshot', 'snapshot'],