{
  "custom": {
    "api_region_name": "eu",
    "default_file_config": {
      "ETag": "?",
      "LastModified": "?",
      "Size": 0,
      "StorageClass": "?"
    },
    "dummy": [],
    "file_not_found": true,
    "file_options": [],
    "loading": false,
    "selected_file": "",
    "selected_file_config": {
      "ETag": "?",
      "Filename": ".svg",
      "Key": ".svg",
      "LastModified": "?",
      "Size": 0,
      "StorageClass": "?"
    },
    "stage_config": {
      "account_id": "006306898152",
      "api_call_role": "arn:aws:iam::609617486056:role/RMESDScadaS3ManagementAPIcallRole-prod-eu-west-1",
      "endpoint": "https://eu-west-1.scada-s3-management.scada.eurme.amazon.dev/",
      "lambda_name": "RMESDScadaS3ManagementFlaskLambda-prod",
      "region": "eu-west-1",
      "repo_bucket": "ignition-image-repo",
      "s3_region": "eu-west-1",
      "source_bucket": "ignition-image-source"
    }
  },
  "events": {
    "system": {
      "onStartup": {
        "config": {
          "script": "\tself.custom.selected_file \u003d self.params.selected_file"
        },
        "scope": "G",
        "type": "script"
      }
    }
  },
  "params": {
    "bucket": "",
    "enables": {
      "delete": true,
      "download": true,
      "file": true,
      "object_key": false,
      "upload": true
    },
    "files": [],
    "prefix": "",
    "selected_file": "",
    "suffix": ".svg",
    "upload_file_types": [
      "svg"
    ],
    "whid": ""
  },
  "propConfig": {
    "custom.api_region_name": {
      "binding": {
        "config": {
          "path": "session.custom.aws.prefix"
        },
        "type": "property"
      },
      "persistent": true
    },
    "custom.default_file_config": {
      "persistent": true
    },
    "custom.default_file_config.Filename": {
      "binding": {
        "config": {
          "expression": "{view.params.selected_file}+{view.params.suffix}"
        },
        "type": "expr"
      }
    },
    "custom.default_file_config.Key": {
      "binding": {
        "config": {
          "expression": "{view.params.prefix}+{view.params.selected_file}+{view.params.suffix}"
        },
        "type": "expr"
      }
    },
    "custom.dummy": {
      "persistent": true
    },
    "custom.file_not_found": {
      "binding": {
        "config": {
          "expression": "{view.custom.selected_file_config.Size}\u003d0"
        },
        "type": "expr"
      },
      "persistent": true
    },
    "custom.file_options": {
      "binding": {
        "config": {
          "path": "view.params.files"
        },
        "transforms": [
          {
            "code": "\tprefix \u003d self.params.prefix\n\tsuffix \u003d self.params.suffix\n\treturn [{\u0027value\u0027: x.Filename, \n\t\t\u0027label\u0027: x.Filename} \n\t\tfor x in value]",
            "type": "script"
          }
        ],
        "type": "property"
      },
      "persistent": true
    },
    "custom.loading": {
      "persistent": true
    },
    "custom.selected_file": {
      "persistent": true
    },
    "custom.selected_file_config": {
      "binding": {
        "config": {
          "expression": "{view.custom.selected_file}+toStr({view.custom.file_options})"
        },
        "transforms": [
          {
            "code": "\tdef_file_config \u003d self.custom.default_file_config\n\treturn next((x for x in self.params.files if x.Filename \u003d\u003d self.custom.selected_file), def_file_config)",
            "type": "script"
          }
        ],
        "type": "expr"
      },
      "persistent": true
    },
    "custom.stage_config": {
      "binding": {
        "config": {
          "expression": "{view.custom.api_region_name}"
        },
        "transforms": [
          {
            "code": "\treturn AWS.s3.STAGE_CONFIG[\u0027prod\u0027][value]",
            "type": "script"
          }
        ],
        "type": "expr"
      },
      "persistent": true
    },
    "params.bucket": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.enables": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.files": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.prefix": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.selected_file": {
      "onChange": {
        "enabled": null,
        "script": "\tif not missedEvents:\n\t\tselection \u003d self.getChild(\"root\").getChild(\"FlexContainer\").getChild(\"Table\").props.selection\n\t\tif currentValue.value:\n\t\t\tif not currentValue.value.endswith(self.params.suffix):\n\t\t\t\tself.custom.selected_file \u003d currentValue.value + self.params.suffix\n\t\t\telse:\n\t\t\t\tself.custom.selected_file \u003d currentValue.value\n\t\t\t# now select the correct row in table that matches selection\n\t\t\tfilename \u003d self.custom.selected_file\n\t\t\tselected_row, selected_data \u003d None, []\n\t\t\tfor index, row in enumerate(self.params.files):\n\t\t\t\tif row.Filename \u003d\u003d filename:\n\t\t\t\t\tselected_row \u003d index\n\t\t\t\t\tselected_data.append(row)\n\t\t\t\t\tbreak\n\t\t\tselection.data \u003d selected_data\n\t\t\tselection.selectedRow \u003d selected_row\n\t\telse:\n\t\t\t# file is none, clear out file selection\n\t\t\t# I know, why are we setting to -1, then None? it\u0027s an ignition persp table bug\n\t\t\t# as of 8.1.20. It works...\n\t\t\tselection.selectedRow \u003d -1\n\t\t\tselection.selectedColumn \u003d -1\n\t\t\tselection.selectedRow \u003d None\n\t\t\tselection.selectedColumn \u003d None\n\t"
      },
      "paramDirection": "input",
      "persistent": true
    },
    "params.suffix": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.upload_file_types": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.whid": {
      "paramDirection": "input",
      "persistent": true
    }
  },
  "props": {
    "defaultSize": {
      "height": 600,
      "width": 550
    }
  },
  "root": {
    "children": [
      {
        "children": [
          {
            "children": [
              {
                "meta": {
                  "name": "Label"
                },
                "position": {
                  "basis": "125px",
                  "shrink": 0
                },
                "props": {
                  "style": {
                    "classes": "Framework/Card/Label Text/RightAlign_with_Padding",
                    "paddingLeft": "5px"
                  },
                  "text": "Select File:"
                },
                "type": "ia.display.label"
              },
              {
                "events": {
                  "component": {
                    "onActionPerformed": {
                      "config": {
                        "script": "\t# when user selects new file, send message to update selected image on parent view\n\tif self.props.value:\n\t\tsuffix \u003d self.view.params.suffix\n\t\tselected_image \u003d self.props.value.replace(suffix, \u0027\u0027)\n\t\tpayload \u003d {\u0027image\u0027: selected_image}\n\t\tsystem.perspective.sendMessage(\u0027update_selected_image\u0027, payload, scope\u003d\u0027session\u0027)\n\t\t"
                      },
                      "scope": "G",
                      "type": "script"
                    }
                  }
                },
                "meta": {
                  "name": "Dropdown",
                  "tooltip": {
                    "location": "bottom",
                    "style": {
                      "whiteSpace": "pre"
                    },
                    "text": "Click here to select a different \nstage folder to manage"
                  }
                },
                "position": {
                  "basis": "175px",
                  "grow": 1,
                  "shrink": 0
                },
                "propConfig": {
                  "props.enabled": {
                    "binding": {
                      "config": {
                        "expression": "{view.params.enables.file}\u0026\u0026try(len({view.params.files})\u003e0,false)"
                      },
                      "type": "expr"
                    }
                  },
                  "props.options": {
                    "binding": {
                      "config": {
                        "path": "view.custom.file_options"
                      },
                      "type": "property"
                    }
                  },
                  "props.value": {
                    "binding": {
                      "config": {
                        "bidirectional": true,
                        "path": "view.custom.selected_file"
                      },
                      "type": "property"
                    }
                  }
                },
                "props": {
                  "style": {
                    "margin": "2px",
                    "marginRight": "5px"
                  }
                },
                "type": "ia.input.dropdown"
              },
              {
                "events": {
                  "component": {
                    "onFileReceived": {
                      "config": {
                        "script": "\tself.upload_file(event\u003devent)\n"
                      },
                      "scope": "G",
                      "type": "script"
                    }
                  }
                },
                "meta": {
                  "name": "FileUpload",
                  "tooltip": {
                    "enabled": true
                  }
                },
                "position": {
                  "basis": "26px",
                  "shrink": 0
                },
                "propConfig": {
                  "meta.tooltip.text": {
                    "binding": {
                      "config": {
                        "expression": "stringFormat(\u0027Upload new version of %s\u0027,{view.custom.selected_file})"
                      },
                      "type": "expr"
                    }
                  },
                  "meta.visible": {
                    "binding": {
                      "config": {
                        "expression": "{view.params.enables.upload}\u0026\u0026!{view.custom.file_not_found}"
                      },
                      "type": "expr"
                    }
                  },
                  "props.supportedFileTypes": {
                    "binding": {
                      "config": {
                        "path": "view.params.upload_file_types"
                      },
                      "type": "property"
                    }
                  }
                },
                "props": {
                  "fileSizeLimit": 20,
                  "fileUploadIcon": {
                    "style": {
                      "borderStyle": "none",
                      "classes": "Input/Button/Secondary_minimal",
                      "margin": "-5px"
                    }
                  },
                  "maxUploads": 1
                },
                "scripts": {
                  "customMethods": [
                    {
                      "name": "update_bindings",
                      "params": [],
                      "script": "\t\"\"\"\n\t\tAfter data saved to S3, refresh session and view bindings\n\t\"\"\"\n\t\n\tself.view.custom.loading \u003d False\n\t# reset file upload component to default state\n\tself.clearUploads()\n\t# send message to update files param on parent view\n\tbucket \u003d self.view.params.bucket\n\tsystem.perspective.sendMessage(\u0027update_file_binding\u0027, {\u0027bucket\u0027: bucket}, scope\u003d\u0027session\u0027)\n\t"
                    },
                    {
                      "name": "show_success_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"success\", \n\t\t\"File Uploaded\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t"
                    },
                    {
                      "name": "show_warning_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"warning\", \n\t\t\"File NOT Uploaded\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t\t"
                    },
                    {
                      "name": "show_error_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"error\", \n\t\t\"File Upload Error!\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t\t\t"
                    },
                    {
                      "name": "upload_file",
                      "params": [
                        "event\u003dNone"
                      ],
                      "script": "\tfrom AWS.s3 import S3Manager\n\tfrom pprint import pformat\n\tsystem.perspective.print(\u0027FileUpload component upload_file custom method reached...\u0027)\n\tself.view.custom.loading \u003d True\n\ttry:\n\t\tapi_stage \u003d \u0027prod\u0027\n\t\tusername \u003d self.session.props.auth.user.userName\n\t\tapi_region_name \u003d self.view.custom.api_region_name\n\t\tbucket \u003d self.view.params.bucket\n\t\tobj_key \u003d self.view.custom.selected_file_config.Key\n\t\tregion \u003d self.view.custom.stage_config.s3_region\n\t\texisting_filename \u003d self.view.custom.selected_file_config.Filename\n\t\tfilename \u003d event.file.name\n\t\t# verify that uploaded file name matches existing file name. Throw error if not.\n\t\tif filename !\u003d existing_filename:\n\t\t\tmsg \u003d \u0027File uploaded does not have the same name as target object key. Please check spelling and that you selected the correct file to upload. Target filename: %s. Received: %s\u0027 % (\n\t\t\t\t\texisting_filename, filename)\n\t\t\tself.show_error_dialog(msg)\n\t\t\tself.view.custom.loading \u003d False\n\t\t\tself.clearUploads()\n\t\t\treturn\n\t\tsystem.perspective.print(\u0027obj_key to upload: %s\u0027 % obj_key)\n\t\tobj_data \u003d event.file.getString()\n\t\tsystem.perspective.print(\u0027obj_data length: %s\u0027 % len(obj_data))\n\n\t\ts3m \u003d S3Manager(api_stage, api_region_name, username)\n\t\ttry:\n\t\t\tresp \u003d s3m.upload(\n\t\t\t\tobj_data\u003dobj_data,\n\t\t\t\tobj_key\u003dobj_key,\n\t\t\t\tbucket\u003dbucket,\n\t\t\t\tregion\u003dregion\n\t\t\t)\n\t\t\tresp_code \u003d resp.get(\u0027code\u0027, None)\n\t\t\tif (resp_code and resp_code !\u003d 200) or (not resp_code and \u0027message\u0027 in resp):\n\t\t\t\t# this means the API encountered an error, annunciate the error here\n\t\t\t\tmsg \u003d \u0027API encountered error uploading %s to %s bucket. \\nResponse: %s\u0027 % (obj_key, bucket, pformat(resp))\n\t\t\t\tsystem.perspective.print(msg)\n\t\t\t\tself.view.custom.loading \u003d False\n\t\t\t\tself.show_error_dialog(msg)\n\t\t\t\tself.clearUploads()\n\t\t\t\treturn\n\t\t\tmsg \u003d \u0027Successfully uploaded %s object in %s bucket!\\nResponse: %s\u0027 % (obj_key, bucket, pformat(resp))\n\t\t\tsystem.perspective.print(msg)\n\t\t\tself.show_success_dialog(msg)\n\t\t\tself.update_bindings()\n\t\texcept:\n\t\t\timport traceback\n\t\t\tmsg \u003d \u0027Error uploading %s object in %s bucket: %s\u0027 % (obj_key, bucket, traceback.format_exc())\n\t\t\tsystem.perspective.print(msg)\n\t\t\tself.view.custom.loading \u003d False\n\t\t\tself.show_error_dialog(msg)\n\t\t\tself.clearUploads()\n\texcept:\n\t\timport traceback\n\t\tmsg \u003d \u0027General Error uploading %s object in %s bucket: %s\u0027 % (obj_key, bucket, traceback.format_exc())\n\t\tsystem.perspective.print(msg)\n\t\tself.view.custom.loading \u003d False\n\t\tself.show_error_dialog(msg)\n\t\tself.clearUploads()\n\t\t"
                    }
                  ],
                  "extensionFunctions": null,
                  "messageHandlers": []
                },
                "type": "ia.input.fileupload"
              },
              {
                "events": {
                  "component": {
                    "onActionPerformed": {
                      "config": {
                        "script": "\tfrom AWS.s3 import S3Manager\n\tfrom pprint import pformat\n\timport json\n\t\n\tapi_stage \u003d \u0027prod\u0027\n\tusername \u003d self.session.props.auth.user.userName\n\tapi_region_name \u003d self.view.custom.api_region_name\n\tbucket \u003d self.view.params.bucket\n\tobj_key \u003d self.view.custom.selected_file_config.Key\n\tregion \u003d self.view.custom.stage_config.s3_region\n\tfilename \u003d self.view.custom.selected_file_config.Filename\n\t\n\ts3m \u003d S3Manager(api_stage, api_region_name, username)\n\tdata \u003d None\n\ttry:\n\t\tresp \u003d s3m.download(bucket\u003dbucket, obj_key\u003dobj_key, region\u003dregion)\n\t\ttry:\n\t\t\tresp_code \u003d resp.get(\u0027code\u0027, None)\n\t\texcept AttributeError:\n\t\t\tresp_code \u003d None\n\t\tif (resp_code and resp_code !\u003d 200) or (not resp_code and \u0027message\u0027 in resp):\n\t\t\t# this means the API encountered an error, annunciate the error here\n\t\t\tmsg \u003d \u0027API encountered error downloading %s on %s bucket. \\nResponse: %s\u0027 % (obj_key, bucket, pformat(sanitize_tree(resp)))\n\t\t\tsystem.perspective.print(msg)\n\t\t\tself.show_error_dialog(msg)\n\t\t\treturn\n\t\tif isinstance(resp, dict) or isinstance(resp, list):\n\t\t\tdata \u003d json.dumps(resp, indent\u003d2)\n\t\telse:\n\t\t\tdata \u003d resp\n\texcept:\n\t\timport traceback\n\t\tmsg \u003d \u0027error downloading %s obj: %s\u0027 % (obj_key, traceback.format_exc())\n\t\tsystem.perspective.print(msg)\n\t\tself.show_error_dialog(msg)\n\tif data:\n\t\tsystem.perspective.download(filename, data)\n\telse:\n\t\tsystem.perspective.print(\u0027no data for %s obj!\u0027 % obj_key)\n\t\tself.show_error_dialog(msg)\n\t"
                      },
                      "scope": "G",
                      "type": "script"
                    }
                  }
                },
                "meta": {
                  "name": "Download Button",
                  "tooltip": {
                    "enabled": true
                  }
                },
                "position": {
                  "basis": "26px",
                  "shrink": 0
                },
                "propConfig": {
                  "meta.tooltip.text": {
                    "binding": {
                      "config": {
                        "expression": "stringFormat(\u0027Download copy of %s\u0027,{view.custom.selected_file})"
                      },
                      "type": "expr"
                    }
                  },
                  "props.enabled": {
                    "binding": {
                      "config": {
                        "expression": "{view.params.enables.download}\u0026\u0026!{view.custom.file_not_found}"
                      },
                      "type": "expr"
                    }
                  }
                },
                "props": {
                  "image": {
                    "icon": {
                      "path": "material/cloud_download"
                    }
                  },
                  "primary": false,
                  "style": {
                    "classes": "Input/Button/Secondary_minimal",
                    "margin": "2px"
                  },
                  "text": ""
                },
                "scripts": {
                  "customMethods": [
                    {
                      "name": "show_error_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"error\", \n\t\t\"File Download Error!\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t\t\t\t"
                    }
                  ],
                  "extensionFunctions": null,
                  "messageHandlers": []
                },
                "type": "ia.input.button"
              },
              {
                "events": {
                  "component": {
                    "onActionPerformed": {
                      "config": {
                        "script": "\tself.show_confirm_dialog()"
                      },
                      "scope": "G",
                      "type": "script"
                    }
                  }
                },
                "meta": {
                  "name": "Delete Button",
                  "tooltip": {
                    "enabled": true
                  }
                },
                "position": {
                  "basis": "26px",
                  "shrink": 0
                },
                "propConfig": {
                  "meta.tooltip.text": {
                    "binding": {
                      "config": {
                        "expression": "stringFormat(\u0027Delete record of %s file from %s bucket\u0027,\r\n\t{view.custom.selected_file},{view.params.bucket})"
                      },
                      "type": "expr"
                    }
                  },
                  "props.enabled": {
                    "binding": {
                      "config": {
                        "expression": "{view.params.enables.delete}\u0026\u0026!{view.custom.file_not_found}"
                      },
                      "type": "expr"
                    }
                  }
                },
                "props": {
                  "image": {
                    "icon": {
                      "path": "material/delete_forever"
                    }
                  },
                  "primary": false,
                  "style": {
                    "classes": "Input/Button/Secondary_minimal",
                    "margin": "2px"
                  },
                  "text": ""
                },
                "scripts": {
                  "customMethods": [
                    {
                      "name": "show_success_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"success\", \n\t\t\"File Deleted\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t\t\t"
                    },
                    {
                      "name": "show_warning_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"warning\", \n\t\t\"File NOT Deleted\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t\t\t"
                    },
                    {
                      "name": "show_error_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"error\", \n\t\t\"File Delete Error!\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t\t\t"
                    },
                    {
                      "name": "show_confirm_dialog",
                      "params": [
                        "payload\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add payload of data to pass to the popup\n\tmsg \u003d (\u0027Are you sure you want to delete %s file from %s S3 bucket? THIS OPERATION CANNOT BE UNDONE!\u0027) % (\n\t\tself.view.custom.selected_file, self.view.params.bucket)\n\tpayload \u003d {\u0027bucket\u0027: self.view.params.bucket}\t\t\n\tAlerts.showAlert(\n\t\t\"info\", \n\t\t\"Delete from S3?\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"Continue\", \n\t\t\"Cancel\", \n\t\t\"delete_forever\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"confirm_delete_file\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\tpayload\n\t)\n\t\t\t"
                    },
                    {
                      "name": "update_bindings",
                      "params": [],
                      "script": "\t\"\"\"\n\t\tAfter deleted from S3, refresh session and view bindings\n\t\"\"\"\n\tself.view.custom.loading \u003d False\n\t# send message to update files param on parent view\n\tbucket \u003d self.view.params.bucket\n\tsystem.perspective.sendMessage(\u0027update_file_binding\u0027, {\u0027bucket\u0027: bucket}, scope\u003d\u0027session\u0027)\n\t"
                    },
                    {
                      "name": "delete_file",
                      "params": [],
                      "script": "\t\"\"\"\n\t\tCall AWS.s3.S3Manager.delete() method with user selections\n\t\"\"\"\n\tfrom AWS.s3 import S3Manager\n\tfrom pprint import pformat\n\tfrom helper.helper import sanitize_tree\n\t\n\tapi_region_name \u003d self.view.custom.api_region_name\n\tusername \u003d self.session.props.auth.user.userName\n\tself.view.custom.loading \u003d True\n\n\ts3m \u003d S3Manager(\u0027prod\u0027, api_region_name, username)\n\n\tbucket \u003d self.view.params.bucket\n\tobj_key \u003d self.view.custom.selected_file_config.Key\n\toperation \u003d \u0027delete\u0027\n\tparams \u003d {\u0027obj_key\u0027: obj_key, \u0027bucket\u0027: bucket}\n\ttry:\n\t\tresp \u003d getattr(s3m, operation)(**params)\n\t\tresp_code \u003d resp.get(\u0027code\u0027, None)\n\t\tif (resp_code and resp_code !\u003d 200) or (not resp_code and \u0027message\u0027 in resp):\n\t\t\t# this means the API encountered an error, annunciate the error here\n\t\t\tmsg \u003d \u0027API encountered error deleting %s on %s bucket. \\nResponse: %s\u0027 % (obj_key, bucket, pformat(sanitize_tree(resp)))\n\t\t\tsystem.perspective.print(msg)\n\t\t\tself.view.custom.loading \u003d False\n\t\t\tself.show_error_dialog(msg)\n\t\t\treturn\n\t\tmsg \u003d pformat(sanitize_tree(resp))\n\t\tsystem.perspective.print(msg)\n\t\tself.show_success_dialog(msg)\n\t\tself.update_bindings()\n\texcept:\n\t\timport traceback\n\t\tmsg \u003d \u0027Error executing %s operation! \\nError: %s\u0027 % (\n\t\t\t\toperation, traceback.format_exc())\n\t\tsystem.perspective.print(msg)\n\t\tself.view.custom.loading \u003d False\n\t\tself.show_error_dialog(msg)\n\t"
                    }
                  ],
                  "extensionFunctions": null,
                  "messageHandlers": [
                    {
                      "messageType": "confirm_delete_file",
                      "pageScope": false,
                      "script": "\tsystem.perspective.closePopup(\u0027alertDialog\u0027)\n\tif payload is not None:\n\t\tbucket_requested \u003d payload.get(\u0027bucket\u0027, None)\n\t\tif bucket_requested and bucket_requested \u003d\u003d self.view.params.bucket:\n\t\t\t# call the delete custom method\n\t\t\tself.delete_file()",
                      "sessionScope": true,
                      "viewScope": true
                    }
                  ]
                },
                "type": "ia.input.button"
              }
            ],
            "meta": {
              "name": "FlexContainer File Selection"
            },
            "position": {
              "shrink": 0
            },
            "props": {
              "style": {
                "classes": "Framework/Cards/Row"
              }
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "meta": {
                  "name": "Label"
                },
                "position": {
                  "basis": "125px",
                  "shrink": 0
                },
                "props": {
                  "style": {
                    "classes": "Framework/Card/Label Text/RightAlign_with_Padding",
                    "paddingLeft": "5px"
                  },
                  "text": "Object Key (uri):"
                },
                "type": "ia.display.label"
              },
              {
                "meta": {
                  "name": "label_LeftAlign"
                },
                "position": {
                  "basis": "200px",
                  "grow": 1
                },
                "propConfig": {
                  "props.params.text": {
                    "binding": {
                      "config": {
                        "path": "view.custom.selected_file_config.Key"
                      },
                      "type": "property"
                    }
                  }
                },
                "props": {
                  "path": "Objects/Templates/Labels/label_LeftAlign",
                  "style": {
                    "classes": "Framework/Card/Value"
                  }
                },
                "type": "ia.display.view"
              }
            ],
            "meta": {
              "name": "FlexContainer Object Key"
            },
            "position": {
              "shrink": 0
            },
            "propConfig": {
              "position.display": {
                "binding": {
                  "config": {
                    "expression": "!{view.custom.file_not_found}"
                  },
                  "type": "expr"
                }
              }
            },
            "props": {
              "style": {
                "classes": "Framework/Cards/Row"
              }
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "meta": {
                  "name": "Label"
                },
                "position": {
                  "basis": "125px",
                  "shrink": 0
                },
                "props": {
                  "style": {
                    "classes": "Framework/Card/Label Text/RightAlign_with_Padding",
                    "paddingLeft": "5px"
                  },
                  "text": "Last Modified:"
                },
                "type": "ia.display.label"
              },
              {
                "meta": {
                  "name": "label_LeftAlign"
                },
                "position": {
                  "basis": "200px",
                  "grow": 1
                },
                "propConfig": {
                  "props.params.text": {
                    "binding": {
                      "config": {
                        "path": "view.custom.selected_file_config.LastModified"
                      },
                      "type": "property"
                    }
                  }
                },
                "props": {
                  "path": "Objects/Templates/Labels/label_LeftAlign",
                  "style": {
                    "classes": "Framework/Card/Value"
                  }
                },
                "type": "ia.display.view"
              }
            ],
            "meta": {
              "name": "FlexContainer Last Modified"
            },
            "position": {
              "shrink": 0
            },
            "propConfig": {
              "position.display": {
                "binding": {
                  "config": {
                    "expression": "!{view.custom.file_not_found}"
                  },
                  "type": "expr"
                }
              }
            },
            "props": {
              "style": {
                "classes": "Framework/Cards/Row"
              }
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "children": [
                  {
                    "meta": {
                      "name": "Label"
                    },
                    "position": {
                      "basis": "125px",
                      "shrink": 0
                    },
                    "props": {
                      "style": {
                        "classes": "Framework/Card/Label Text/RightAlign_with_Padding",
                        "paddingLeft": "5px"
                      },
                      "text": "File Size (KB):"
                    },
                    "type": "ia.display.label"
                  },
                  {
                    "meta": {
                      "name": "label_LeftAlign"
                    },
                    "position": {
                      "basis": "200px",
                      "grow": 1
                    },
                    "propConfig": {
                      "props.params.text": {
                        "binding": {
                          "config": {
                            "expression": "round({view.custom.selected_file_config.Size}/1024.0,2)"
                          },
                          "type": "expr"
                        }
                      }
                    },
                    "props": {
                      "path": "Objects/Templates/Labels/label_LeftAlign",
                      "style": {
                        "classes": "Framework/Card/Value"
                      }
                    },
                    "type": "ia.display.view"
                  }
                ],
                "meta": {
                  "name": "FlexContainer File Size"
                },
                "position": {
                  "basis": "50%",
                  "grow": 1
                },
                "type": "ia.container.flex"
              },
              {
                "children": [
                  {
                    "meta": {
                      "name": "Label"
                    },
                    "position": {
                      "basis": "125px",
                      "shrink": 0
                    },
                    "props": {
                      "style": {
                        "classes": "Framework/Card/Label Text/RightAlign_with_Padding",
                        "paddingLeft": "5px"
                      },
                      "text": "Storage Class:"
                    },
                    "type": "ia.display.label"
                  },
                  {
                    "meta": {
                      "name": "label_LeftAlign"
                    },
                    "position": {
                      "basis": "200px",
                      "grow": 1
                    },
                    "propConfig": {
                      "props.params.text": {
                        "binding": {
                          "config": {
                            "path": "view.custom.selected_file_config.StorageClass"
                          },
                          "type": "property"
                        }
                      }
                    },
                    "props": {
                      "path": "Objects/Templates/Labels/label_LeftAlign",
                      "style": {
                        "classes": "Framework/Card/Value"
                      }
                    },
                    "type": "ia.display.view"
                  }
                ],
                "meta": {
                  "name": "FlexContainer Storage Class"
                },
                "position": {
                  "basis": "50%",
                  "grow": 1
                },
                "type": "ia.container.flex"
              }
            ],
            "meta": {
              "name": "FlexContainer File Detail"
            },
            "position": {
              "shrink": 0
            },
            "propConfig": {
              "position.display": {
                "binding": {
                  "config": {
                    "expression": "!{view.custom.file_not_found}"
                  },
                  "type": "expr"
                }
              }
            },
            "props": {
              "style": {
                "classes": "Framework/Cards/Row"
              }
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "events": {
                  "component": {
                    "onActionPerformed": {
                      "config": {
                        "script": "\t# build out the stage, site, flow-view, and copy_option from the object-key in row\n\tobj_key \u003d self.view.custom.selected_file_config.Key\n\tfilename \u003d self.view.custom.selected_file_config.Filename\n\tsuffix \u003d self.view.params.suffix\n\tpath \u003d obj_key.split(\u0027/\u0027)\n\tsite \u003d path[1]\n\tview \u003d filename.replace(suffix,\u0027\u0027)\n\tbucket \u003d self.view.params.bucket\n\t# build out query_params from row values\n\t# view, site, and bucket are multi-select dropdowns so need to be cast as lists\n\tnull \u003d None\n\tquery_params \u003d {\n\t\t\"copy_option\": null,\n\t\t\"destination_bucket\": bucket,\n\t\t\"destination_site\": site,\n\t\t\"destination_view\": view,\n\t\t\"end_time\": null,\n\t\t\"error_occurred\": null,\n\t\t\"operation\": null,\n\t\t\"source_bucket\": null,\n\t\t\"source_site\": null,\n\t\t\"source_view\": null,\n\t\t\"start_time\": null,\n\t\t\"username\": \"\"\n\t}\n\t# Open audit log viewer\n\tview_path \u003d \u0027PopUp-Views/S3/Audit/Log_Viewer\u0027\n\tparams \u003d {\u0027query_params\u0027: query_params}\n\tsystem.perspective.openPopup(\u0027Audit Log Viewer\u0027, view_path, \n\t\t\t\t\t\t\t\tparams, \u0027SCADA S3 Audit Logs\u0027)"
                      },
                      "scope": "G",
                      "type": "script"
                    }
                  }
                },
                "meta": {
                  "name": "Audit Logs Button",
                  "tooltip": {
                    "enabled": true,
                    "location": "bottom",
                    "text": "View Audit Logs for this file"
                  }
                },
                "position": {
                  "shrink": 0
                },
                "propConfig": {
                  "props.enabled": {
                    "binding": {
                      "config": {
                        "expression": "!{view.custom.file_not_found}"
                      },
                      "type": "expr"
                    }
                  }
                },
                "props": {
                  "image": {
                    "icon": {
                      "path": "material/table_view"
                    }
                  },
                  "primary": false,
                  "style": {
                    "margin": "2px",
                    "paddingLeft": "4px",
                    "paddingRight": "4px"
                  },
                  "text": "Audit Logs"
                },
                "type": "ia.input.button"
              },
              {
                "events": {
                  "component": {
                    "onActionPerformed": {
                      "config": {
                        "script": "\t# build out the stage, site, flow-view, and copy_option from the object-key in row\n\tobj_key \u003d self.view.custom.selected_file_config.Key\n\tfilename \u003d self.view.custom.selected_file_config.Filename\n\tsuffix \u003d self.view.params.suffix\n\tpath \u003d obj_key.split(\u0027/\u0027)\n\tsite \u003d path[1]\n\tview \u003d filename.replace(suffix,\u0027\u0027)\n\tbucket \u003d self.view.params.bucket\n\t# build out query_params from row values\n\tquery_params \u003d {\n\t\t\"view\": view,\n\t\t\"object_key\": obj_key,\n\t\t\"site\": site,\n\t\t\"bucket\": bucket\n\t}\n\t# Open version history log viewer\n\tview_path \u003d \u0027PopUp-Views/S3/Versions/Log_Viewer\u0027\n\tparams \u003d {\u0027query_params\u0027: query_params}\n\tsystem.perspective.openPopup(\u0027Version Log Viewer\u0027, view_path, \n\t\t\t\t\t\t\t\tparams, \u0027SCADA S3 Version History Log Viewer\u0027)\n\t\t"
                      },
                      "scope": "G",
                      "type": "script"
                    }
                  }
                },
                "meta": {
                  "name": "Version History Button",
                  "tooltip": {
                    "text": "View Version History for this file"
                  }
                },
                "position": {
                  "shrink": 0
                },
                "propConfig": {
                  "props.enabled": {
                    "binding": {
                      "config": {
                        "expression": "!{view.custom.file_not_found}"
                      },
                      "type": "expr"
                    }
                  }
                },
                "props": {
                  "image": {
                    "icon": {
                      "path": "material/history"
                    }
                  },
                  "primary": false,
                  "style": {
                    "margin": "2px",
                    "paddingLeft": "4px",
                    "paddingRight": "4px"
                  },
                  "text": "Version History"
                },
                "type": "ia.input.button"
              },
              {
                "meta": {
                  "name": "Label"
                },
                "position": {
                  "basis": "75px",
                  "shrink": 0
                },
                "props": {
                  "style": {
                    "classes": "Framework/Card/Label Text/RightAlign_with_Padding",
                    "paddingLeft": "5px"
                  },
                  "text": "Upload New File:"
                },
                "type": "ia.display.label"
              },
              {
                "events": {
                  "component": {
                    "onFileReceived": {
                      "config": {
                        "script": "\tself.upload_file(event\u003devent)\n"
                      },
                      "scope": "G",
                      "type": "script"
                    }
                  }
                },
                "meta": {
                  "name": "FileUpload",
                  "tooltip": {
                    "enabled": true
                  }
                },
                "position": {
                  "basis": "25%",
                  "shrink": 0
                },
                "propConfig": {
                  "meta.tooltip.text": {
                    "binding": {
                      "config": {
                        "expression": "stringFormat(\u0027Upload new file to %s S3 bucket\u0027,{view.params.bucket})"
                      },
                      "type": "expr"
                    }
                  },
                  "position.display": {
                    "binding": {
                      "config": {
                        "path": "view.params.enables.upload"
                      },
                      "type": "property"
                    }
                  },
                  "props.supportedFileTypes": {
                    "binding": {
                      "config": {
                        "path": "view.params.upload_file_types"
                      },
                      "type": "property"
                    }
                  }
                },
                "props": {
                  "fileSizeLimit": 100,
                  "fileUploadIcon": {
                    "style": {
                      "classes": ""
                    }
                  },
                  "maxUploads": 1,
                  "style": {
                    "backgroundColor": "var(--neutral-30)",
                    "borderStyle": "none",
                    "classes": "FadeInFast, background, background-none",
                    "cursor": "pointer",
                    "margin": "2px",
                    "max-height": "40px",
                    "overflow": "visible"
                  }
                },
                "scripts": {
                  "customMethods": [
                    {
                      "name": "update_bindings",
                      "params": [],
                      "script": "\t\"\"\"\n\t\tAfter data saved to S3, refresh session and view bindings\n\t\"\"\"\n\t\n\tself.view.custom.loading \u003d False\n\t# reset file upload component to default state\n\tself.clearUploads()\n\t# send message to update files param on parent view\n\tbucket \u003d self.view.params.bucket\n\tsystem.perspective.sendMessage(\u0027update_file_binding\u0027, {\u0027bucket\u0027: bucket}, scope\u003d\u0027session\u0027)\n\t"
                    },
                    {
                      "name": "show_success_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"success\", \n\t\t\"File Uploaded\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t"
                    },
                    {
                      "name": "show_warning_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"warning\", \n\t\t\"File NOT Uploaded\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t\t"
                    },
                    {
                      "name": "show_error_dialog",
                      "params": [
                        "msg\u003dNone"
                      ],
                      "script": "\t# ~~ 13 PARAMETERS ~~\n\t# state\t\t\t\t\t(default \u003d info) empty string uses generic gray styling\n\t# title \t\t\t\t(default \u003d Alert Title) empty string sets the title visibility to false\n\t# message \t\t\t\t(default \u003d Alert message goes here.)\n\t# show close button\t\t(default \u003d true) boolean\n\t# btn text primary\t\t(default \u003d \"Primary\")\n\t# btn text secondary\t(default \u003d \"Secondary\")\n\t# btn icon primary \t\t(default \u003d chevron_right) do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon secondary \t(default \u003d \"\") do not include \u0027material/\u0027 in the path, just the icon name\n\t# btn icon alignment\t(default \u003d \"right\") left or right\n\t# btn primary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn secondary action\t(default \u003d \"\") add message handlers on this button to enable other script actions\n\t# btn close action\t\t(default \u003d \"\") add message handlers on this icon to enable other script actions\n\t# payload\t\t\t\t(default \u003d {}) add a payload here to return to the target message handler\n\t\n\tAlerts.showAlert(\n\t\t\"error\", \n\t\t\"File Upload Error!\", \n\t\tmsg, \n\t\t\"true\",\n\t\t\"OK\", \n\t\t\"CLOSE\", \n\t\t\"\", \n\t\t\"\", \n\t\t\"left\", \n\t\t\"closePopup\", \n\t\t\"closePopup\", \n\t\t\"closePopup\",\n\t\t{}\n\t)\n\t\t\t\t\t"
                    },
                    {
                      "name": "upload_file",
                      "params": [
                        "event\u003dNone"
                      ],
                      "script": "\tfrom AWS.s3 import S3Manager\n\tfrom pprint import pformat\n\t\n\tself.view.custom.loading \u003d True\n\ttry:\n\t\tapi_stage \u003d \u0027prod\u0027\n\t\tusername \u003d self.session.props.auth.user.userName\n\t\tapi_region_name \u003d self.view.custom.api_region_name\n\t\tbucket \u003d self.view.params.bucket\n\t\tdefault_obj_key \u003d self.view.custom.default_file_config.Key\n\t\tdefault_filename \u003d self.view.custom.default_file_config.Filename\n\t\tregion \u003d self.view.custom.stage_config.s3_region\n\t\tfilename \u003d event.file.name\n\t\t# check if file already exists in S3 site folder, throw error if so\n\t\tif any(x.Filename \u003d\u003d filename for x in self.view.params.files):\n\t\t\tmsg \u003d \u0027%s file already exists in the site folder. Please use the upload button next to the file select dropdown or select a new file to upload\u0027 % filename\n\t\t\tself.show_error_dialog(msg)\n\t\t\tself.view.custom.loading \u003d False\n\t\t\tself.clearUploads()\n\t\t\treturn\n\t\tobj_key \u003d default_obj_key.replace(default_filename, filename)\n\t\tobj_data \u003d event.file.getString()\n\t\t\n\t\ts3m \u003d S3Manager(api_stage, api_region_name, username)\n\t\ttry:\n\t\t\tresp \u003d s3m.upload(\n\t\t\t\tobj_data\u003dobj_data,\n\t\t\t\tobj_key\u003dobj_key,\n\t\t\t\tbucket\u003dbucket,\n\t\t\t\tregion\u003dregion\n\t\t\t)\n\t\t\tresp_code \u003d resp.get(\u0027code\u0027, None)\n\t\t\tif (resp_code and resp_code !\u003d 200) or (not resp_code and \u0027message\u0027 in resp):\n\t\t\t\t# this means the API encountered an error, annunciate the error here\n\t\t\t\tmsg \u003d \u0027API encountered error uploading %s to %s bucket. \\nResponse: %s\u0027 % (obj_key, bucket, pformat(resp))\n\t\t\t\tsystem.perspective.print(msg)\n\t\t\t\tself.view.custom.loading \u003d False\n\t\t\t\tself.show_error_dialog(msg)\n\t\t\t\tself.clearUploads()\n\t\t\t\treturn\n\t\t\tmsg \u003d \u0027Successfully uploaded %s object in %s bucket!\\nResponse: %s\u0027 % (obj_key, bucket, pformat(resp))\n\t\t\tsystem.perspective.print(msg)\n\t\t\tself.show_success_dialog(msg)\n\t\t\tself.update_bindings()\n\t\texcept:\n\t\t\timport traceback\n\t\t\tmsg \u003d \u0027Error uploading %s object in %s bucket: %s\u0027 % (obj_key, bucket, traceback.format_exc())\n\t\t\tsystem.perspective.print(msg)\n\t\t\tself.view.custom.loading \u003d False\n\t\t\tself.show_error_dialog(msg)\n\t\t\tself.clearUploads()\n\texcept:\n\t\timport traceback\n\t\tmsg \u003d \u0027General Error uploading %s object in %s bucket: %s\u0027 % (obj_key, bucket, traceback.format_exc())\n\t\tsystem.perspective.print(msg)\n\t\tself.view.custom.loading \u003d False\n\t\tself.show_error_dialog(msg)\n\t\tself.clearUploads()\n\t\t"
                    }
                  ],
                  "extensionFunctions": null,
                  "messageHandlers": []
                },
                "type": "ia.input.fileupload"
              }
            ],
            "meta": {
              "name": "FlexContainer Log Buttons"
            },
            "position": {
              "shrink": 0
            },
            "props": {
              "justify": "center"
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "children": [
                  {
                    "meta": {
                      "name": "Title"
                    },
                    "position": {
                      "basis": "100%"
                    },
                    "propConfig": {
                      "props.text": {
                        "binding": {
                          "config": {
                            "expression": "stringFormat(\u0027%s Object%s\u0027, len({view.params.files}), \r\n\tif(len({view.params.files})\u003d1,\u0027\u0027,\u0027s\u0027))"
                          },
                          "type": "expr"
                        }
                      }
                    },
                    "props": {
                      "style": {
                        "classes": "Title/Text",
                        "fontSize": 14,
                        "overflow": "visible"
                      }
                    },
                    "type": "ia.display.label"
                  }
                ],
                "meta": {
                  "name": "Title"
                },
                "position": {
                  "basis": "50%"
                },
                "props": {
                  "style": {
                    "fontSize": 1,
                    "marginLeft": 10,
                    "overflow": "visible"
                  }
                },
                "type": "ia.container.flex"
              },
              {
                "children": [
                  {
                    "meta": {
                      "name": "FilterCheck",
                      "tooltip": {
                        "enabled": true,
                        "location": "top-left",
                        "text": "Enable Table Search"
                      }
                    },
                    "position": {
                      "basis": "108px"
                    },
                    "propConfig": {
                      "position.display": {
                        "binding": {
                          "config": {
                            "expression": "LEN({..../Table.props.data})\u003e0"
                          },
                          "type": "expr"
                        }
                      }
                    },
                    "props": {
                      "checkedIcon": {
                        "style": {
                          "fontSize": 16
                        }
                      },
                      "indeterminateIcon": {
                        "style": {
                          "fontSize": 16
                        }
                      },
                      "style": {
                        "fontSize": 12
                      },
                      "text": "Search?",
                      "textPosition": "left",
                      "uncheckedIcon": {
                        "style": {
                          "fontSize": 16
                        }
                      }
                    },
                    "type": "ia.input.checkbox"
                  },
                  {
                    "meta": {
                      "name": "Spacer1"
                    },
                    "position": {
                      "basis": "1px"
                    },
                    "props": {
                      "style": {
                        "classes": "General/Divider"
                      }
                    },
                    "type": "ia.container.flex"
                  },
                  {
                    "events": {
                      "dom": {
                        "onClick": {
                          "config": {
                            "script": "\tself.view.custom.selected_file \u003d \u0027\u0027\n\ttable \u003d self.parent.parent.parent.getChild(\"Table\")\n\t# ignition perspective has a bug with table where the only way to \n\t# actually de-select and remove the row highlight is to set the\n\t# row and column to -1 and THEN None\n\t# this will automatically clear the selection.data array\n\ttable.props.selection.selectedRow \u003d -1\n\ttable.props.selection.selectedColumn \u003d -1\n\ttable.props.selection.selectedRow \u003d None\n\ttable.props.selection.selectedColumn \u003d None"
                          },
                          "scope": "G",
                          "type": "script"
                        }
                      }
                    },
                    "meta": {
                      "name": "ClearSelectionButton",
                      "tooltip": {
                        "enabled": true,
                        "location": "top-left",
                        "text": "Clear Selection"
                      }
                    },
                    "position": {
                      "basis": "31px"
                    },
                    "propConfig": {
                      "position.display": {
                        "binding": {
                          "config": {
                            "expression": "len({..../Table.props.selection.data})\u003e0"
                          },
                          "type": "expr"
                        }
                      }
                    },
                    "props": {
                      "path": "material/clear",
                      "style": {
                        "classes": "General/Button"
                      }
                    },
                    "type": "ia.display.icon"
                  },
                  {
                    "meta": {
                      "name": "Spacer2"
                    },
                    "position": {
                      "basis": "1px"
                    },
                    "propConfig": {
                      "position.display": {
                        "binding": {
                          "config": {
                            "path": "../ClearSelectionButton.position.display"
                          },
                          "type": "property"
                        }
                      }
                    },
                    "props": {
                      "style": {
                        "classes": "General/Divider"
                      }
                    },
                    "type": "ia.container.flex"
                  },
                  {
                    "events": {
                      "dom": {
                        "onClick": {
                          "config": {
                            "draggable": false,
                            "id": "ColumnSelection",
                            "modal": true,
                            "overlayDismiss": true,
                            "position": {
                              "relativeLocation": "bottom-left"
                            },
                            "positionType": "relative",
                            "resizable": true,
                            "showCloseIcon": true,
                            "type": "toggle",
                            "viewParams": {
                              "Columns": "{/root/FlexContainer/TableHeader/TableActions/ColumnSelectionButton.custom.Columns}"
                            },
                            "viewPath": "Objects/PowerTable/ColumnSelection",
                            "viewportBound": false
                          },
                          "scope": "C",
                          "type": "popup"
                        }
                      }
                    },
                    "meta": {
                      "name": "ColumnSelectionButton",
                      "tooltip": {
                        "enabled": true,
                        "location": "top-left",
                        "text": "+/- Columns"
                      }
                    },
                    "position": {
                      "basis": "29px"
                    },
                    "propConfig": {
                      "custom.Columns": {
                        "binding": {
                          "config": {
                            "path": "..../Table.props.columns"
                          },
                          "transforms": [
                            {
                              "code": "\tcolumns \u003d {}\n\tif len(value) \u003e 0:\n\t\tfor column in value:\n\t\t\t#field \u003d column.field\n\t\t\tfield \u003d column.header.title\n\t\t\tif field \u003d\u003d \u0027\u0027:\n\t\t\t\tfield \u003d \u0027None\u0027\n\t\t\tcolumns[field] \u003d column.visible\n\treturn columns",
                              "type": "script"
                            }
                          ],
                          "type": "property"
                        }
                      },
                      "position.display": {
                        "binding": {
                          "config": {
                            "expression": "LEN({..../Table.props.data})\u003e0"
                          },
                          "type": "expr"
                        }
                      }
                    },
                    "props": {
                      "path": "material/view_column",
                      "style": {
                        "classes": "General/Button",
                        "fontSize": 12,
                        "marginBottom": 5,
                        "marginTop": 5
                      }
                    },
                    "type": "ia.display.icon"
                  },
                  {
                    "meta": {
                      "name": "Spacer4"
                    },
                    "position": {
                      "basis": "1px"
                    },
                    "propConfig": {
                      "position.display": {
                        "binding": {
                          "config": {
                            "expression": "LEN({..../Table.props.data})\u003e0"
                          },
                          "type": "expr"
                        }
                      }
                    },
                    "props": {
                      "style": {
                        "classes": "General/Divider"
                      }
                    },
                    "type": "ia.container.flex"
                  },
                  {
                    "events": {
                      "dom": {
                        "onClick": {
                          "config": {
                            "script": "\tself.view.custom.filters.selection_active \u003d not self.view.custom.filters.selection_active"
                          },
                          "scope": "G",
                          "type": "script"
                        }
                      }
                    },
                    "meta": {
                      "name": "FilterButton",
                      "tooltip": {
                        "enabled": true,
                        "location": "top-left",
                        "text": "Filter Table"
                      }
                    },
                    "position": {
                      "basis": "29px",
                      "display": false
                    },
                    "props": {
                      "path": "material/filter_list",
                      "style": {
                        "classes": "General/Button",
                        "fontSize": 12,
                        "marginBottom": 5,
                        "marginTop": 5
                      }
                    },
                    "type": "ia.display.icon"
                  },
                  {
                    "meta": {
                      "name": "Spacer3"
                    },
                    "position": {
                      "basis": "1px"
                    },
                    "props": {
                      "style": {
                        "classes": "General/Divider"
                      }
                    },
                    "type": "ia.container.flex"
                  },
                  {
                    "events": {
                      "dom": {
                        "onClick": {
                          "config": {
                            "script": "\n\tcsv_headers \u003d []\n\tcsv_data \u003d []\n\tsystem.perspective.print(\u0027DOWNLOADING TABLE DATA\u0027)\n\tsource_data \u003d  self.parent.parent.parent.getChild(\"Table\").props.data\n\theaders \u003d source_data[0].keys()\n\t\n\tif \u0027style\u0027 in headers and \u0027value\u0027 in headers and len(headers) \u003d\u003d 2:\n\t\tdata \u003d [row[\u0027value\u0027] for row in source_data]\n\telse:\n\t\tdata \u003d source_data\n\t\t\n\tfor record in data:\n\t\tif len(csv_headers) \u003d\u003d 0:\n\t\t\tcsv_headers \u003d record.keys()\n\t\t\tcsv_headers.sort()\n\t\t\tcsv_headers \u003d [str(i) for i in csv_headers]\n\t\tcsv_row \u003d []\n\t\tfor index in range(len(record)):\n\t\t\tcsv_row.append(str(record[csv_headers[index]]))\n\t\tcsv_data.append(csv_row)\n\t\n\ttry:\n\t\tcsv_dataset \u003d system.dataset.toDataSet(csv_headers, csv_data)\n\texcept Exception, e:\n\t\tsystem.perspective.print(str(e))\n\tcsv_export \u003d system.dataset.toCSV(csv_dataset)\n\tfilename \u003d \u0027{0}.csv\u0027.format(str(system.date.now()).replace(\u0027 \u0027, \u0027_\u0027))\n\tsystem.perspective.download(filename, csv_export)\n\t\n\tsystem.perspective.print(\u0027DONE DOWNLOADING TABLE DATA\u0027)"
                          },
                          "scope": "G",
                          "type": "script"
                        }
                      }
                    },
                    "meta": {
                      "name": "SettingsButton",
                      "tooltip": {
                        "enabled": true,
                        "location": "top-left",
                        "text": "Download Table Contents"
                      }
                    },
                    "position": {
                      "basis": "30px"
                    },
                    "propConfig": {
                      "position.display": {
                        "binding": {
                          "config": {
                            "expression": "LEN({..../Table.props.data})\u003e0"
                          },
                          "type": "expr"
                        }
                      }
                    },
                    "props": {
                      "path": "material/cloud_download",
                      "style": {
                        "classes": "General/Button",
                        "marginRight": 10
                      }
                    },
                    "type": "ia.display.icon"
                  }
                ],
                "meta": {
                  "name": "TableActions",
                  "tooltip": {
                    "location": "top-right"
                  }
                },
                "position": {
                  "grow": 1
                },
                "props": {
                  "justify": "flex-end"
                },
                "type": "ia.container.flex"
              }
            ],
            "meta": {
              "name": "TableHeader"
            },
            "position": {
              "shrink": 0
            },
            "props": {
              "justify": "space-between",
              "style": {
                "borderBottomStyle": "solid",
                "borderBottomWidth": 1,
                "cursor": "pointer"
              }
            },
            "type": "ia.container.flex"
          },
          {
            "events": {
              "component": {
                "onSelectionChange": {
                  "config": {
                    "script": "\t# validate the selection data is not null\n\tif self.props.selection.data:\n\t\tfilename \u003d self.props.selection.data[0].Filename\n\t\tself.view.custom.selected_file \u003d filename\n\t\t# send message to update selected file on parent container\n\t\tsuffix \u003d self.view.params.suffix\n\t\tpayload \u003d {\u0027image\u0027: filename.replace(suffix, \u0027\u0027)}\n\t\tsystem.perspective.sendMessage(\u0027update_selected_image\u0027, payload, scope\u003d\u0027session\u0027)\n\t"
                  },
                  "scope": "G",
                  "type": "script"
                }
              }
            },
            "meta": {
              "name": "Table"
            },
            "position": {
              "basis": "370px",
              "shrink": 0
            },
            "propConfig": {
              "props.data": {
                "binding": {
                  "config": {
                    "path": "view.params.files"
                  },
                  "type": "property"
                }
              },
              "props.filter.enabled": {
                "binding": {
                  "config": {
                    "path": "../TableHeader/TableActions/FilterCheck.props.selected"
                  },
                  "type": "property"
                },
                "onChange": {
                  "enabled": null,
                  "script": "\tif not getattr(currentValue, \u0027value\u0027, None):\n\t\t# clear filter text when filter is disabled\n\t\tself.props.filter.text \u003d \u0027\u0027\n\t\t"
                }
              }
            },
            "props": {
              "columns": [
                {
                  "align": "center",
                  "boolean": "checkbox",
                  "dateFormat": "MM/DD/YYYY",
                  "editable": false,
                  "field": "Filename",
                  "filter": {
                    "boolean": {
                      "condition": ""
                    },
                    "date": {
                      "condition": "",
                      "value": ""
                    },
                    "enabled": false,
                    "number": {
                      "condition": "",
                      "value": ""
                    },
                    "string": {
                      "condition": "",
                      "value": ""
                    },
                    "visible": "on-hover"
                  },
                  "footer": {
                    "align": "center",
                    "justify": "left",
                    "style": {
                      "classes": ""
                    },
                    "title": ""
                  },
                  "header": {
                    "align": "center",
                    "justify": "center",
                    "style": {
                      "classes": ""
                    },
                    "title": "Filename"
                  },
                  "justify": "center",
                  "number": "value",
                  "numberFormat": "0,0.##",
                  "progressBar": {
                    "bar": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "max": 100,
                    "min": 0,
                    "track": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "value": {
                      "enabled": true,
                      "format": "0,0.##",
                      "justify": "center",
                      "style": {
                        "classes": ""
                      }
                    }
                  },
                  "render": "auto",
                  "resizable": true,
                  "sort": "none",
                  "sortable": true,
                  "strictWidth": false,
                  "style": {
                    "classes": ""
                  },
                  "toggleSwitch": {
                    "color": {
                      "selected": "",
                      "unselected": ""
                    }
                  },
                  "viewParams": {},
                  "viewPath": "",
                  "visible": true,
                  "width": ""
                },
                {
                  "align": "center",
                  "boolean": "checkbox",
                  "dateFormat": "MM/DD/YYYY",
                  "editable": false,
                  "field": "Size",
                  "filter": {
                    "boolean": {
                      "condition": ""
                    },
                    "date": {
                      "condition": "",
                      "value": ""
                    },
                    "enabled": false,
                    "number": {
                      "condition": "",
                      "value": ""
                    },
                    "string": {
                      "condition": "",
                      "value": ""
                    },
                    "visible": "on-hover"
                  },
                  "footer": {
                    "align": "center",
                    "justify": "left",
                    "style": {
                      "classes": ""
                    },
                    "title": ""
                  },
                  "header": {
                    "align": "center",
                    "justify": "center",
                    "style": {
                      "classes": ""
                    },
                    "title": "Size (bytes)"
                  },
                  "justify": "center",
                  "number": "value",
                  "numberFormat": "0,0.##",
                  "progressBar": {
                    "bar": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "max": 100,
                    "min": 0,
                    "track": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "value": {
                      "enabled": true,
                      "format": "0,0.##",
                      "justify": "center",
                      "style": {
                        "classes": ""
                      }
                    }
                  },
                  "render": "auto",
                  "resizable": true,
                  "sort": "none",
                  "sortable": true,
                  "strictWidth": false,
                  "style": {
                    "classes": ""
                  },
                  "toggleSwitch": {
                    "color": {
                      "selected": "",
                      "unselected": ""
                    }
                  },
                  "viewParams": {},
                  "viewPath": "",
                  "visible": true,
                  "width": ""
                },
                {
                  "align": "center",
                  "boolean": "checkbox",
                  "dateFormat": "MM/DD/YYYY",
                  "editable": false,
                  "field": "LastModified",
                  "filter": {
                    "boolean": {
                      "condition": ""
                    },
                    "date": {
                      "condition": "",
                      "value": ""
                    },
                    "enabled": false,
                    "number": {
                      "condition": "",
                      "value": ""
                    },
                    "string": {
                      "condition": "",
                      "value": ""
                    },
                    "visible": "on-hover"
                  },
                  "footer": {
                    "align": "center",
                    "justify": "left",
                    "style": {
                      "classes": ""
                    },
                    "title": ""
                  },
                  "header": {
                    "align": "center",
                    "justify": "center",
                    "style": {
                      "classes": ""
                    },
                    "title": "Last Updated"
                  },
                  "justify": "center",
                  "number": "value",
                  "numberFormat": "0,0.##",
                  "progressBar": {
                    "bar": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "max": 100,
                    "min": 0,
                    "track": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "value": {
                      "enabled": true,
                      "format": "0,0.##",
                      "justify": "center",
                      "style": {
                        "classes": ""
                      }
                    }
                  },
                  "render": "auto",
                  "resizable": true,
                  "sort": "none",
                  "sortable": true,
                  "strictWidth": false,
                  "style": {
                    "classes": ""
                  },
                  "toggleSwitch": {
                    "color": {
                      "selected": "",
                      "unselected": ""
                    }
                  },
                  "viewParams": {},
                  "viewPath": "",
                  "visible": true,
                  "width": ""
                },
                {
                  "align": "center",
                  "boolean": "checkbox",
                  "dateFormat": "MM/DD/YYYY",
                  "editable": false,
                  "field": "Key",
                  "filter": {
                    "boolean": {
                      "condition": ""
                    },
                    "date": {
                      "condition": "",
                      "value": ""
                    },
                    "enabled": false,
                    "number": {
                      "condition": "",
                      "value": ""
                    },
                    "string": {
                      "condition": "",
                      "value": ""
                    },
                    "visible": "on-hover"
                  },
                  "footer": {
                    "align": "center",
                    "justify": "left",
                    "style": {
                      "classes": ""
                    },
                    "title": ""
                  },
                  "header": {
                    "align": "center",
                    "justify": "center",
                    "style": {
                      "classes": ""
                    },
                    "title": "Key"
                  },
                  "justify": "center",
                  "number": "value",
                  "numberFormat": "0,0.##",
                  "progressBar": {
                    "bar": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "max": 100,
                    "min": 0,
                    "track": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "value": {
                      "enabled": true,
                      "format": "0,0.##",
                      "justify": "center",
                      "style": {
                        "classes": ""
                      }
                    }
                  },
                  "render": "auto",
                  "resizable": true,
                  "sort": "none",
                  "sortable": true,
                  "strictWidth": false,
                  "style": {
                    "classes": ""
                  },
                  "toggleSwitch": {
                    "color": {
                      "selected": "",
                      "unselected": ""
                    }
                  },
                  "viewParams": {},
                  "viewPath": "",
                  "visible": true,
                  "width": ""
                },
                {
                  "align": "center",
                  "boolean": "checkbox",
                  "dateFormat": "MM/DD/YYYY",
                  "editable": false,
                  "field": "ETag",
                  "filter": {
                    "boolean": {
                      "condition": ""
                    },
                    "date": {
                      "condition": "",
                      "value": ""
                    },
                    "enabled": false,
                    "number": {
                      "condition": "",
                      "value": ""
                    },
                    "string": {
                      "condition": "",
                      "value": ""
                    },
                    "visible": "on-hover"
                  },
                  "footer": {
                    "align": "center",
                    "justify": "left",
                    "style": {
                      "classes": ""
                    },
                    "title": ""
                  },
                  "header": {
                    "align": "center",
                    "justify": "center",
                    "style": {
                      "classes": ""
                    },
                    "title": "ETag"
                  },
                  "justify": "center",
                  "number": "value",
                  "numberFormat": "0,0.##",
                  "progressBar": {
                    "bar": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "max": 100,
                    "min": 0,
                    "track": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "value": {
                      "enabled": true,
                      "format": "0,0.##",
                      "justify": "center",
                      "style": {
                        "classes": ""
                      }
                    }
                  },
                  "render": "auto",
                  "resizable": true,
                  "sort": "none",
                  "sortable": true,
                  "strictWidth": false,
                  "style": {
                    "classes": ""
                  },
                  "toggleSwitch": {
                    "color": {
                      "selected": "",
                      "unselected": ""
                    }
                  },
                  "viewParams": {},
                  "viewPath": "",
                  "visible": false,
                  "width": ""
                },
                {
                  "align": "center",
                  "boolean": "checkbox",
                  "dateFormat": "MM/DD/YYYY",
                  "editable": false,
                  "field": "StorageClass",
                  "filter": {
                    "boolean": {
                      "condition": ""
                    },
                    "date": {
                      "condition": "",
                      "value": ""
                    },
                    "enabled": false,
                    "number": {
                      "condition": "",
                      "value": ""
                    },
                    "string": {
                      "condition": "",
                      "value": ""
                    },
                    "visible": "on-hover"
                  },
                  "footer": {
                    "align": "center",
                    "justify": "left",
                    "style": {
                      "classes": ""
                    },
                    "title": ""
                  },
                  "header": {
                    "align": "center",
                    "justify": "center",
                    "style": {
                      "classes": ""
                    },
                    "title": "Storage Class"
                  },
                  "justify": "center",
                  "number": "value",
                  "numberFormat": "0,0.##",
                  "progressBar": {
                    "bar": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "max": 100,
                    "min": 0,
                    "track": {
                      "color": "",
                      "style": {
                        "classes": ""
                      }
                    },
                    "value": {
                      "enabled": true,
                      "format": "0,0.##",
                      "justify": "center",
                      "style": {
                        "classes": ""
                      }
                    }
                  },
                  "render": "auto",
                  "resizable": true,
                  "sort": "none",
                  "sortable": true,
                  "strictWidth": false,
                  "style": {
                    "classes": ""
                  },
                  "toggleSwitch": {
                    "color": {
                      "selected": "",
                      "unselected": ""
                    }
                  },
                  "viewParams": {},
                  "viewPath": "",
                  "visible": false,
                  "width": ""
                }
              ],
              "filter": {},
              "style": {
                "margin": "10px"
              }
            },
            "type": "ia.display.table"
          }
        ],
        "meta": {
          "name": "FlexContainer"
        },
        "position": {
          "basis": "100%",
          "grow": 1
        },
        "props": {
          "direction": "column"
        },
        "type": "ia.container.flex"
      }
    ],
    "meta": {
      "name": "root"
    },
    "scripts": {
      "customMethods": [],
      "extensionFunctions": null,
      "messageHandlers": [
        {
          "messageType": "activate-filter",
          "pageScope": true,
          "script": "\t# implement your handler here\n\tfilter_position \u003d payload[\u0027id\u0027]\n\tsystem.perspective.print(filter_position)\n\tadd \u003d True\n\tfor filter in self.view.custom.filters.active:\n\t\tif filter.id \u003d\u003d filter_position:\n\t\t\tadd \u003d False\n\tif add:\n\t\tfor filter in self.view.custom.filters.deactive:\n\t\t\tif filter.id \u003d\u003d filter_position:\t\t\t\t\n\t\t\t\tself.view.custom.filters.active.append(filter)",
          "sessionScope": true,
          "viewScope": false
        },
        {
          "messageType": "deactivate-filter",
          "pageScope": true,
          "script": "\tfilter_position \u003d payload[\u0027id\u0027]\n\tsystem.perspective.print(filter_position)\n\t\n\tif filter_position \u003d\u003d -1 :\n\t\tself.view.custom.filters.active \u003d []\n\telse:\n\t\tfor index, filter in enumerate(self.view.custom.filters.active):\n\t\t\tif filter.id \u003d\u003d filter_position:\n\t\t\t\tsystem.perspective.print(filter.id)\n\t\t\t\tself.view.custom.filters.active.pop(index)\n\n#\tfor filter in self.view.custom.filter_menu_data:\n#\t\tif filter.filter_id \u003d\u003d filter_position:\n#\t\t\tsystem.perspective.print(filter.filter_id)\n#\t\t\tfilter.active \u003d False\n#\t\t\tbreak",
          "sessionScope": true,
          "viewScope": false
        },
        {
          "messageType": "column-visibility",
          "pageScope": true,
          "script": "\t# implement your handler here\n\ttable_columns \u003d self.getChild(\"FlexContainer\").getChild(\"Table\").props.columns\n\tfor table_column in table_columns:\n\t\t#if payload.keys()[0] \u003d\u003d table_column[\u0027field\u0027]:\n\t\tif payload.keys()[0] \u003d\u003d table_column[\u0027header\u0027][\u0027title\u0027]:\n\t\t\ttable_column.visible \u003d payload.values()[0]",
          "sessionScope": false,
          "viewScope": false
        }
      ]
    },
    "type": "ia.container.flex"
  }
}