## Blocklet export api 改动

新约定， 如果 blocklet 的 export api 返回数据中，包含了 `dependentComponents`, 在用户选中了这个资源时， 会自动选中这些依赖的组件。

example：

```js
res.json({
  resources: [
    ...list.map((x) => ({
      ...x,
      id: `application-${x._id}`,
      name: `${x.name} (as Application)`,
      dependentComponents: [
        'error-did',
        'z8ia1mAXo8ZE7ytGF36L5uBf9kD2kenhqFGp9',
        'z2qZyjnsRffFtn2PDnDwDHTRbAu53RpKqDtFZ',
        'z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk',
      ],
    })),
    ...list.map((x) => ({
      ...x,
      id: `tool-${x._id}`,
      name: `${x.name} (as Tool)`,
      dependentComponents: ['error-did', 'z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk'],
    })),
    ...list.map((x) => ({
      ...x,
      id: `template-${x._id}`,
      name: `${x.name} (as Template)`,
    })),
    ...list.map((x) => ({
      ...x,
      id: `example-${x._id}`,
      name: `${x.name} (as Example)`,
    })),
  ],
});
return;
```

## BlockletStudio Component example

因为 iframe 的加载会有过程, 推荐在点击按钮让渲染 loading, 在 onOpened 取消 loading:

```tsx
import { Icon } from '@iconify-icon/react';
import ArrowUp from '@iconify-icons/tabler/arrow-big-up-line';
import { Box, IconButton, CircularProgress as Spinner, svgIconClasses } from '@mui/material';
import { useState } from 'react';

import { AI_STUDIO_COMPONENT_DID } from '../../libs/constants';
import { BlockletStudio } from './blocklet-studio';

export default function Exporter() {
  const [showCreateResource, setShowCreateResource] = useState(false);
  const [opening, setOpening] = useState(false);
  const handleShowDialog = () => {
    setOpening(true);
    setShowCreateResource(true);
  };

  return (
    <>
      <IconButton
        sx={{
          position: 'relative',
          minWidth: 40,
          minHeight: 40,
          borderRadius: '100%',
          [`.${svgIconClasses.root}`]: {
            color: 'text.secondary',
          },
        }}
        onClick={handleShowDialog}>
        {opening ? <Spinner size={16} /> : <Box component={Icon} icon={ArrowUp} style={{ fontSize: 24 }} />}
      </IconButton>
      <BlockletStudio
        mode="dialog"
        tenantScope="test-tenant-scope-id-2"
        title="demo aigne project"
        description={'This is a demo project for "aigne" blocklet.'}
        note='This is a demo project for "aigne" blocklet.'
        introduction="the introduction."
        componentDid={AI_STUDIO_COMPONENT_DID}
        // 新增的参数，用于禁用选择组件
        dependentComponentsMode="readonly"
        componentsTitle="Components"
        resourcesTitle="Add Files"
        // 透传到 get blocklet resource 的参数
        resourcesParams={{ name: 'test-project', ok: true }}
        open={showCreateResource}
        setOpen={setShowCreateResource}
        onConnected={() => alert('connected')}
        onUploaded={() => alert('uploaded')}
        onReleased={() => alert('released')}
        onOpened={() => setOpening(false)}
        // 默认选中的组件
        components={[
          { did: 'z8ia3xzq2tMq8CRHfaXj1BTYJyYnEcHbqP8cJ', included: true, required: true },
          { did: 'z2qZyjnsRffFtn2PDnDwDHTRbAu53RpKqDtFZ', included: true, required: false },
        ]}
        // 默认选中的资源
        resources={{
          z8iZpog7mcgcgBZzTiXJCWESvmnRrQmnd3XBB: [
            'template-448698592710885376',
            'template-448696391418511360',
            'template',
            'example-448698592710885376',
          ],
        }}
      />
    </>
  );
}
```
