Slate FAQ

The following are a few frequently asked questions about Contour. For general information, see Slate documentation.

--

Introduction to debugging slate

In many ways, Slate is the most complex Foundry tool available to developers. Slate puts the tools to build a single-page web application into an approachable package, but provides few built-in rails, instead allowing a wide degree of freedom in implementing different patterns. This flexibility is a powerful feature and allows a diverse array of applications, dashboards, and workflow tools to be built in Slate, but it also means it is quite easy to implement anti-patterns that result in slow performance or confusion, non-deterministic application behavior.

Getting to the root cause of the most complex of these types of implementation issues requires reverse engineering the application logic in the context of Slate development best practices as well as general principles of web application development.

We will break these down below to call out places where we have seen anti-patterns emerge and suggest improved practices or guide solutions. We will start with relevant questions of web technology:

1. Front-end web technology

  • How a web browser works.
  • How network requests are made from a browser and responded to from other services.
  • How browser resources are allocated to the rendering and JavaScript execution of a particular website.
  • How HTML and CSS work together to define how a website looks.
  • How JavaScript is compiled and executed.

While this knowledge is not specific to Slate, misunderstanding these fundamentals is at the root of many questions about performance, layout, and styling for Slate apps which are effectively custom-built web applications.

W3Schools ↗ amongst many other sources provide basic tutorials in these topics.

2. Postgres and SQL

It is also helpful to be familiar with SQL and how a Postgres database constructs and executes a query, since most applications retrieve their data with queries against the Postgate instance where data is synced from Foundry datasets for application access.

Many questions around query development, errors, performance are not Slate-specific and can be answered with common search queries, often in the form: Postgres + [question].

Slate, however, is not particularly friendly in parsing and providing error messages generated by Postgres, and we recommend you review the section below for common causes and remedies for these issues and refer to the Postgres Performance and Tuning guidelines for more detailed information.

3. Slate-specific knowledge

Building complex applications in Slate can take some getting used to and many anti-patterns can arise from "imposing" other application development concepts onto Slate, rather than working within framework provided by Slate. There are often implicit "correct" patterns for implementing a given functionality that best mesh with these fundamental Slate concepts.

Much of this complexity is covered in Understand dependencies, which includes discussions of the core components of Slate (the Dependency graph, the Event framework, widgets, queries, functions, and so on), common patterns (and common anti-patterns), and best practices for design and implementation.

We recommend developers and support engineers to have familiarity with this documentation as many common questions can be answered with content already explained in depth. In many cases, the best way to answer a question is not to try and solve the specific instance - for example, by opening the app and trying to reverse-engineer the user's development decisions - but rather to understand the general category of failure the user is encountering and direct them to the relevant discussion in any of the following:

For some of the most common cases, this FAQ documentation is a short-cut to brief explanations and useful reference material.

Return to top


Queries

Failed queries

Query-related questions come in many flavors and figuring out the root cause can point to many resolution strategies. In some cases, the issue presents with an explicit error message, but in others, there may be no error message or the conditions of failure may be non-deterministic (in that sometimes they happen, and sometimes they do not). The troubleshooting steps below present some common root causes and related resolution strategies.

To troubleshoot, perform the following steps:

Sometimes a query goes against general usage patterns for synchronous network requests:

  • Queries that try to return too much data to the browser.
    • Queries should return less than 10,000 rows as rough rule of thumb.
      • Sometimes the query will explicitly return with an error that says 'too many rows', but often, the query will succeed though the rest of the application will be very slow. In these cases, look for queries that are returning lots of rows and try to reduce the returned amount.
    • If you are trying to display a table with lots of rows or otherwise need to present raw rows to the user, use the LIMIT and OFFSET statements to implement a paging workflow, either with the built-in properties of the Table widget or with a custom workflow.
  • Queries that are so large that they take a long time to simply make the request.
    • Queries should take < 5s round-trip.
    • If you have a query with a large payload, consider pushing more of the logic embedded in the query into the transformation layer producing the datasets.

For this general category of question, refer to Optimize indexes and schema design documentation and consider that applications should be structured, so the data returned to the browser is in its final form, rather than in need of heavy manipulation in JavaScript functions.

Sometimes the issue is instead related to how Postgres interprets and responds to the request:

  • Queries that are slow because they are not optimally structured.
  • Queries that are slow because the dataset is not or is incorrectly indexed.
  • Queries that have incorrect syntax.

These types of questions are often answered with a search of Postgres + [error message] of Postgres + [desired query]. For all questions related to troubleshooting or investigating query performance, refer to the Postgres query performance and tuning guide.

And sometimes the issue is rather with how and when Slate executes queries according to the developer's configuration:

  • Queries fail non-deterministically on page load.
  • Queries that return an unhelpful error at 20s (the Slate timeout period)
    • The requests made through Slate queries timeout on the Slate side at 20s, regardless of what happening on the server-side of the request. The definitive diagnosis for this failure mode is to view the application in View mode with the Google Chrome Network Inspector open when you refresh the page. This will show the duration of each query request and if you see a query turn red at 20s, you can be sure the failure is because Slate has timed out the query.
    • Resolve this both by improving query performance: Postgres query performance and tuning and Controlling query execution.
    • For more on timeouts specifically, review the next section on Postgres query times out.
  • Queries that fail in certain circumstances (because the Handlebars rendering is not well protected).
    • If you have Handlebars statements in your query, make sure they're protected by {{#if}} statements or through logic in a function against null values or other edge cases.
  • Queries that execute at the wrong time or fail to execute.

Return to top


Postgres query times out

When queries time out, there are two primary factors at play:

  • Data scale - how many rows are in the table in Postgres and how many rows you are returning from the query.
  • Query optimization - how "expensive" is the query.

As an application developer, it is necessary to understand these factors and how they affect your query. Neither are Slate nor Foundry-specific, so you can make progress through searching for Postgres SQL query performance and find the general best practices as well as tips in the Postgres Query Performance and Tuning guide.

To troubleshoot, perform the following steps:

A few pointers that may help, based on frequently seen issues from app developers:

  • Data Scale: Limit the scale of the dataset you are syncing to Postgres. For example, if you only need one year of data, do not sync a dataset of all time and then filter in your query.

  • Data Scale: Reduce the number of columns in the table. For example, if you only select a few columns in the query, drop them in a transform before syncing the table to avoid overhead.

  • Data Scale: Return as few rows as possible. If you are displaying the raw rows, use OFFSET and PAGING to retrieve further rows rather than returning more than a few hundred rows in response to any query.

  • Query Optimization: Avoid expensive SQL commands where possible. Frequent offenders are COALESCE, DISTINCT, any JOIN on columns that are not "complete" (such as some values are null) or WHERE clause filters that involve leading wildcards (%) or complex match expressions.

  • Query Optimization: Push work upstream. This includes data cleanup (removing nulls, formatting dates, mapping display values) and metrics calculations (monthly totals, averages across buckets, etc.) should be pushed into the transforms layer when possible. If you need to allow users to customize these through filters, you can still "pre-aggregate" metrics across a few dimensions, then do a much simpler query to sum/average/etc. across just a few rows that meet those criteria.

  • Query Optimization: Use EXPLAIN ANALYZE do get the query plan and understand how Postgres is interpreting your query. This will help identify bottlenecks where the time is being spent and you can further target your optimizations. Here ↗ is a useful primer on reading and understanding the results.

  • Query Optimization: Review Optimize queries in Postgres.

Return to top


Cannot reference columns in my Postgres query

In Postgres, column names are assumed to be lower case. Since Foundry allows flexible casing and spacing in column names, when a table is indexed to Postres, the table is wrapped in " (double quote) characters to preserve the casing.

This means if the column has capitalized characters, you will need to wrap the reference in your SQL query in double quotes as well.

You can read more about this behavior on StackOverflow ↗.

To troubleshoot, perform the following steps:

Queries with mishandled column identifiers will often have an error such as:

ERROR: column mixedcasecolumn does not exist HINT: Perhaps you meant to reference the column "Mixed Case Column"

In these cases, best practice is to update the dataset in question to use column identifiers that meet Postgres defaults, which is generally lowercase characters with underscores replacing spaces. Otherwise, simply ensure that the identifiers are properly encapsulated in double quotes.

Phonograph Queries and General Foundry Writeback

More advanced users building complex applications with data write-back to Foundry datasets will be using the Phonograph service. Ensure that the Phonograph Reference Application is available on your Foundry instance.

Most common questions are answered there with example queries and widget patterns. In addition, most of the content from the reference example can be reviewed at How To: Writeback to Foundry.

To troubleshoot, perform the following steps:

Read the documentation carefully as most common issues are covered, though this is a deep and complex feature. Please reach out to the Palantir support team with particular questions or issues.

Return to top


Phonograph query truncates text on Submit

In an edge case configuration, you can observe writeback queries that reference one or more Text Area widgets send a Phonograph request with only partial text. For instance, if the user enters long text like This is a test message for writeback and quickly presses the Submit button to trigger the writeback query, only This is a te might be included.

The underlying cause is the 0.5s debounce delay used by the Text Area widget to prevent the Dependency Graph from re-evaluating with every key press in the widget input. This delay means that the query will submit without the entire text if, and only if:

  • A text area widget is the last input filled in by a user, and,
  • The submit button is pressed less than 0.5s after the last character is entered into the text area.

To troubleshoot, perform the following steps:

The simplest solution is to tweak the user experience such that it is not possible to use the submit option within 0.5s of entering long text. For instance, adding in a confirmation dialog before submitting the query or simply re-ordering the form elements, so there is another field to complete after the text area widget.

Other solutions would be to swap the text area widget for a Text Input widget, which does not include the debounce delay. It is also possible to use a Toast widget as a delay buffer between the submit button press and the query execution to ensure that enough time passes that the full text is included.

Return to top


Functions

My function does not work

Functions in Slate are basic JavaScript executed in a sandbox from the rest of the application. They are purely user-generated code, so the majority of issues related to functions will at root be issues of misunderstanding or otherwise failing to correctly implement the desired functionality in JavaScript.

To troubleshoot, perform the following steps:

The basic steps of debugging are to simplify the function until it behaves in an expected way, then add back complexity in small steps until the unexpected behavior returns. At this point you have identified the point where further research is required to understand the correct way to implement the desired behavior.

An additional tool for debugging is the Chrome DevTools Debugger ↗. Consider also a related section on Debug using DevTool Add “breakpoints” to your function with a debugger; statement.

Then, with the Chrome DevTools panel open, click the Test button in the Function window. The function execution will pause at the breakpoint, and you can continue to step through the function code and view the values of variables.

Return to top


My function is not running when expected

Functions interact in unintuitive ways with the Events framework because in normal usage they are not called but instead are executed by the Dependency Graph when they are out-of-date with their inputs and their output is rendered to JSON for consumption by downstream dependencies.

To troubleshoot, perform the following steps:

If a function is behaving in an unexpected manner, double check that you understand how they fit in to the Dependency Graph and Event Framework /documentation/product/slate/application-functionality#best-practices-and-common-patterns-for-javascript-functions.

It's very rare to need a pattern where an Event calls the [f_myFunction].run action. An application attempting to rely on this pattern should be refactored to use the normal resolution of the dependency graph. Instead of triggering the function directly, instead update an upstream dependency, for example by triggering a query or setting the value of a referenced variable.

Return to top


Map widget

My GEOJSON is not rendering

The map widget supports rendering properly defined geojson map features, such as points and geometries. These can be dynamically generated or retrieved from a database, however the formatting is specific and can be difficult to achieve if it is created by hand or through a novel algorithm.

To troubleshoot, perform the following steps:

Review the GeoJSON in the Map Widget reference example. Try searching for it on your Foundry instance and if it is not available, file an issue.

Return to top


Styling

My style is not applied, or how do I override style [x]?

All styling in Slate ultimately translates into CSS. You can inspect any element of your application with the Chrome Inspector tool (Right-click > Inspect on any element) to see what classes are applied to that element and understand the document hierarchy.

To troubleshoot, perform the following steps:

Review the documentation section on Style to understand more deeply how and where styles are defined, applied, and rendered in Slate.

Return to top


Layout

Application rendering issues

In some configurations, if you attempt to configure a widget to be a “dynamic” width and height, instead you will find your widget rendered in a small box when the page loads. Triggering the [w_myWidget.resize] action causes the widget to render to the expected size.

This behavior is caused by a collision between CSS specifying the width and height of various widget elements as percentages - normally 100% - and the Flex property on one or more parent containers. With these collisions, Slate is unable to determine the correct dimensions of the element enclosing the widget at render-time and therefore renders the widget too small.

To troubleshoot, perform the following steps:

The appropriate pattern for implementing responsive widget dimensions is to only use the Flex configuration settings on the parent container(s) and child widgets. Do not set other width or height properties manually through CSS. To resolve, start with root child widget(s) and move up through all the parent widgets, removing any positional or dimensional CSS rules.

You can use margin and padding properties to inset or otherwise align child widgets. If you are comfortable with Flexbox CSS rules, you can use the Chrome Inspector to identify which elements and classes to target and provide overrides or additional Flexbox rules to achieve the exact desired behavior.

Return to top


My Slate app will not print / How do I export my App

Slate is optimized for rapid application development. The underlying framework imposes few limitations on the configurability of layout our styling. As a result, Slate is unable to generically render all applications in a manner suitable for print media or export. Application developers will need to invest time on an app-by-app basis to support printing.

To troubleshoot, perform the following steps:

The first and best option is to consider why there is a requirement or request to print your app. Do your users simply need a way to preserve the view they've created and reference it later or use it during a presentation?

In this case, consider using (or highlighting to your users to use) the built-in Get Shareable Link functionality. In "View" mode, it is under the Action menu. This link creates a unique URL with an ID that will, whenever the link is loaded, return all the page widgets to the state they were in when the link was generated. This means, for example, a set of input widgets will default to the inputs configured by the user and feed into the queries, etc.

If you really must print or export, then you will need to define additional media CSS styles to help your application render appropriately.

To start, you'll need to add at least this to the Global Styles:

@media print {
  @page {
    size: A4;
  }

  html, body , .ws-root-container.ws-sandbox {
    height: 600mm !important;
  }

  sl-app-view-actions {
    display: none !important;
  }
}

Printing responsive applications or any application with complex styling or layouts will be very difficult. In these cases, consider creating a “Print View” as a separate application that receives necessary inputs through URL parameters and generates a simplified view optimized for printing. This will increase the development cost and maintenance burden but will result in satisfactory behavior.

Return to top


Performance

My application is slow to load or sluggish in edit mode

Like all web applications, Slate uses browser resources in the end user's computer to execute JavaScript code and render the document model (DOM) defined in HTML with the styles specified in CSS. Some portion of these resources are constant; they are the overhead of working within the Slate framework. However, in cases of poor performance, the root cause is most often a form of application overload where the configuration defined in the course of developing the application demands too many resources from the browser to either render the application, execute the JavaScript, or simply store in memory the results of many large queries.

In some cases, a single function or query might be the cause. In this case, you can use the performance metrics in the Dependencies tab of an application to look at the Time in Node for various queries and functions. This metric represents the duration spent resolving that particular node on page load, which can help identify likely candidates for application bottlenecks.

In general, a best practice is to favor lightweight, well-bounded, single-serving applications and create large workflows or applications out of “clusters” of small application with deep linking between them.

Return to top