The following are a few frequently asked questions about Slate. For general information, see Slate documentation.
--
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:
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.
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.
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.
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:
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:
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:
20s
, you can be sure the failure is because Slate has timed out the query.{{#if}}
statements or through logic in a function against null
values or other edge cases.Event Madness
is relevant.When queries time out, there are two primary factors at play:
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.
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.
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.
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:
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.
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.
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.
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.
[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.
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.
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.
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.
Slate saves the application configuration as a JSON document, which generally has a size limit of 2,000,000 bytes of UTF-8 encoded characters. Attempts to save a Slate application with a configuration above the size limit will fail, and changes will need to be made to the application configuration to decrease the size. The JSON document of an opened Slate application can be retrieved through export.
Every part of a Slate application takes up configuration size to some degree, and editors should be conscious about both the scale of Slate applications being built, and the resources being embedded in the application configuration. The following are prevalent reasons for the overuse of configuration size, along with proposed solutions:
Upload the image to Foundry and reference the image using the Image widget.
Consider refactoring functions to extract common logic into function libraries.
Additionally, large functions may be better suited as Foundry Functions consumed via the Platform editor.
While function libraries are shared across all pages of a Slate application to conserve space, javascript libraries can be quite large. Either refactor custom libraries to use shared logic, or use minified versions of external libraries.