Skip to main content

AMA Custom Blocks Contest Edition #3 - Releasing your block


The Custom Blocks contest deadline is approaching! Do you have questions about releasing or debugging your block? We’re hosting our third live Ask Me Anything (AMA) session in this thread on Wednesday (6/24) at 11am PT.

Billy Littlefield and Tim Deng from our platform engineering team will be ready to answer any development questions you have.

We’ll be picking 3 questions at random to win a $40 Amazon gift card. Any solutions offered by the community will be included in the draw as well. You can even start posting your questions now, and we’ll be answering questions live from 11am - 11:30am PT on Wednesday. See you there!

35 replies

Kamille_Parks11
Forum|alt.badge.img+15

The block I’m building will require an external library’s CSS to be imported/loaded. My original plan was to install Webpack to do this, but there weren’t any Blocks examples that use it. To your knowledge, would I be able to install webpack as I would with any other React app, or would the Custom Blocks setup require a different approach? Does the way Blocks are transpiled interfere with Webpack?


  • New Participant
  • 2 replies
  • June 24, 2020

I’m aware that there are official airtable widgets for building UI, but can I use 3rd-party UI widgets library? (MIT licensed)


There was some discussion about writing tests for custom blocks a while ago. I’m still finding the most success with the “test mode” that I had suggested to the original poster, but I’m curious if you could expand on Kasra’s second idea:

If I have a layout function that makes calls to Custom Block APIs, wouldn’t I still need access to those functions outside of the Airtable environment to perform a unit test? Or was Kasra’s suggestion more along the lines of a layout function would be called before passing to an Airtable API and the unit test could be used as a way to ensure valid information is being passed in?


Do you have any advice or guidelines on how to present errors to users? I know some of the examples include permissions and other checks before performing operations for Airtable-specific API calls. More generally though, can you share best practices, UI-wise, on how to present users with error information?

Some ideas I can think of are:

  • Yes/no or Ok/cancel dialogs
  • “Update settings before continuing…” (require a ‘re-run’)
  • In-line option to dynamically change a setting that automatically re-tries
  • Attempt to process all “requests” and provide a list of successes/errors at the end

Obviously, some/all/none of these might work for different use cases. I’m trying to see if there’s any built-in UI components (I don’t think so?) or best ways to incorporate custom components (like react-bootstrap).


Hi

I’ve just finished a very first version of Image Annotation block. Here is a demo: https://www.youtube.com/watch?v=1O6hSDny2TA. Could you give me some feedback on what to improve before releasing it?

And some more quesitons:

  1. Is it possible to specify not only fields, but also field values in RecordQueryResultOpts? For example, to get only records which have a specific value in a specific field?
  2. How can I create a table with a field that will be linked to another table? What options should I use when calling 'base.unstable_createTableAsync`
  3. Is it possible to import a css file in the component? Can I extend the build/dev configs somehow?
  4. Do you provide some tools to log errors in Custom Blocks or it will be better to use something like Sentry for now?

Kamille_Parks11
Forum|alt.badge.img+15

I have a button that creates a new record using createRecordAsync() when clicked. I would like to open the newly created record once this is done using expandRecord(), but createRecordAsync() only provides the record ID and not the record object. Loading the new record using useRecordById() seems to break hook rules; this is all in an async function. Any advice?


Kamille_Parks11 wrote:

I have a button that creates a new record using createRecordAsync() when clicked. I would like to open the newly created record once this is done using expandRecord(), but createRecordAsync() only provides the record ID and not the record object. Loading the new record using useRecordById() seems to break hook rules; this is all in an async function. Any advice?


@Kamille_Parks
I think you’ll need to do those as separate actions. So create the record and close out that async action. You have your recordID, so in a new action use that record to expand it. Trying to access a newly created record within the same async block that it is being created generally isn’t going to work because you aren’t guaranteed to have the record available yet. But once you’ve awaited the return of the async function, you can be guaranteed to have that recordID to work with.

It’s also just generally good practice to segment out actions like this. It’s the universal temptation for developers to get as much done in a single go or block of code as possible. It feels more efficient, and it feels quicker, like you can get more done with fewer lines of code. That’s probably true; but in the long run, using more lines of code, and more tedious-feeling cycles of “doing an action --> saving the result --> doing some new action on that result” will result in generally more resilient and easier to understand/modify/expand code.


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

Thank you for implementing my suggestion use a random drawing for awarding the gift card!


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

Is there a way for a block to put up an alert outside the context of the block itself?

For example, if a block is monitoring a table and notices an error condition, is there some way for the block to notify the user, even if the user does not look at the block? Modal dialog boxes seem to work only in the context of the block, and alert is very ugly and probably best for debugging purposes.


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

It appears that in order to have a remote release of a block, the block author needs to be a collaborator with creator permissions in the target base. Can you confirm this?

Is there a way to install a custom block without the developer being a creator?
Does the block remain after the developer/creator is no longer a collaborator?


Kamille_Parks11 wrote:

The block I’m building will require an external library’s CSS to be imported/loaded. My original plan was to install Webpack to do this, but there weren’t any Blocks examples that use it. To your knowledge, would I be able to install webpack as I would with any other React app, or would the Custom Blocks setup require a different approach? Does the way Blocks are transpiled interfere with Webpack?


There was a little discussion about external CSS files and Webpack in this topic thread and the answer seems to be: not currently possible. It seems like external CSS can only be loaded using loadCSSFromString or loadCSSFromURLAsync.

I’m curious to hear from the Airtable folks how block transpiling interacts with Webpack and/or other command-line tools.


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

I noticed that when I click the “Custom” button next to the name of a custom block, it shows

  • the name of the block developer (based on the Airtable account)
  • the email address of the block developer (based on the Airtable account)
  • the date of the last update

Is all of this information set automatically? Can we change it to display a different name or email address?


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

I noticed that there is a version number in block.json. Is this version number displayed to the block user anywhere?

Are there guidelines for where to display version information to the user?

Could it be included along with the contact info for the block developer when the “Custom” button is clicked?


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

It looks like the .block folder lists remotes, including base app ids. I’d rather not include my app ids in a public git repository.

However, this folder is not included in the .gitignore file by default.
What are the implications of adding this folder to the .gitignore file?
How hard will it be for someone to re-create my custom block if I add this folder to .gitignore?


  • Participating Frequently
  • 9 replies
  • June 24, 2020

Hey y’all, Billy and I will be live for the next 30 minutes to answer your questions!


  • Participating Frequently
  • 9 replies
  • June 24, 2020
Yuriy_Klyuch wrote:

I’m aware that there are official airtable widgets for building UI, but can I use 3rd-party UI widgets library? (MIT licensed)


Yes, you can use third party open source packages in the contest as long as you are using it in accordance with their license terms. You can refer to our contest rules if you have any further queries!


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

Several times when I try to create a new block from the command line, I get npm enoent errors, and can’t create the new block. I can’t tell any difference between when it works and when it doesn’t. Sometimes I have to come back hours later and try again.

Any insight?


Kamille_Parks11 wrote:

The block I’m building will require an external library’s CSS to be imported/loaded. My original plan was to install Webpack to do this, but there weren’t any Blocks examples that use it. To your knowledge, would I be able to install webpack as I would with any other React app, or would the Custom Blocks setup require a different approach? Does the way Blocks are transpiled interfere with Webpack?


Hi Kamille! The way that the @airtable/blocks-cli builds the blocks is currently not configurable, so the webpack approach won’t work in the current state. The SDK provides a couple of ways to include CSS, though – loadCSSFromString & loadCSSFromURLAsync


Matthew_Thomas wrote:

Do you have any advice or guidelines on how to present errors to users? I know some of the examples include permissions and other checks before performing operations for Airtable-specific API calls. More generally though, can you share best practices, UI-wise, on how to present users with error information?

Some ideas I can think of are:

  • Yes/no or Ok/cancel dialogs
  • “Update settings before continuing…” (require a ‘re-run’)
  • In-line option to dynamically change a setting that automatically re-tries
  • Attempt to process all “requests” and provide a list of successes/errors at the end

Obviously, some/all/none of these might work for different use cases. I’m trying to see if there’s any built-in UI components (I don’t think so?) or best ways to incorporate custom components (like react-bootstrap).


Hi Matthew!

Some good guidelines to follow:

  • Disable interactions that the user doesn’t have permission for, rather than checking onClick
    • You can supplement this disabled state with a Tooltip, or including error text in a sticky footer
  • Similarly, disable interactions if the settings configuration is invalid and would preclude the interaction from successfully completing. In this case, using a TextButton in a sticky footer to open the settings could be a nice touch.
    • If the operation consists of multiple line-items, and only some are invalid, you should highlight the invalid items inline (potentially with a “quick-fix” button, depending on how complex the “fix” is)
  • If you don’t know whether an operation will succeed until runtime, a “Results” screen showing successes & failures is a good strategy (similar to the SendGrid block)

We have a number of UI components that can help with some of these interactions this built into the SDK:

You’re also welcome to use third-party libraries as you would in other apps (e.g. npm install cool-ui-library ). If you have any feedback about the UI components that do exist in the SDK (see the docs site for a full list) we’d love to hear it!


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

When invoking a custom block from a button, is there a way to tell when a button has been pressed again? I can tell if a button for a different record has been pressed because I can compare the current record with the previous record, but I would also like to be able to tell if the button for the same record has been pressed again.

Use case: the user presses the button to start a wizard, which progresses through some screens. If the user presses the button again, I would like to start the wizard over again from the beginning.


  • Participating Frequently
  • 9 replies
  • June 24, 2020
Matthew_Thomas wrote:

There was some discussion about writing tests for custom blocks a while ago. I’m still finding the most success with the “test mode” that I had suggested to the original poster, but I’m curious if you could expand on Kasra’s second idea:

If I have a layout function that makes calls to Custom Block APIs, wouldn’t I still need access to those functions outside of the Airtable environment to perform a unit test? Or was Kasra’s suggestion more along the lines of a layout function would be called before passing to an Airtable API and the unit test could be used as a way to ensure valid information is being passed in?


I think what Kasra was getting at is closer to your latter point – writing unit tests against stateless logic which doesn’t interact directly with the base (e.g. testing data manipulation logic that happens before sending to the base or after fetching from the base). You could use mock data and/or stubs to help seed the functions you’re testing.

Improving the testability of blocks & coming up with a more concrete guide of best practices is something we’re thinking about for the future!


  • Participating Frequently
  • 9 replies
  • June 24, 2020
kuovonne wrote:

Is there a way for a block to put up an alert outside the context of the block itself?

For example, if a block is monitoring a table and notices an error condition, is there some way for the block to notify the user, even if the user does not look at the block? Modal dialog boxes seem to work only in the context of the block, and alert is very ugly and probably best for debugging purposes.


Unfortunately that isn’t possible; blocks operate in an iframe with a separate context from the rest of the page. We’re thinking about other ways to provide notifications (e.g. toasts), but that isn’t something that currently exists.


Kamille_Parks11 wrote:

I have a button that creates a new record using createRecordAsync() when clicked. I would like to open the newly created record once this is done using expandRecord(), but createRecordAsync() only provides the record ID and not the record object. Loading the new record using useRecordById() seems to break hook rules; this is all in an async function. Any advice?


Jeremy’s answer should solve this – if you store the newly created record ID in some local state, then on a future re-render the records returned from useRecords should contain the new record, and you can call expandRecord.

If you did want to fetch the new record in the same block of code, I think you could do so doing something like this:

const newRecordId = await table.createRecordAsync(...)
const freshQueryResult = await table.selectRecordsAsync()
expandRecord(freshQueryResult.getRecordById(newRecordId))

But depending on how often this gets called, it may be better to just wait for the next render cycle.


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020
Billy_Littlefie wrote:

Jeremy’s answer should solve this – if you store the newly created record ID in some local state, then on a future re-render the records returned from useRecords should contain the new record, and you can call expandRecord.

If you did want to fetch the new record in the same block of code, I think you could do so doing something like this:

const newRecordId = await table.createRecordAsync(...)
const freshQueryResult = await table.selectRecordsAsync()
expandRecord(freshQueryResult.getRecordById(newRecordId))

But depending on how often this gets called, it may be better to just wait for the next render cycle.


What determines how soon a new render occurs?


kuovonne
Forum|alt.badge.img+17
  • Brainy
  • 5996 replies
  • June 24, 2020

How do you recommend showing a <Loader scale={0.3} /> while doing a fetch?
Do I use state to keep track of when the fetch has been sent, and then change state when the response is received? Is there an easier way?


Reply