Skip to main content

AMA Custom Blocks Contest Edition #3 - Releasing your block


Show first post

35 replies

Forum|alt.badge.img+5
  • Participating Frequently
  • 9 replies
  • June 24, 2020
kuovonne wrote:

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?


That information is set automatically, by the person who last runs block release . Like you noted, it’s tied to an Airtable account so you can’t manually edit it (but you can have a creator on your base release a version of the block to change it to their name and email).


Forum|alt.badge.img+4
kuovonne wrote:

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?


That version isn’t exposed anywhere, but can be used internally (e.g. to supplement your commit history). When you block release, all installations of that block will reference the new code, so it isn’t possible for users to be on different versions of the same block currently. We’re thinking about ways to expose when a new release has been pushed up to the consumer!

Under the hood, versioning is still something that can be done - for example if you there are required schema changes you’d like to enforce upon a new release. One strategy you could take here is to store it version in GlobalConfig, then perform some logic that runs in your root component and can perform necessary operations if needed –

e.g.

if (globalConfig.get('blockVersion') < 2) {
    globalConfig.setPathsAsync([
        {path: 'someNewPath', value: 'default'},
        {path: 'blockVersion', value: 2}
    ])
}

This could be wrapped into a custom useBlockVersion hook or similar.


Forum|alt.badge.img+4
kuovonne wrote:

What determines how soon a new render occurs?


It largely depends on how the block is architected, but here are some examples –

If you’re using a standard react useState hook, a rerender will trigger anytime you modify the state using the returned setter (e.g. const [value, setValue] = useState(0) whenever setValue is called).

If you’re using the useRecords hook, a rerender will fire anytime a record is deleted / added in the base, or cell values change, or record colors change (this includes changes that propagate from the block itself). For the hooks provided by the SDK, this is determined by the watchable keys. This is a little in the weeds, but you can see which watchable keys useRecords uses here. You can even define your own triggers by using useWatchable on an Airtable model directly


Forum|alt.badge.img+4
kuovonne wrote:

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?


Hmm, I’m not sure what might be causing this off the top of my head. This is on block init ? If this continues occurring or you’re able to reproduce more reliably, please write in to blocks@airtable.com so we can try to debug further


Forum|alt.badge.img+5
  • Participating Frequently
  • 9 replies
  • June 24, 2020
kuovonne wrote:

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?


Adding your .block folder to your git ignore will prevent it from syncing to your git remote, but it’ll still be on your local computer. If you’re the only one working on the custom block and you only use one computer, this isn’t an issue (otherwise, everyone else collaborating on your block will need the same app and base IDs). If you’re concerned about other users, ignoring your .block folder should be fine! They can choose “Remix from GitHub” when creating a custom block, and it will automatically create a .block folder for them.


Forum|alt.badge.img+4
kuovonne wrote:

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.


Ah, interesting use case. With the useRecordActionData hook, the data always will be the latest press, so you wouldn’t register a separate click. I think you can register a callback directly, though, using registerRecordActionDataCallback which should execute the registered callback on every push (even if its the same button).

I wonder if there’s value in providing a timestamp or ID in the action payload to distinguish between these clicks using the hook.

EDIT: Another solution here would be to use a usePrevious hook, e.g.

function usePrevious(value) {
	const ref = React.useRef();
	React.useEffect(() => {
		ref.current = value;
	});
	return ref.current;
}

This way, you can compare the value returned by useRecordActionData() for subsequent presses. Even if the same record is clicked, the object returned by useRecordActionData on a subsequent button press will be a new object compared to the value cached by usePrevious.

function MyComponent() {
    const buttonData = useRecordActionData();
    const lastButtonData = usePrevious(buttonData);
    useEffect(() => {
        if (buttonData !== lastButtonData && buttonData) {
            // perform logic for button press
        }
    }, [buttonData, lastButtonData])
    
   // ... rest of component ...
}

Forum|alt.badge.img+4
kuovonne wrote:

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?


I think that’s the most logical way – barebones example:

function MyComponent() {
    const [isLoading, setIsLoading] = useState(false);
    
    function fetchTheThing() {
        setIsLoading(true);
        
        fetch('example.com').then(response => {
            // do stuff with response
            setIsLoading(false);
        })
    }

    return (
        <Box>
            {isLoading ? (
                <Loader />
            ) : (
                <RestOfApp />
            )}
        </Box>
    )
}

Forum|alt.badge.img+4
kuovonne wrote:

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?


Correct, currently only creators can create, release, and install blocks in a given base. It’s not currently possible to install a custom block without creator permissions. If the developer/creator is removed from the base, the block will remain. Releasing, publishing, and sharing blocks is something we’re thinking about for the future in order to reduce friction for both the developer and consumers.


Forum|alt.badge.img+5
  • Participating Frequently
  • 9 replies
  • June 24, 2020

And that’s a wrap! If you have any further questions, you can always find us in the custom blocks beta forum. The winners for this week are @Yuriy_Klyuch, @kuovonne, and @Kirill_Madorin!

With the contest deadline fast approaching (July 6th), we’ll be hosting our last AMA in the custom blocks contest series next week with a twist! Instead of AMA, we’ve got a fun “AYA” format planned. The post will be up EoD Friday and will be open until 6pm PT on Thursday, July 1. We’ll be giving out Amazon gift cards to three of the most insightful posts. Stay tuned!


Forum|alt.badge.img+4
Kirill_Madorin wrote:

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?

Exciting to see your block in action! I’ll have to refrain from providing feedback now, assuming this is an entrant in the current blocks contest. Happy to answer your questions, though!

  1. It’s not currently possible to specify field values using RecordQueryResultOpts, but if you create a view in the main product that performs this filtering, you can select records from just that view.
  2. Unfortunately, linked record fields are not included in the current scope of metadata writes (along with formulaic fields) - some work still needs to be done on what that API looks like.
  3. You can’t currently configure the build, but CSS can be loaded using loadCSSFromString or loadCSSFromURLAsync.
  4. We don’t currently provide any built-in tooling for error logging. In theory, you could log errors to an “Errors” table in the base, but that may not be the best approach depending on your use-case.

Reply