├── .codeclimate.yml ├── .dockerignore ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── actions │ ├── docker-build-push │ │ └── action.yml │ └── pnpm-install │ │ └── action.yml └── workflows │ ├── docker-push.yml │ ├── integration-tests.yml │ ├── linting.yml │ ├── manual-preview.yml │ ├── preview-cleanup.yml │ ├── templates │ └── preview-template.yaml │ └── unit-tests.yml ├── .gitignore ├── .gitpod.yml ├── .husky ├── commit-msg ├── install.mjs └── pre-commit ├── .idea ├── modules.xml └── teable.iml ├── .ncurc.yml ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── AGPL_LICENSE ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── apps ├── nestjs-backend │ ├── .eslintrc.js │ ├── .gitignore │ ├── .idea │ │ ├── modules.xml │ │ └── nestjs-backend.iml │ ├── README.md │ ├── nest-cli.json │ ├── package.json │ ├── src │ │ ├── app.module.ts │ │ ├── bootstrap.ts │ │ ├── cache │ │ │ ├── cache.module.ts │ │ │ ├── cache.provider.ts │ │ │ ├── cache.service.ts │ │ │ └── types.ts │ │ ├── configs │ │ │ ├── auth.config.ts │ │ │ ├── base.config.ts │ │ │ ├── bootstrap.config.ts │ │ │ ├── cache.config.ts │ │ │ ├── config.module.ts │ │ │ ├── config.spec.ts │ │ │ ├── env.validation.schema.ts │ │ │ ├── logger.config.ts │ │ │ ├── mail.config.ts │ │ │ ├── oauth.config.ts │ │ │ ├── storage.ts │ │ │ └── threshold.config.ts │ │ ├── const.ts │ │ ├── custom.exception.ts │ │ ├── db-provider │ │ │ ├── aggregation-query │ │ │ │ ├── aggregation-function.abstract.ts │ │ │ │ ├── aggregation-function.interface.ts │ │ │ │ ├── aggregation-query.abstract.ts │ │ │ │ ├── aggregation-query.interface.ts │ │ │ │ ├── postgres │ │ │ │ │ ├── aggregation-function.postgres.ts │ │ │ │ │ ├── aggregation-query.postgres.ts │ │ │ │ │ ├── multiple-value │ │ │ │ │ │ └── multiple-value-aggregation.adapter.ts │ │ │ │ │ └── single-value │ │ │ │ │ │ └── single-value-aggregation.adapter.ts │ │ │ │ └── sqlite │ │ │ │ │ ├── aggregation-function.sqlite.ts │ │ │ │ │ ├── aggregation-query.sqlite.ts │ │ │ │ │ ├── multiple-value │ │ │ │ │ └── multiple-value-aggregation.adapter.ts │ │ │ │ │ └── single-value │ │ │ │ │ └── single-value-aggregation.adapter.ts │ │ │ ├── base-query │ │ │ │ ├── abstract.ts │ │ │ │ ├── base-query.postgres.ts │ │ │ │ └── base-query.sqlite.ts │ │ │ ├── db.provider.interface.ts │ │ │ ├── db.provider.ts │ │ │ ├── duplicate-table │ │ │ │ ├── abstract.ts │ │ │ │ ├── duplicate-attachment-table-query.abstract.ts │ │ │ │ ├── duplicate-attachment-table-query.postgres.ts │ │ │ │ ├── duplicate-attachment-table-query.sqlite.ts │ │ │ │ ├── duplicate-query.postgres.ts │ │ │ │ └── duplicate-query.sqlite.ts │ │ │ ├── filter-query │ │ │ │ ├── cell-value-filter.abstract.ts │ │ │ │ ├── cell-value-filter.interface.ts │ │ │ │ ├── filter-query.abstract.ts │ │ │ │ ├── filter-query.interface.ts │ │ │ │ ├── postgres │ │ │ │ │ ├── cell-value-filter │ │ │ │ │ │ ├── cell-value-filter.postgres.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── multiple-value │ │ │ │ │ │ │ ├── multiple-boolean-cell-value-filter.adapter.ts │ │ │ │ │ │ │ ├── multiple-datetime-cell-value-filter.adapter.ts │ │ │ │ │ │ │ ├── multiple-json-cell-value-filter.adapter.ts │ │ │ │ │ │ │ ├── multiple-number-cell-value-filter.adapter.ts │ │ │ │ │ │ │ └── multiple-string-cell-value-filter.adapter.ts │ │ │ │ │ │ └── single-value │ │ │ │ │ │ │ ├── boolean-cell-value-filter.adapter.ts │ │ │ │ │ │ │ ├── datetime-cell-value-filter.adapter.ts │ │ │ │ │ │ │ ├── json-cell-value-filter.adapter.ts │ │ │ │ │ │ │ ├── number-cell-value-filter.adapter.ts │ │ │ │ │ │ │ └── string-cell-value-filter.adapter.ts │ │ │ │ │ └── filter-query.postgres.ts │ │ │ │ └── sqlite │ │ │ │ │ ├── cell-value-filter │ │ │ │ │ ├── cell-value-filter.sqlite.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── multiple-value │ │ │ │ │ │ ├── multiple-boolean-cell-value-filter.adapter.ts │ │ │ │ │ │ ├── multiple-datetime-cell-value-filter.adapter.ts │ │ │ │ │ │ ├── multiple-json-cell-value-filter.adapter.ts │ │ │ │ │ │ ├── multiple-number-cell-value-filter.adapter.ts │ │ │ │ │ │ └── multiple-string-cell-value-filter.adapter.ts │ │ │ │ │ └── single-value │ │ │ │ │ │ ├── boolean-cell-value-filter.adapter.ts │ │ │ │ │ │ ├── datetime-cell-value-filter.adapter.ts │ │ │ │ │ │ ├── json-cell-value-filter.adapter.ts │ │ │ │ │ │ ├── number-cell-value-filter.adapter.ts │ │ │ │ │ │ └── string-cell-value-filter.adapter.ts │ │ │ │ │ └── filter-query.sqlite.ts │ │ │ ├── group-query │ │ │ │ ├── format-string.ts │ │ │ │ ├── group-query.abstract.ts │ │ │ │ ├── group-query.interface.ts │ │ │ │ ├── group-query.postgres.ts │ │ │ │ └── group-query.sqlite.ts │ │ │ ├── index-query │ │ │ │ └── index-abstract-builder.ts │ │ │ ├── integrity-query │ │ │ │ ├── abstract.ts │ │ │ │ ├── integrity-query.postgres.ts │ │ │ │ └── integrity-query.sqlite.ts │ │ │ ├── postgres.provider.ts │ │ │ ├── search-query │ │ │ │ ├── abstract.ts │ │ │ │ ├── get-offset.ts │ │ │ │ ├── search-index-builder.postgres.ts │ │ │ │ ├── search-index-builder.sqlite.ts │ │ │ │ ├── search-query.postgres.ts │ │ │ │ ├── search-query.sqlite.ts │ │ │ │ └── types.ts │ │ │ ├── sort-query │ │ │ │ ├── function │ │ │ │ │ ├── sort-function.abstract.ts │ │ │ │ │ └── sort-function.interface.ts │ │ │ │ ├── postgres │ │ │ │ │ ├── multiple-value │ │ │ │ │ │ ├── multiple-datetime-sort.adapter.ts │ │ │ │ │ │ ├── multiple-json-sort.adapter.ts │ │ │ │ │ │ └── multiple-number-sort.adapter.ts │ │ │ │ │ ├── single-value │ │ │ │ │ │ ├── date-sort.adapter.ts │ │ │ │ │ │ ├── json-sort.adapter.ts │ │ │ │ │ │ └── string-sort.adapter.ts │ │ │ │ │ ├── sort-query.function.ts │ │ │ │ │ └── sort-query.postgres.ts │ │ │ │ ├── sort-query.abstract.ts │ │ │ │ ├── sort-query.interface.ts │ │ │ │ └── sqlite │ │ │ │ │ ├── multiple-value │ │ │ │ │ ├── multiple-datetime-sort.adapter.ts │ │ │ │ │ ├── multiple-json-sort.adapter.ts │ │ │ │ │ └── multiple-number-sort.adapter.ts │ │ │ │ │ ├── single-value │ │ │ │ │ ├── date-sort.adapter.ts │ │ │ │ │ ├── json-sort.adapter.ts │ │ │ │ │ └── string-sort.adapter.ts │ │ │ │ │ ├── sort-query.function.ts │ │ │ │ │ └── sort-query.sqlite.ts │ │ │ └── sqlite.provider.ts │ │ ├── event-emitter │ │ │ ├── decorators │ │ │ │ └── emit-controller-event.decorator.ts │ │ │ ├── event-emitter.module.ts │ │ │ ├── event-emitter.service.ts │ │ │ ├── event-job │ │ │ │ ├── event-job.module.ts │ │ │ │ └── fallback │ │ │ │ │ ├── event-emitter.ts │ │ │ │ │ ├── fallback-queue.module.ts │ │ │ │ │ ├── fallback-queue.service.ts │ │ │ │ │ └── local-queue.provider.ts │ │ │ ├── events │ │ │ │ ├── base │ │ │ │ │ └── base.event.ts │ │ │ │ ├── core-event.ts │ │ │ │ ├── event.enum.ts │ │ │ │ ├── index.ts │ │ │ │ ├── op-event.ts │ │ │ │ ├── space │ │ │ │ │ ├── collaborator.event.ts │ │ │ │ │ └── space.event.ts │ │ │ │ ├── table │ │ │ │ │ ├── field.event.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── record.event.ts │ │ │ │ │ ├── table.event.ts │ │ │ │ │ └── view.event.ts │ │ │ │ └── user │ │ │ │ │ └── user.event.ts │ │ │ ├── interceptor │ │ │ │ └── event.Interceptor.ts │ │ │ └── listeners │ │ │ │ ├── action-trigger.listener.ts │ │ │ │ ├── attachment.listener.ts │ │ │ │ ├── base-permission-update.listener.ts │ │ │ │ ├── collaborator-notification.listener.ts │ │ │ │ ├── pin.listener.ts │ │ │ │ ├── record-history.listener.ts │ │ │ │ └── trash.listener.ts │ │ ├── features │ │ │ ├── access-token │ │ │ │ ├── access-token.controller.spec.ts │ │ │ │ ├── access-token.controller.ts │ │ │ │ ├── access-token.encryptor.ts │ │ │ │ ├── access-token.module.ts │ │ │ │ ├── access-token.service.spec.ts │ │ │ │ └── access-token.service.ts │ │ │ ├── aggregation │ │ │ │ ├── aggregation.module.ts │ │ │ │ ├── aggregation.service.spec.ts │ │ │ │ ├── aggregation.service.ts │ │ │ │ └── open-api │ │ │ │ │ ├── aggregation-open-api.controller.spec.ts │ │ │ │ │ ├── aggregation-open-api.controller.ts │ │ │ │ │ ├── aggregation-open-api.module.ts │ │ │ │ │ ├── aggregation-open-api.service.spec.ts │ │ │ │ │ └── aggregation-open-api.service.ts │ │ │ ├── ai │ │ │ │ ├── ai.controller.ts │ │ │ │ ├── ai.module.ts │ │ │ │ ├── ai.service.ts │ │ │ │ └── constant.ts │ │ │ ├── attachments │ │ │ │ ├── attachments-crop.module.ts │ │ │ │ ├── attachments-crop.processor.ts │ │ │ │ ├── attachments-storage.module.ts │ │ │ │ ├── attachments-storage.service.ts │ │ │ │ ├── attachments-table.module.ts │ │ │ │ ├── attachments-table.service.spec.ts │ │ │ │ ├── attachments-table.service.ts │ │ │ │ ├── attachments.controller.spec.ts │ │ │ │ ├── attachments.controller.ts │ │ │ │ ├── attachments.module.ts │ │ │ │ ├── attachments.service.spec.ts │ │ │ │ ├── attachments.service.ts │ │ │ │ ├── constant.ts │ │ │ │ ├── guard │ │ │ │ │ └── auth.guard.ts │ │ │ │ └── plugins │ │ │ │ │ ├── adapter.ts │ │ │ │ │ ├── local.spec.ts │ │ │ │ │ ├── local.ts │ │ │ │ │ ├── minio.ts │ │ │ │ │ ├── s3.ts │ │ │ │ │ ├── storage.module.ts │ │ │ │ │ ├── storage.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils.ts │ │ │ ├── auth │ │ │ │ ├── auth.controller.spec.ts │ │ │ │ ├── auth.controller.ts │ │ │ │ ├── auth.module.ts │ │ │ │ ├── auth.service.spec.ts │ │ │ │ ├── auth.service.ts │ │ │ │ ├── decorators │ │ │ │ │ ├── disabled-permission.decorator.ts │ │ │ │ │ ├── ensure-login.decorator.ts │ │ │ │ │ ├── permissions.decorator.ts │ │ │ │ │ ├── public.decorator.ts │ │ │ │ │ ├── resource_meta.decorator.ts │ │ │ │ │ └── token.decorator.ts │ │ │ │ ├── guard │ │ │ │ │ ├── auth.guard.ts │ │ │ │ │ ├── github.guard.ts │ │ │ │ │ ├── google.guard.ts │ │ │ │ │ ├── local-auth.guard.ts │ │ │ │ │ ├── oidc.guard.ts │ │ │ │ │ ├── permission.guard.ts │ │ │ │ │ └── social.guard.ts │ │ │ │ ├── local-auth │ │ │ │ │ ├── local-auth.controller.ts │ │ │ │ │ ├── local-auth.module.ts │ │ │ │ │ └── local-auth.service.ts │ │ │ │ ├── oauth │ │ │ │ │ └── oauth.store.ts │ │ │ │ ├── permission.module.ts │ │ │ │ ├── permission.service.spec.ts │ │ │ │ ├── permission.service.ts │ │ │ │ ├── session │ │ │ │ │ ├── session-handle.module.ts │ │ │ │ │ ├── session-handle.service.ts │ │ │ │ │ ├── session-store.service.spec.ts │ │ │ │ │ ├── session-store.service.ts │ │ │ │ │ ├── session.module.ts │ │ │ │ │ ├── session.serializer.ts │ │ │ │ │ └── session.service.ts │ │ │ │ ├── social │ │ │ │ │ ├── controller.adapter.ts │ │ │ │ │ ├── github │ │ │ │ │ │ ├── github.controller.ts │ │ │ │ │ │ └── github.module.ts │ │ │ │ │ ├── google │ │ │ │ │ │ ├── google.controller.ts │ │ │ │ │ │ └── google.module.ts │ │ │ │ │ ├── oidc │ │ │ │ │ │ ├── oidc.controller.ts │ │ │ │ │ │ └── oidc.module.ts │ │ │ │ │ └── social.module.ts │ │ │ │ ├── strategies │ │ │ │ │ ├── access-token.passport.ts │ │ │ │ │ ├── access-token.strategy.ts │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── github.strategy.ts │ │ │ │ │ ├── google.strategy.ts │ │ │ │ │ ├── jwt.strategy.ts │ │ │ │ │ ├── local.strategy.spec.ts │ │ │ │ │ ├── local.strategy.ts │ │ │ │ │ ├── oidc.strategy.ts │ │ │ │ │ ├── session.passport.ts │ │ │ │ │ ├── session.strategy.ts │ │ │ │ │ └── types.ts │ │ │ │ └── utils.ts │ │ │ ├── base-sql-executor │ │ │ │ ├── base-sql-executor.module.ts │ │ │ │ ├── base-sql-executor.service.ts │ │ │ │ ├── const.ts │ │ │ │ ├── utils.spec.ts │ │ │ │ └── utils.ts │ │ │ ├── base │ │ │ │ ├── BatchProcessor.class.ts │ │ │ │ ├── base-duplicate.service.spec.ts │ │ │ │ ├── base-duplicate.service.ts │ │ │ │ ├── base-export.service.ts │ │ │ │ ├── base-import-processor │ │ │ │ │ ├── base-import-attachments-csv.module.ts │ │ │ │ │ ├── base-import-attachments-csv.processor.ts │ │ │ │ │ ├── base-import-attachments.module.ts │ │ │ │ │ ├── base-import-attachments.processor.ts │ │ │ │ │ ├── base-import-csv.module.ts │ │ │ │ │ ├── base-import-csv.processor.ts │ │ │ │ │ ├── base-import-junction-csv.module.ts │ │ │ │ │ └── base-import-junction.processor.ts │ │ │ │ ├── base-import.service.ts │ │ │ │ ├── base-query │ │ │ │ │ ├── base-query.service.ts │ │ │ │ │ └── parse │ │ │ │ │ │ ├── aggregation.ts │ │ │ │ │ │ ├── filter.ts │ │ │ │ │ │ ├── group.ts │ │ │ │ │ │ ├── order.ts │ │ │ │ │ │ ├── select.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ ├── base.controller.ts │ │ │ │ ├── base.module.ts │ │ │ │ ├── base.service.spec.ts │ │ │ │ ├── base.service.ts │ │ │ │ ├── constant.ts │ │ │ │ ├── db-connection.service.spec.ts │ │ │ │ ├── db-connection.service.ts │ │ │ │ ├── utils.spec.ts │ │ │ │ └── utils.ts │ │ │ ├── calculation │ │ │ │ ├── README.md │ │ │ │ ├── batch.service.spec.ts │ │ │ │ ├── batch.service.ts │ │ │ │ ├── calculation.module.ts │ │ │ │ ├── field-calculation.service.spec.ts │ │ │ │ ├── field-calculation.service.ts │ │ │ │ ├── link.service.spec.ts │ │ │ │ ├── link.service.ts │ │ │ │ ├── reference.service.spec.ts │ │ │ │ ├── reference.service.ts │ │ │ │ ├── system-field.service.ts │ │ │ │ └── utils │ │ │ │ │ ├── changes.spec.ts │ │ │ │ │ ├── changes.ts │ │ │ │ │ ├── compose-maps.spec.ts │ │ │ │ │ ├── compose-maps.ts │ │ │ │ │ ├── detect-link.spec.ts │ │ │ │ │ ├── detect-link.ts │ │ │ │ │ ├── dfs.spec.ts │ │ │ │ │ ├── dfs.ts │ │ │ │ │ └── name-console.ts │ │ │ ├── chat │ │ │ │ ├── chart-completion.ro.ts │ │ │ │ ├── chat.controller.spec.ts │ │ │ │ ├── chat.controller.ts │ │ │ │ ├── chat.module.ts │ │ │ │ ├── chat.service.spec.ts │ │ │ │ └── chat.service.ts │ │ │ ├── collaborator │ │ │ │ ├── collaborator.controller.spec.ts │ │ │ │ ├── collaborator.controller.ts │ │ │ │ ├── collaborator.module.ts │ │ │ │ ├── collaborator.service.spec.ts │ │ │ │ └── collaborator.service.ts │ │ │ ├── comment │ │ │ │ ├── comment-open-api.controller.spec.ts │ │ │ │ ├── comment-open-api.controller.ts │ │ │ │ ├── comment-open-api.module.ts │ │ │ │ └── comment-open-api.service.ts │ │ │ ├── dashboard │ │ │ │ ├── dashboard.controller.spec.ts │ │ │ │ ├── dashboard.controller.ts │ │ │ │ ├── dashboard.module.ts │ │ │ │ ├── dashboard.service.spec.ts │ │ │ │ └── dashboard.service.ts │ │ │ ├── export │ │ │ │ └── open-api │ │ │ │ │ ├── export-open-api.controller.ts │ │ │ │ │ ├── export-open-api.module.ts │ │ │ │ │ └── export-open-api.service.ts │ │ │ ├── field │ │ │ │ ├── constant.ts │ │ │ │ ├── field-calculate │ │ │ │ │ ├── field-calculate.module.ts │ │ │ │ │ ├── field-converting-link.service.spec.ts │ │ │ │ │ ├── field-converting-link.service.ts │ │ │ │ │ ├── field-converting.service.spec.ts │ │ │ │ │ ├── field-converting.service.ts │ │ │ │ │ ├── field-creating.service.spec.ts │ │ │ │ │ ├── field-creating.service.ts │ │ │ │ │ ├── field-deleting.service.spec.ts │ │ │ │ │ ├── field-deleting.service.ts │ │ │ │ │ ├── field-supplement.service.ts │ │ │ │ │ └── field-view-sync.service.ts │ │ │ │ ├── field-duplicate │ │ │ │ │ ├── field-duplicate.module.ts │ │ │ │ │ └── field-duplicate.service.ts │ │ │ │ ├── field.module.ts │ │ │ │ ├── field.service.spec.ts │ │ │ │ ├── field.service.ts │ │ │ │ ├── model │ │ │ │ │ ├── factory.ts │ │ │ │ │ ├── field-base.ts │ │ │ │ │ └── field-dto │ │ │ │ │ │ ├── attachment-field.dto.ts │ │ │ │ │ │ ├── auto-number-field.dto.ts │ │ │ │ │ │ ├── checkbox-field.dto.ts │ │ │ │ │ │ ├── created-by-field.dto.ts │ │ │ │ │ │ ├── created-time-field.dto.ts │ │ │ │ │ │ ├── date-field.dto.ts │ │ │ │ │ │ ├── formula-field.dto.ts │ │ │ │ │ │ ├── last-modified-by-field.dto.ts │ │ │ │ │ │ ├── last-modified-time-field.dto.ts │ │ │ │ │ │ ├── link-field.dto.ts │ │ │ │ │ │ ├── long-text-field.dto.ts │ │ │ │ │ │ ├── multiple-select-field.dto.ts │ │ │ │ │ │ ├── number-field.dto.ts │ │ │ │ │ │ ├── rating-field.dto.ts │ │ │ │ │ │ ├── rollup-field.dto.ts │ │ │ │ │ │ ├── single-line-text-field.dto.ts │ │ │ │ │ │ ├── single-select-field.dto.ts │ │ │ │ │ │ └── user-field.dto.ts │ │ │ │ ├── open-api │ │ │ │ │ ├── field-open-api.controller.ts │ │ │ │ │ ├── field-open-api.module.ts │ │ │ │ │ ├── field-open-api.service.spec.ts │ │ │ │ │ └── field-open-api.service.ts │ │ │ │ └── util.ts │ │ │ ├── graph │ │ │ │ ├── graph.module.ts │ │ │ │ ├── graph.service.spec.ts │ │ │ │ └── graph.service.ts │ │ │ ├── health │ │ │ │ ├── health.controller.spec.ts │ │ │ │ ├── health.controller.ts │ │ │ │ └── health.module.ts │ │ │ ├── import │ │ │ │ └── open-api │ │ │ │ │ ├── NOTICE.md │ │ │ │ │ ├── delimiter-stream.ts │ │ │ │ │ ├── import-open-api.controller.ts │ │ │ │ │ ├── import-open-api.module.ts │ │ │ │ │ ├── import-open-api.service.ts │ │ │ │ │ └── import.class.ts │ │ │ ├── integrity │ │ │ │ ├── foreign-key.service.ts │ │ │ │ ├── integrity.controller.ts │ │ │ │ ├── integrity.module.ts │ │ │ │ ├── link-field.service.ts │ │ │ │ └── link-integrity.service.ts │ │ │ ├── invitation │ │ │ │ ├── invitation.controller.spec.ts │ │ │ │ ├── invitation.controller.ts │ │ │ │ ├── invitation.module.ts │ │ │ │ ├── invitation.service.spec.ts │ │ │ │ └── invitation.service.ts │ │ │ ├── mail-sender │ │ │ │ ├── mail-helpers.ts │ │ │ │ ├── mail-sender.module.ts │ │ │ │ ├── mail-sender.service.ts │ │ │ │ └── templates │ │ │ │ │ ├── pages │ │ │ │ │ └── normal.hbs │ │ │ │ │ └── partials │ │ │ │ │ ├── collaborator-cell-tag.hbs │ │ │ │ │ ├── collaborator-multi-row-tag.hbs │ │ │ │ │ ├── common-body.hbs │ │ │ │ │ ├── email-verify-code.hbs │ │ │ │ │ ├── footer.hbs │ │ │ │ │ ├── header.hbs │ │ │ │ │ ├── html-body.hbs │ │ │ │ │ ├── invite.hbs │ │ │ │ │ └── reset-password.hbs │ │ │ ├── next │ │ │ │ ├── next.controller.ts │ │ │ │ ├── next.module.ts │ │ │ │ ├── next.service.ts │ │ │ │ └── plugin │ │ │ │ │ ├── plugin-proxy.middleware.ts │ │ │ │ │ ├── plugin-proxy.module.ts │ │ │ │ │ └── plugin.module.ts │ │ │ ├── notification │ │ │ │ ├── notification.controller.ts │ │ │ │ ├── notification.module.ts │ │ │ │ └── notification.service.ts │ │ │ ├── oauth │ │ │ │ ├── guard │ │ │ │ │ └── oauth2-client.guard.ts │ │ │ │ ├── oauth-server.controller.ts │ │ │ │ ├── oauth-server.service.spec.ts │ │ │ │ ├── oauth-server.service.ts │ │ │ │ ├── oauth-tx-store.ts │ │ │ │ ├── oauth.controller.spec.ts │ │ │ │ ├── oauth.controller.ts │ │ │ │ ├── oauth.module.ts │ │ │ │ ├── oauth.service.spec.ts │ │ │ │ ├── oauth.service.ts │ │ │ │ ├── strategies │ │ │ │ │ └── oauth2-client.strategies.ts │ │ │ │ └── types.ts │ │ │ ├── organization │ │ │ │ ├── organization.controller.ts │ │ │ │ └── organization.module.ts │ │ │ ├── pin │ │ │ │ ├── pin.controller.ts │ │ │ │ ├── pin.module.ts │ │ │ │ └── pin.service.ts │ │ │ ├── plugin-context-menu │ │ │ │ ├── plugin-context-menu.controller.ts │ │ │ │ ├── plugin-context-menu.module.ts │ │ │ │ └── plugin-context-menu.service.ts │ │ │ ├── plugin-panel │ │ │ │ ├── plugin-panel.controller.ts │ │ │ │ ├── plugin-panel.module.ts │ │ │ │ └── plugin-panel.service.ts │ │ │ ├── plugin │ │ │ │ ├── official │ │ │ │ │ ├── config │ │ │ │ │ │ ├── chart.ts │ │ │ │ │ │ ├── sheet-form-view.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── official-plugin-init.service.ts │ │ │ │ ├── plugin-auth.service.ts │ │ │ │ ├── plugin.controller.spec.ts │ │ │ │ ├── plugin.controller.ts │ │ │ │ ├── plugin.module.ts │ │ │ │ ├── plugin.service.spec.ts │ │ │ │ ├── plugin.service.ts │ │ │ │ └── utils.ts │ │ │ ├── record │ │ │ │ ├── constant.ts │ │ │ │ ├── open-api │ │ │ │ │ ├── field-key.pipe.ts │ │ │ │ │ ├── record-open-api.controller.ts │ │ │ │ │ ├── record-open-api.module.ts │ │ │ │ │ ├── record-open-api.service.spec.ts │ │ │ │ │ ├── record-open-api.service.ts │ │ │ │ │ ├── record-undo-redo-service.ts │ │ │ │ │ └── tql.pipe.ts │ │ │ │ ├── record-calculate │ │ │ │ │ ├── record-calculate.module.ts │ │ │ │ │ └── record-calculate.service.ts │ │ │ │ ├── record-permission.service.ts │ │ │ │ ├── record.module.ts │ │ │ │ ├── record.service.spec.ts │ │ │ │ ├── record.service.ts │ │ │ │ ├── type.ts │ │ │ │ ├── typecast.validate.spec.ts │ │ │ │ ├── typecast.validate.ts │ │ │ │ └── user-name.listener.service.ts │ │ │ ├── selection │ │ │ │ ├── selection.controller.spec.ts │ │ │ │ ├── selection.controller.ts │ │ │ │ ├── selection.module.ts │ │ │ │ ├── selection.service.spec.ts │ │ │ │ └── selection.service.ts │ │ │ ├── setting │ │ │ │ ├── admin.controller.ts │ │ │ │ ├── admin.service.ts │ │ │ │ ├── setting.controller.ts │ │ │ │ ├── setting.module.ts │ │ │ │ └── setting.service.ts │ │ │ ├── share │ │ │ │ ├── guard │ │ │ │ │ ├── auth.guard.ts │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── share-auth-local.guard.ts │ │ │ │ │ └── submit.decorator.ts │ │ │ │ ├── share-auth.module.ts │ │ │ │ ├── share-auth.service.ts │ │ │ │ ├── share-socket.service.ts │ │ │ │ ├── share.controller.spec.ts │ │ │ │ ├── share.controller.ts │ │ │ │ ├── share.module.ts │ │ │ │ ├── share.service.spec.ts │ │ │ │ ├── share.service.ts │ │ │ │ └── strategies │ │ │ │ │ └── jwt.strategy.ts │ │ │ ├── space │ │ │ │ ├── space.controller.spec.ts │ │ │ │ ├── space.controller.ts │ │ │ │ ├── space.module.ts │ │ │ │ ├── space.service.spec.ts │ │ │ │ ├── space.service.ts │ │ │ │ └── template-space-init │ │ │ │ │ └── template-space.init.service.ts │ │ │ ├── table │ │ │ │ ├── constant.ts │ │ │ │ ├── open-api │ │ │ │ │ ├── table-open-api.controller.ts │ │ │ │ │ ├── table-open-api.module.ts │ │ │ │ │ ├── table-open-api.service.spec.ts │ │ │ │ │ ├── table-open-api.service.ts │ │ │ │ │ └── table.pipe.ts │ │ │ │ ├── table-duplicate.service.ts │ │ │ │ ├── table-index.service.ts │ │ │ │ ├── table-permission.service.ts │ │ │ │ ├── table.module.ts │ │ │ │ ├── table.service.spec.ts │ │ │ │ └── table.service.ts │ │ │ ├── template │ │ │ │ ├── template-open-api.controller.spec.ts │ │ │ │ ├── template-open-api.controller.ts │ │ │ │ ├── template-open-api.module.ts │ │ │ │ └── template-open-api.service.ts │ │ │ ├── trash │ │ │ │ ├── listener │ │ │ │ │ └── table-trash.listener.ts │ │ │ │ ├── trash.controller.ts │ │ │ │ ├── trash.module.ts │ │ │ │ └── trash.service.ts │ │ │ ├── undo-redo │ │ │ │ ├── open-api │ │ │ │ │ ├── undo-redo.controller.ts │ │ │ │ │ ├── undo-redo.module.ts │ │ │ │ │ └── undo-redo.service.ts │ │ │ │ ├── operations │ │ │ │ │ ├── convert-field.operation.ts │ │ │ │ │ ├── create-fields.operation.ts │ │ │ │ │ ├── create-records.operation.ts │ │ │ │ │ ├── create-view.operation.ts │ │ │ │ │ ├── delete-fields.operation.ts │ │ │ │ │ ├── delete-records.operation.ts │ │ │ │ │ ├── delete-view.operation.ts │ │ │ │ │ ├── paste-selection.operation.ts │ │ │ │ │ ├── update-records-order.operation.ts │ │ │ │ │ ├── update-records.operation.ts │ │ │ │ │ └── update-view.operation.ts │ │ │ │ └── stack │ │ │ │ │ ├── undo-redo-operation.service.ts │ │ │ │ │ ├── undo-redo-stack.module.ts │ │ │ │ │ └── undo-redo-stack.service.ts │ │ │ ├── user │ │ │ │ ├── last-visit │ │ │ │ │ ├── last-visit.controller.ts │ │ │ │ │ ├── last-visit.module.ts │ │ │ │ │ └── last-visit.service.ts │ │ │ │ ├── user-init.service.ts │ │ │ │ ├── user.controller.spec.ts │ │ │ │ ├── user.controller.ts │ │ │ │ ├── user.module.ts │ │ │ │ ├── user.service.spec.ts │ │ │ │ └── user.service.ts │ │ │ └── view │ │ │ │ ├── constant.ts │ │ │ │ ├── model │ │ │ │ ├── calendar-view.dto.ts │ │ │ │ ├── factory.ts │ │ │ │ ├── form-view.dto.ts │ │ │ │ ├── gallery-view.dto.ts │ │ │ │ ├── grid-view.dto.ts │ │ │ │ ├── kanban-view.dto.ts │ │ │ │ └── plugin-view.dto.ts │ │ │ │ ├── open-api │ │ │ │ ├── view-open-api.controller.ts │ │ │ │ ├── view-open-api.module.ts │ │ │ │ ├── view-open-api.service.spec.ts │ │ │ │ └── view-open-api.service.ts │ │ │ │ ├── view.module.ts │ │ │ │ ├── view.service.spec.ts │ │ │ │ └── view.service.ts │ │ ├── filter │ │ │ └── global-exception.filter.ts │ │ ├── global │ │ │ ├── global.module.ts │ │ │ ├── init-bootstrap.provider.ts │ │ │ ├── init-bootstrap.service.ts │ │ │ └── knex │ │ │ │ ├── index.ts │ │ │ │ ├── knex.extend.ts │ │ │ │ └── knex.module.ts │ │ ├── index.ts │ │ ├── logger │ │ │ └── logger.module.ts │ │ ├── middleware │ │ │ └── request-info.middleware.ts │ │ ├── share-db │ │ │ ├── auth.middleware.ts │ │ │ ├── interface.ts │ │ │ ├── readonly │ │ │ │ ├── field-readonly.service.ts │ │ │ │ ├── readonly.module.ts │ │ │ │ ├── readonly.service.ts │ │ │ │ ├── record-readonly.service.ts │ │ │ │ ├── table-readonly.service.ts │ │ │ │ └── view-readonly.service.ts │ │ │ ├── repair-attachment-op │ │ │ │ ├── repair-attachment-op.module.ts │ │ │ │ └── repair-attachment-op.service.ts │ │ │ ├── share-db.adapter.ts │ │ │ ├── share-db.module.ts │ │ │ ├── share-db.service.ts │ │ │ ├── share-db.spec.ts │ │ │ ├── sharedb-redis.pubsub.ts │ │ │ └── utils.ts │ │ ├── tracing.ts │ │ ├── tracing │ │ │ └── decorators │ │ │ │ └── span.ts │ │ ├── types │ │ │ ├── cls.ts │ │ │ └── session.ts │ │ ├── utils │ │ │ ├── code-generate.ts │ │ │ ├── db-helpers.ts │ │ │ ├── db-validation-error.ts │ │ │ ├── encryptor.ts │ │ │ ├── exception-parse.ts │ │ │ ├── extract-field-reference.ts │ │ │ ├── file-utils.spec.ts │ │ │ ├── file-utils.ts │ │ │ ├── filter.ts │ │ │ ├── generate-thumbnail-path.ts │ │ │ ├── get-max-level-role.ts │ │ │ ├── index.ts │ │ │ ├── is-not-hidden-field.ts │ │ │ ├── is-user-or-link.ts │ │ │ ├── major-field-keys-changed.spec.ts │ │ │ ├── major-field-keys-changed.ts │ │ │ ├── metadata.ts │ │ │ ├── name-conversion.ts │ │ │ ├── second.ts │ │ │ ├── string-hash.ts │ │ │ ├── timing.ts │ │ │ ├── update-order.spec.ts │ │ │ ├── update-order.ts │ │ │ └── value-convert.ts │ │ ├── worker │ │ │ └── parse.ts │ │ ├── ws │ │ │ ├── wjs.d.ts │ │ │ ├── ws.gateway.dev.ts │ │ │ ├── ws.gateway.spec.ts │ │ │ ├── ws.gateway.ts │ │ │ ├── ws.module.ts │ │ │ ├── ws.service.spec.ts │ │ │ └── ws.service.ts │ │ └── zod.validation.pipe.ts │ ├── static │ │ ├── plugin │ │ │ ├── chart-logo.png │ │ │ ├── chart.png │ │ │ └── sheet-form-logo.png │ │ └── system │ │ │ ├── anonymous.png │ │ │ └── automation-robot.png │ ├── test │ │ ├── access-token.e2e-spec.ts │ │ ├── aggregation-search.e2e-spec.ts │ │ ├── aggregation.e2e-spec.ts │ │ ├── attachment.e2e-spec.ts │ │ ├── auth.e2e-spec.ts │ │ ├── base-duplicate.e2e-spec.ts │ │ ├── base-query.e2e-spec.ts │ │ ├── base.e2e-spec.ts │ │ ├── comment.e2e-spec.ts │ │ ├── computed-user-field.e2e-spec.ts │ │ ├── credit.e2e-spec.ts │ │ ├── dashboard.e2e-spec.ts │ │ ├── data-helpers │ │ │ ├── 20x-link.ts │ │ │ ├── 20x.ts │ │ │ └── caces │ │ │ │ ├── aggregation-query │ │ │ │ ├── checkbox-field.ts │ │ │ │ ├── date-field.ts │ │ │ │ ├── index.ts │ │ │ │ ├── multiple-select-field.ts │ │ │ │ ├── number-field.ts │ │ │ │ ├── single-select-field.ts │ │ │ │ ├── text-field.ts │ │ │ │ └── user-field.ts │ │ │ │ ├── record-filter-query │ │ │ │ ├── checkbox-field.ts │ │ │ │ ├── date-field │ │ │ │ │ ├── date-field.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── is-after-sets.ts │ │ │ │ │ ├── is-before-sets.ts │ │ │ │ │ ├── is-not-sets.ts │ │ │ │ │ ├── is-on-or-after-sets.ts │ │ │ │ │ ├── is-on-or-before-sets.ts │ │ │ │ │ ├── is-sets.ts │ │ │ │ │ ├── is-with-in-sets.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── index.ts │ │ │ │ ├── multiple-select-field.ts │ │ │ │ ├── number-field.ts │ │ │ │ ├── single-select-field.ts │ │ │ │ ├── text-field.ts │ │ │ │ └── user-field.ts │ │ │ │ └── view-default-share-meta.ts │ │ ├── db-connection.e2e-spec.ts │ │ ├── field-calculation.e2e-spec.ts │ │ ├── field-converting.e2e-spec.ts │ │ ├── field-duplicate.e2e-spec.ts │ │ ├── field-reference.e2e-spec.ts │ │ ├── field-view-sync.e2e-spec.ts │ │ ├── field.e2e-spec.ts │ │ ├── filter.e2e-spec.ts │ │ ├── formula.e2e-spec.ts │ │ ├── graph.e2e-spec.ts │ │ ├── group.e2e-spec.ts │ │ ├── import-base.e2e-spec.ts │ │ ├── integrity.e2e-spec.ts │ │ ├── invitation.e2e-spec.ts │ │ ├── link-api.e2e-spec.ts │ │ ├── lookup.e2e-spec.ts │ │ ├── oauth-server.e2e-spec.ts │ │ ├── oauth.e2e-spec.ts │ │ ├── order-update.e2e-spec.ts │ │ ├── performance.e2e-spec.ts │ │ ├── pin.e2e-spec.ts │ │ ├── plugin-context-menu.e2e-spec.ts │ │ ├── plugin-panel.e2e-spec.ts │ │ ├── plugin.e2e-spec.ts │ │ ├── record-field-key.e2e-spec.ts │ │ ├── record-filter-query.e2e-spec.ts │ │ ├── record-history.e2e-spec.ts │ │ ├── record-link-select-query.e2e-spec.ts │ │ ├── record-search-query.e2e-spec.ts │ │ ├── record-typecast.e2e-spec.ts │ │ ├── record.e2e-spec.ts │ │ ├── reference.e2e-spec.ts.bak │ │ ├── rollup.e2e-spec.ts │ │ ├── scheduled-computing.e2e-spec.ts │ │ ├── selection.e2e-spec.ts │ │ ├── set-column-meta.e2e-spec.ts │ │ ├── share-socket.e2e-spec.ts │ │ ├── share.e2e-spec.ts │ │ ├── sort.e2e-spec.ts │ │ ├── space.e2e-spec.ts │ │ ├── table-duplicate.e2e-spec.ts │ │ ├── table-export.e2e-spec.ts │ │ ├── table-import.e2e-spec.ts │ │ ├── table-trash.e2e-spec.ts │ │ ├── table.e2e-spec.ts │ │ ├── template.e2e-spec.ts │ │ ├── trash.e2e-spec.ts │ │ ├── undo-redo.e2e-spec.ts │ │ ├── user-last-visit.e2e-spec.ts │ │ ├── utils │ │ │ ├── axios-instance │ │ │ │ ├── anonymous-user.ts │ │ │ │ └── new-user.ts │ │ │ ├── data.generator.ts │ │ │ ├── event-promise.ts │ │ │ ├── field-mock.ts │ │ │ ├── get-error.ts │ │ │ ├── init-app.ts │ │ │ ├── record-mock.ts │ │ │ ├── seed.ts │ │ │ └── testing-logger.ts │ │ ├── view-option.e2e-spec.ts │ │ └── view.e2e-spec.ts │ ├── tsconfig.build.json │ ├── tsconfig.eslint.json │ ├── tsconfig.json │ ├── vitest-e2e.config.ts │ ├── vitest-e2e.setup.ts │ ├── vitest.config.ts │ ├── webpack.config.js │ └── webpack.dev.js └── nextjs-app │ ├── .env │ ├── .env.development │ ├── .env.example │ ├── .env.test │ ├── .escheckrc │ ├── .eslintrc.js │ ├── .gitignore │ ├── .idea │ ├── modules.xml │ └── nextjs-app.iml │ ├── .size-limit.js │ ├── README.md │ ├── babel.config.backup.js │ ├── components.json │ ├── config │ └── tests │ │ ├── AppTestProviders.tsx │ │ ├── I18nextTestStubProvider.tsx │ │ ├── ReactSvgrMock.tsx │ │ ├── setupVitest.ts │ │ └── test-utils.tsx │ ├── e2e │ └── pages │ │ ├── index │ │ ├── index-chinese.spec.ts │ │ └── index.spec.ts │ │ └── system │ │ └── 404.spec.ts │ ├── lint-staged.config.js │ ├── next-env.d.ts │ ├── next-i18next.config.js │ ├── next.config.js │ ├── package.json │ ├── playwright.config.ts │ ├── postcss.config.js │ ├── public │ ├── favicon.ico │ └── images │ │ ├── example │ │ ├── Boy1.png │ │ ├── Boy3.png │ │ ├── Girl1.png │ │ ├── Girl2.png │ │ └── Girl3.png │ │ ├── favicon │ │ ├── .readme │ │ ├── android-144x144.png │ │ ├── android-192x192.png │ │ ├── android-36x36.png │ │ ├── android-48x48.png │ │ ├── android-72x72.png │ │ ├── android-96x96.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── android-chrome-maskable-192x192.png │ │ ├── android-chrome-maskable-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── msapplication-icon-144x144.png │ │ ├── mstile-150x150.png │ │ ├── safari-pinned-tab.svg │ │ └── site.webmanifest │ │ └── layout │ │ └── footer-waves.svg │ ├── sentry.client.config.ts │ ├── sentry.server.config.ts │ ├── src │ ├── AppProviders.tsx │ ├── backend │ │ └── api │ │ │ └── rest │ │ │ ├── axios.ts │ │ │ ├── get-user.ts │ │ │ └── ssr-api.ts │ ├── components │ │ ├── Banner.tsx │ │ ├── Guide.tsx │ │ ├── Metrics.tsx │ │ ├── RouterProgress.tsx │ │ ├── Selector.tsx │ │ ├── TeableLogo.tsx │ │ ├── layout │ │ │ ├── MainFooter.tsx │ │ │ ├── MainLayout.tsx │ │ │ ├── __tests__ │ │ │ │ └── MainLayout.test.tsx │ │ │ └── index.ts │ │ └── store │ │ │ ├── guide.ts │ │ │ └── index.ts │ ├── features │ │ ├── app │ │ │ ├── automation │ │ │ │ └── Pages.tsx │ │ │ ├── blocks │ │ │ │ ├── AuthorityMatrix.tsx │ │ │ │ ├── Error.tsx │ │ │ │ ├── admin │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── setting │ │ │ │ │ │ ├── SettingPage.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── Branding.tsx │ │ │ │ │ │ │ ├── BrandingLogo.tsx │ │ │ │ │ │ │ ├── CopyInstance.tsx │ │ │ │ │ │ │ ├── ai-config │ │ │ │ │ │ │ │ ├── AIModelPreferencesCard.tsx │ │ │ │ │ │ │ │ ├── AIProviderCard.tsx │ │ │ │ │ │ │ │ ├── AiForm.tsx │ │ │ │ │ │ │ │ ├── AiModelSelect.tsx │ │ │ │ │ │ │ │ ├── LlmProviderForm.tsx │ │ │ │ │ │ │ │ ├── LlmproviderManage.tsx │ │ │ │ │ │ │ │ ├── constant.ts │ │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── template │ │ │ │ │ │ ├── TemplatePage.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ ├── BaseSelectPanel.tsx │ │ │ │ │ │ ├── MarkdownEditor.tsx │ │ │ │ │ │ ├── TemplateCategorySelect.tsx │ │ │ │ │ │ ├── TemplateCover.tsx │ │ │ │ │ │ ├── TemplateTable.tsx │ │ │ │ │ │ ├── TemplateTooltips.tsx │ │ │ │ │ │ ├── TextEditor.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── upload-panel │ │ │ │ │ │ │ ├── Process.tsx │ │ │ │ │ │ │ ├── TemplateCoverPreview.tsx │ │ │ │ │ │ │ ├── Trigger.tsx │ │ │ │ │ │ │ ├── UploadPanel.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── base │ │ │ │ │ ├── BasePermissionListener.tsx │ │ │ │ │ ├── base-side-bar │ │ │ │ │ │ ├── BaseSideBar.tsx │ │ │ │ │ │ ├── BaseSidebarHeaderLeft.tsx │ │ │ │ │ │ └── QuickAction.tsx │ │ │ │ │ └── duplicate │ │ │ │ │ │ ├── DuplicateBaseModal.tsx │ │ │ │ │ │ ├── TemplateCreateBaseModal.tsx │ │ │ │ │ │ ├── useDuplicateBaseStore.ts │ │ │ │ │ │ ├── useTemplateCreateBaseStore.ts │ │ │ │ │ │ └── useTemplateMonitor.ts │ │ │ │ ├── billing │ │ │ │ │ ├── SpaceSubscriptionModal.tsx │ │ │ │ │ ├── useSpaceSubscriptionMonitor.ts │ │ │ │ │ └── useSpaceSubscriptionStore.ts │ │ │ │ ├── dashboard │ │ │ │ │ └── Dashboard.tsx │ │ │ │ ├── db-connection │ │ │ │ │ └── Panel.tsx │ │ │ │ ├── design │ │ │ │ │ ├── BaseDetail.tsx │ │ │ │ │ ├── Design.tsx │ │ │ │ │ ├── TableDetail.tsx │ │ │ │ │ ├── TableTabs.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── Actions.tsx │ │ │ │ │ │ ├── FieldPropertyEditor.tsx │ │ │ │ │ │ └── Integrity.tsx │ │ │ │ │ └── data-table │ │ │ │ │ │ ├── DataTable.tsx │ │ │ │ │ │ ├── FieldGraph.tsx │ │ │ │ │ │ └── useDataColumns.tsx │ │ │ │ ├── graph │ │ │ │ │ ├── DynamicFieldGraph.tsx │ │ │ │ │ ├── FieldGraph.tsx │ │ │ │ │ ├── ProgressBar.tsx │ │ │ │ │ ├── useGraph.tsx │ │ │ │ │ └── usePlan.ts │ │ │ │ ├── import-table │ │ │ │ │ ├── TableImport.tsx │ │ │ │ │ ├── UrlPanel.tsx │ │ │ │ │ ├── field-config-panel │ │ │ │ │ │ ├── CollapsePanel.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── inplace-panel │ │ │ │ │ │ │ ├── FieldSelector.tsx │ │ │ │ │ │ │ ├── InplaceFieldConfigPanel.tsx │ │ │ │ │ │ │ └── InplacePreviewColumn.tsx │ │ │ │ │ │ └── new-create-panel │ │ │ │ │ │ │ ├── FieldConfigPanel.tsx │ │ │ │ │ │ │ └── PreviewColumn.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── upload-panel │ │ │ │ │ │ ├── Process.tsx │ │ │ │ │ │ ├── Trigger.tsx │ │ │ │ │ │ ├── UploadPanel.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ ├── index.ts │ │ │ │ ├── setting │ │ │ │ │ ├── SettingRight.tsx │ │ │ │ │ ├── SettingRightTitle.tsx │ │ │ │ │ ├── access-token │ │ │ │ │ │ ├── AccessTokenList.tsx │ │ │ │ │ │ ├── PersonAccessTokenForm.tsx │ │ │ │ │ │ ├── PersonAccessTokenPage.tsx │ │ │ │ │ │ ├── PersonAccessTokenTitle.tsx │ │ │ │ │ │ └── form │ │ │ │ │ │ │ ├── AccessList.tsx │ │ │ │ │ │ │ ├── AccessSelect.tsx │ │ │ │ │ │ │ ├── AccessTokenForm.tsx │ │ │ │ │ │ │ ├── AccessTokenFormEdit.tsx │ │ │ │ │ │ │ ├── ExpirationSelect.tsx │ │ │ │ │ │ │ └── RefreshToken.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── FormItem.tsx │ │ │ │ │ │ ├── FormPageLayout.tsx │ │ │ │ │ │ ├── RequireCom.tsx │ │ │ │ │ │ └── ScopesSelect.tsx │ │ │ │ │ ├── oauth-app │ │ │ │ │ │ ├── OAuthAppDecisionPage.tsx │ │ │ │ │ │ ├── OAuthAppPage.tsx │ │ │ │ │ │ ├── constant.ts │ │ │ │ │ │ └── manage │ │ │ │ │ │ │ ├── CallbackEditor.tsx │ │ │ │ │ │ │ ├── List.tsx │ │ │ │ │ │ │ ├── OAuthAppEdit.tsx │ │ │ │ │ │ │ ├── OAuthAppForm.tsx │ │ │ │ │ │ │ └── OAuthAppNew.tsx │ │ │ │ │ ├── plugin │ │ │ │ │ │ ├── MarkDownEditor.tsx │ │ │ │ │ │ ├── PluginEdit.tsx │ │ │ │ │ │ ├── PluginList.tsx │ │ │ │ │ │ ├── PluginNew.tsx │ │ │ │ │ │ ├── PluginPage.tsx │ │ │ │ │ │ ├── component │ │ │ │ │ │ │ ├── JsonEditor.tsx │ │ │ │ │ │ │ ├── LogoEditor.tsx │ │ │ │ │ │ │ ├── NewSecret.tsx │ │ │ │ │ │ │ ├── PositionSelector.tsx │ │ │ │ │ │ │ ├── StatusBadge.tsx │ │ │ │ │ │ │ └── StatusDot.tsx │ │ │ │ │ │ └── hooks │ │ │ │ │ │ │ └── useStatusStatic.ts │ │ │ │ │ └── query-builder │ │ │ │ │ │ ├── FilterBuilder.tsx │ │ │ │ │ │ ├── PreviewScript.tsx │ │ │ │ │ │ ├── PreviewTable.tsx │ │ │ │ │ │ ├── QueryBuilder.tsx │ │ │ │ │ │ ├── SearchBuilder.tsx │ │ │ │ │ │ ├── SortBuilder.tsx │ │ │ │ │ │ ├── ViewBuilder.tsx │ │ │ │ │ │ └── useTransformFieldKey.ts │ │ │ │ ├── share │ │ │ │ │ └── view │ │ │ │ │ │ ├── AuthPage.tsx │ │ │ │ │ │ ├── EmbedFooter.tsx │ │ │ │ │ │ ├── ShareTablePermissionProvider.tsx │ │ │ │ │ │ ├── ShareView.tsx │ │ │ │ │ │ ├── ShareViewPage.tsx │ │ │ │ │ │ └── component │ │ │ │ │ │ ├── calendar │ │ │ │ │ │ ├── CalendarView.tsx │ │ │ │ │ │ └── toolbar │ │ │ │ │ │ │ ├── Toolbar.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── form │ │ │ │ │ │ ├── FormView.tsx │ │ │ │ │ │ └── FormViewBase.tsx │ │ │ │ │ │ ├── gallery │ │ │ │ │ │ ├── GalleryView.tsx │ │ │ │ │ │ └── toolbar │ │ │ │ │ │ │ ├── Toolbar.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── grid │ │ │ │ │ │ ├── GridView.tsx │ │ │ │ │ │ ├── GridViewBase.tsx │ │ │ │ │ │ ├── aggregation │ │ │ │ │ │ │ ├── AggregationProvider.tsx │ │ │ │ │ │ │ ├── GroupPointProvider.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── toolbar │ │ │ │ │ │ │ ├── Sort.tsx │ │ │ │ │ │ │ ├── Toolbar.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── kanban │ │ │ │ │ │ ├── KanbanView.tsx │ │ │ │ │ │ └── toolbar │ │ │ │ │ │ │ ├── Toolbar.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── plugin │ │ │ │ │ │ └── SharePluginView.tsx │ │ │ │ │ │ └── share-view-filter │ │ │ │ │ │ ├── FilterUser.tsx │ │ │ │ │ │ ├── ShareViewFilter.tsx │ │ │ │ │ │ ├── filter-link │ │ │ │ │ │ ├── FilterLink.tsx │ │ │ │ │ │ ├── FilterLinkSelectList.tsx │ │ │ │ │ │ ├── FilterLinkSelectTrigger.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── space-setting │ │ │ │ │ ├── collaborator │ │ │ │ │ │ ├── CollaboratorPage.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── general │ │ │ │ │ │ ├── GeneralPage.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── integration │ │ │ │ │ │ ├── IntegrationPage.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ ├── AiConfig.tsx │ │ │ │ │ │ ├── IntegrationCard.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── space │ │ │ │ │ ├── BaseCard.tsx │ │ │ │ │ ├── ColorBg.tsx │ │ │ │ │ ├── DraggableBaseGrid.tsx │ │ │ │ │ ├── RecentlyBase.tsx │ │ │ │ │ ├── SharedBasePage.tsx │ │ │ │ │ ├── SpaceCard.tsx │ │ │ │ │ ├── SpaceInnerPage.tsx │ │ │ │ │ ├── SpacePage.tsx │ │ │ │ │ ├── component │ │ │ │ │ │ ├── BaseActionTrigger.tsx │ │ │ │ │ │ ├── BaseListTrigger.tsx │ │ │ │ │ │ ├── EditableSpaceSelect.tsx │ │ │ │ │ │ ├── SpaceActionTrigger.tsx │ │ │ │ │ │ └── upload-panel │ │ │ │ │ │ │ ├── Process.tsx │ │ │ │ │ │ │ ├── Trigger.tsx │ │ │ │ │ │ │ ├── UploadPanel.tsx │ │ │ │ │ │ │ ├── UploadPanelDialog.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── space-side-bar │ │ │ │ │ │ ├── ItemButton.tsx │ │ │ │ │ │ ├── PinItem.tsx │ │ │ │ │ │ ├── PinList.tsx │ │ │ │ │ │ ├── SpaceItem.tsx │ │ │ │ │ │ ├── SpaceList.tsx │ │ │ │ │ │ ├── SpaceOperation.tsx │ │ │ │ │ │ ├── SpaceSideBar.tsx │ │ │ │ │ │ └── StarButton.tsx │ │ │ │ │ ├── useBaseList.tsx │ │ │ │ │ ├── usePinMap.ts │ │ │ │ │ └── useSpaceListOrdered.tsx │ │ │ │ ├── table-list │ │ │ │ │ ├── DraggableList.tsx │ │ │ │ │ ├── NoDraggableList.tsx │ │ │ │ │ ├── TableList.tsx │ │ │ │ │ ├── TableListItem.tsx │ │ │ │ │ ├── TableOperation.tsx │ │ │ │ │ ├── useAddTable.ts │ │ │ │ │ └── useTableHref.tsx │ │ │ │ ├── table │ │ │ │ │ ├── FailAlert.tsx │ │ │ │ │ ├── Table.tsx │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── use-aggregations-query.ts │ │ │ │ │ │ ├── use-import-status.ts │ │ │ │ │ │ ├── use-row-count-query.ts │ │ │ │ │ │ └── use-view-error-handler.tsx │ │ │ │ │ ├── store │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── use-locked-view-tip-store.ts │ │ │ │ │ └── table-header │ │ │ │ │ │ ├── AddPluginView.tsx │ │ │ │ │ │ ├── AddView.tsx │ │ │ │ │ │ ├── Collaborators.tsx │ │ │ │ │ │ ├── LockedViewTip.tsx │ │ │ │ │ │ ├── TableHeader.tsx │ │ │ │ │ │ └── TableInfo.tsx │ │ │ │ ├── trash │ │ │ │ │ ├── BaseTrashPage.tsx │ │ │ │ │ ├── SpaceTrashPage.tsx │ │ │ │ │ └── components │ │ │ │ │ │ ├── TableTrash.tsx │ │ │ │ │ │ └── TableTrashDialog.tsx │ │ │ │ └── view │ │ │ │ │ ├── View.tsx │ │ │ │ │ ├── calendar │ │ │ │ │ ├── CalendarView.tsx │ │ │ │ │ ├── CalendarViewBase.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── AddDateFieldDialog.tsx │ │ │ │ │ │ ├── AddEventButton.tsx │ │ │ │ │ │ ├── Calendar.tsx │ │ │ │ │ │ ├── CalendarConfig.tsx │ │ │ │ │ │ ├── EventList.tsx │ │ │ │ │ │ ├── EventListContainer.tsx │ │ │ │ │ │ └── EventMenu.tsx │ │ │ │ │ ├── context │ │ │ │ │ │ ├── CalendarContext.ts │ │ │ │ │ │ ├── CalendarProvider.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useCalendar.ts │ │ │ │ │ │ ├── useCalendarFields.ts │ │ │ │ │ │ └── useEventMenuStore.ts │ │ │ │ │ ├── type.ts │ │ │ │ │ └── util.ts │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── field │ │ │ │ │ ├── FieldSetting.tsx │ │ │ │ │ └── useFieldSettingStore.ts │ │ │ │ │ ├── form │ │ │ │ │ ├── FormView.tsx │ │ │ │ │ ├── FormViewBase.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── BrandFooter.tsx │ │ │ │ │ │ ├── Drag.tsx │ │ │ │ │ │ ├── FormCellEditor.tsx │ │ │ │ │ │ ├── FormEditor.tsx │ │ │ │ │ │ ├── FormEditorMain.tsx │ │ │ │ │ │ ├── FormField.tsx │ │ │ │ │ │ ├── FormFieldEditor.tsx │ │ │ │ │ │ ├── FormPreviewer.tsx │ │ │ │ │ │ ├── FormSidebar.tsx │ │ │ │ │ │ ├── FromBody.tsx │ │ │ │ │ │ ├── ShareUserEditor.tsx │ │ │ │ │ │ ├── SortableItem.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── share-link-editor │ │ │ │ │ │ │ ├── FormLinkEditor.tsx │ │ │ │ │ │ │ └── LinkRecordList.tsx │ │ │ │ │ ├── constant.ts │ │ │ │ │ └── util.ts │ │ │ │ │ ├── gallery │ │ │ │ │ ├── GalleryView.tsx │ │ │ │ │ ├── GalleryViewBase.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── Card.tsx │ │ │ │ │ │ ├── CardCarousel.tsx │ │ │ │ │ │ ├── SortableItem.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── context │ │ │ │ │ │ ├── GalleryContext.ts │ │ │ │ │ │ ├── GalleryProvider.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useCacheRecords.ts │ │ │ │ │ │ └── useGallery.ts │ │ │ │ │ ├── type.ts │ │ │ │ │ └── utils │ │ │ │ │ │ ├── card.ts │ │ │ │ │ │ ├── columns.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── grid │ │ │ │ │ ├── DomBox.tsx │ │ │ │ │ ├── GridView.tsx │ │ │ │ │ ├── GridViewBase.tsx │ │ │ │ │ ├── GridViewBaseInner.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── AiGenerateButton.tsx │ │ │ │ │ │ ├── ConfirmNewRecords.tsx │ │ │ │ │ │ ├── FieldMenu.tsx │ │ │ │ │ │ ├── GroupHeaderMenu.tsx │ │ │ │ │ │ ├── PluginMenu.tsx │ │ │ │ │ │ ├── PrefillingRowContainer.tsx │ │ │ │ │ │ ├── PresortRowContainer.tsx │ │ │ │ │ │ ├── RecordMenu.tsx │ │ │ │ │ │ ├── StatisticMenu.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── const.ts │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useCollaborate.ts │ │ │ │ │ │ ├── useIsSelectionLoaded.ts │ │ │ │ │ │ ├── useSelectionOperation.ts │ │ │ │ │ │ └── useSelectionStore.ts │ │ │ │ │ ├── useGridSearchStore.ts │ │ │ │ │ └── utils │ │ │ │ │ │ ├── copyAndPaste.ts │ │ │ │ │ │ ├── getSyncCopyData.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── selection.ts │ │ │ │ │ ├── hooks │ │ │ │ │ └── useToolbarChange.ts │ │ │ │ │ ├── kanban │ │ │ │ │ ├── KanbanView.tsx │ │ │ │ │ ├── KanbanViewBase.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── KanbanCard.tsx │ │ │ │ │ │ ├── KanbanContainer.tsx │ │ │ │ │ │ ├── KanbanStack.tsx │ │ │ │ │ │ ├── KanbanStackContainer.tsx │ │ │ │ │ │ ├── KanbanStackCreator.tsx │ │ │ │ │ │ ├── KanbanStackHeader.tsx │ │ │ │ │ │ ├── KanbanStackTitle.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── interface.ts │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── context │ │ │ │ │ │ ├── KanbanContext.ts │ │ │ │ │ │ ├── KanbanProvider.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useInView.ts │ │ │ │ │ │ └── useKanban.ts │ │ │ │ │ ├── store │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── useKanbanStackCollapsed.ts │ │ │ │ │ ├── type.ts │ │ │ │ │ └── utils │ │ │ │ │ │ ├── card.ts │ │ │ │ │ │ ├── drag.ts │ │ │ │ │ │ ├── filter.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── list │ │ │ │ │ ├── DraggableWrapper.tsx │ │ │ │ │ ├── ExpandViewList.tsx │ │ │ │ │ ├── PinViewItem.tsx │ │ │ │ │ ├── ViewList.tsx │ │ │ │ │ ├── ViewListItem.tsx │ │ │ │ │ ├── useAddView.ts │ │ │ │ │ ├── useDeleteView.ts │ │ │ │ │ └── useDuplicateView.ts │ │ │ │ │ ├── plugin │ │ │ │ │ └── PluginView.tsx │ │ │ │ │ ├── search │ │ │ │ │ ├── SearchButton.tsx │ │ │ │ │ ├── SearchCommand.tsx │ │ │ │ │ └── SearchCountPagination.tsx │ │ │ │ │ ├── tool-bar │ │ │ │ │ ├── CalendarToolBar.tsx │ │ │ │ │ ├── FormToolBar.tsx │ │ │ │ │ ├── GalleryToolBar.tsx │ │ │ │ │ ├── GridToolBar.tsx │ │ │ │ │ ├── KanbanToolBar.tsx │ │ │ │ │ ├── Others.tsx │ │ │ │ │ ├── SharePopover.tsx │ │ │ │ │ ├── ToolBarButton.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── CalendarViewOperators.tsx │ │ │ │ │ │ ├── CoverFieldSelect.tsx │ │ │ │ │ │ ├── GalleryViewOperators.tsx │ │ │ │ │ │ ├── GridViewOperators.tsx │ │ │ │ │ │ ├── KanbanViewOperators.tsx │ │ │ │ │ │ ├── PersonalViewSwitch.tsx │ │ │ │ │ │ ├── UndoRedoButtons.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── useToolBarStore.tsx │ │ │ │ │ ├── hook │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── useViewConfigurable.ts │ │ │ │ │ ├── store │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── useFormModeStore.ts │ │ │ │ │ └── useViewFilterLinkContext.ts │ │ │ │ │ └── types.ts │ │ │ ├── components │ │ │ │ ├── Chart │ │ │ │ │ ├── Chart.tsx │ │ │ │ │ ├── bar.ts │ │ │ │ │ ├── base.ts │ │ │ │ │ ├── createChart.ts │ │ │ │ │ ├── line.tsx │ │ │ │ │ ├── pie.tsx │ │ │ │ │ └── type.ts │ │ │ │ ├── CopyButton.tsx │ │ │ │ ├── LanguagePicker.tsx │ │ │ │ ├── MenuDeleteItem.tsx │ │ │ │ ├── SideBarFooter.tsx │ │ │ │ ├── SpaceSettingContainer.tsx │ │ │ │ ├── ThemePicker.tsx │ │ │ │ ├── Welcom.tsx │ │ │ │ ├── ai-chat │ │ │ │ │ ├── components │ │ │ │ │ │ ├── LoadingDot.tsx │ │ │ │ │ │ ├── Message.tsx │ │ │ │ │ │ ├── MessageContext.tsx │ │ │ │ │ │ ├── MessageInput.tsx │ │ │ │ │ │ ├── MessageMeta.tsx │ │ │ │ │ │ ├── Messages.tsx │ │ │ │ │ │ ├── ModelSelector.tsx │ │ │ │ │ │ ├── message-part │ │ │ │ │ │ │ ├── Markdown.tsx │ │ │ │ │ │ │ ├── ReasonMessagePart.tsx │ │ │ │ │ │ │ ├── TextMessagePart.tsx │ │ │ │ │ │ │ └── ToolMessagePart.tsx │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── use-scroll-to-bottom.ts │ │ │ │ │ ├── context │ │ │ │ │ │ ├── ChatContext.tsx │ │ │ │ │ │ ├── ChatProvider.tsx │ │ │ │ │ │ └── useChatContext.ts │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── useActiveChat.ts │ │ │ │ │ │ ├── useChatEnabled.ts │ │ │ │ │ │ ├── useChatHistory.ts │ │ │ │ │ │ └── useChatMessages.ts │ │ │ │ │ ├── panel │ │ │ │ │ │ ├── ChatContainer.tsx │ │ │ │ │ │ ├── ChatHistory.tsx │ │ │ │ │ │ ├── ChatPanel.tsx │ │ │ │ │ │ ├── ChatPanelHeader.tsx │ │ │ │ │ │ ├── ChatTriggerButton.tsx │ │ │ │ │ │ └── PanelContainer.tsx │ │ │ │ │ ├── store │ │ │ │ │ │ ├── useChatPanelStore.ts │ │ │ │ │ │ └── useChatStore.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── billing │ │ │ │ │ ├── Level.tsx │ │ │ │ │ ├── LevelWithUpgrade.tsx │ │ │ │ │ ├── Status.tsx │ │ │ │ │ └── UsageLimitModal.tsx │ │ │ │ ├── collaborator-manage │ │ │ │ │ ├── base │ │ │ │ │ │ ├── BaseCollaboratorContent.tsx │ │ │ │ │ │ ├── BaseCollaboratorModal.tsx │ │ │ │ │ │ ├── BaseCollaborators.tsx │ │ │ │ │ │ ├── BaseInvite.tsx │ │ │ │ │ │ ├── BaseInviteLink.tsx │ │ │ │ │ │ └── useFilteredRoleStatic.ts │ │ │ │ │ ├── components │ │ │ │ │ │ ├── Collaborator.tsx │ │ │ │ │ │ ├── CollaboratorAdd.tsx │ │ │ │ │ │ ├── CollaboratorItem.tsx │ │ │ │ │ │ ├── CollaboratorList.tsx │ │ │ │ │ │ ├── Invite.tsx │ │ │ │ │ │ ├── InviteLinkItem.tsx │ │ │ │ │ │ └── RoleSelect.tsx │ │ │ │ │ ├── space-inner │ │ │ │ │ │ └── Collaborators.tsx │ │ │ │ │ ├── space │ │ │ │ │ │ ├── Collaborators.tsx │ │ │ │ │ │ ├── SpaceCollaboratorModal.tsx │ │ │ │ │ │ ├── SpaceCollaboratorModalTrigger.tsx │ │ │ │ │ │ ├── SpaceInvite.tsx │ │ │ │ │ │ ├── SpaceInviteLink.tsx │ │ │ │ │ │ └── useFilteredRoleStatic.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── useRoleStatic.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── emoji │ │ │ │ │ ├── Emoji.tsx │ │ │ │ │ └── EmojiPicker.tsx │ │ │ │ ├── expand-record-container │ │ │ │ │ ├── ExpandRecordContainer.tsx │ │ │ │ │ ├── ExpandRecordContainerBase.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── field-setting │ │ │ │ │ ├── DefaultValue.tsx │ │ │ │ │ ├── DynamicFieldEditor.tsx │ │ │ │ │ ├── FieldEditor.spec.tsx │ │ │ │ │ ├── FieldEditor.tsx │ │ │ │ │ ├── FieldOptions.tsx │ │ │ │ │ ├── FieldSetting.tsx │ │ │ │ │ ├── SelectFieldType.tsx │ │ │ │ │ ├── SelectTable.tsx │ │ │ │ │ ├── SystemInfo.tsx │ │ │ │ │ ├── field-ai-config │ │ │ │ │ │ ├── AttachmentFieldAiConfig.tsx │ │ │ │ │ │ ├── FieldAiConfig.tsx │ │ │ │ │ │ ├── MultipleSelectFieldAiConfig.tsx │ │ │ │ │ │ ├── RatingFieldAiConfig.tsx │ │ │ │ │ │ ├── SingleSelectFieldAiConfig.tsx │ │ │ │ │ │ ├── TextFieldAiConfig.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── attachment-select │ │ │ │ │ │ │ │ ├── AttachmentSelect.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── field-select │ │ │ │ │ │ │ │ ├── FieldSelect.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── prompt-editor │ │ │ │ │ │ │ │ ├── PromptEditor.tsx │ │ │ │ │ │ │ │ ├── PromptEditorContainer.tsx │ │ │ │ │ │ │ │ ├── extensions │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ ├── theme.ts │ │ │ │ │ │ │ │ └── variable.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── field-validation │ │ │ │ │ │ └── FieldValidation.tsx │ │ │ │ │ ├── formatting │ │ │ │ │ │ ├── DatetimeFormatting.tsx │ │ │ │ │ │ ├── NumberFormatting.tsx │ │ │ │ │ │ ├── TimeZoneFormatting.tsx │ │ │ │ │ │ └── UnionFormatting.tsx │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── useDefaultFieldName.ts │ │ │ │ │ │ ├── useUpdateLookupOptions.spec.ts │ │ │ │ │ │ └── useUpdateLookupOptions.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── lookup-options │ │ │ │ │ │ ├── LookupFilterOptions.tsx │ │ │ │ │ │ └── LookupOptions.tsx │ │ │ │ │ ├── options │ │ │ │ │ │ ├── CheckboxOptions.tsx │ │ │ │ │ │ ├── CreatedTimeOptions.tsx │ │ │ │ │ │ ├── DateOptions.tsx │ │ │ │ │ │ ├── FormulaOptions.tsx │ │ │ │ │ │ ├── LinkOptions │ │ │ │ │ │ │ ├── LinkOptions.tsx │ │ │ │ │ │ │ ├── MoreLinkOptions.tsx │ │ │ │ │ │ │ ├── SelectTable.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── LongTextOptions.tsx │ │ │ │ │ │ ├── NumberOptions.tsx │ │ │ │ │ │ ├── RatingOptions.tsx │ │ │ │ │ │ ├── RollupOptions.tsx │ │ │ │ │ │ ├── SelectOptions │ │ │ │ │ │ │ ├── ChoiceItem.tsx │ │ │ │ │ │ │ ├── ColorPicker.tsx │ │ │ │ │ │ │ ├── SelectDefaultValue.tsx │ │ │ │ │ │ │ ├── SelectOptions.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── SingleLineTextOptions.tsx │ │ │ │ │ │ └── UserOptions.tsx │ │ │ │ │ ├── show-as │ │ │ │ │ │ ├── MultiNumberShowAs.tsx │ │ │ │ │ │ ├── SingleLineTextShowAs.tsx │ │ │ │ │ │ ├── SingleNumberShowAs.tsx │ │ │ │ │ │ └── UnionShowAs.tsx │ │ │ │ │ ├── type.ts │ │ │ │ │ └── useFieldTypeSubtitle.ts │ │ │ │ ├── index.ts │ │ │ │ ├── notifications │ │ │ │ │ ├── NotificationActionBar.tsx │ │ │ │ │ ├── NotificationIcon.tsx │ │ │ │ │ ├── NotificationItem.tsx │ │ │ │ │ ├── NotificationList.tsx │ │ │ │ │ ├── NotificationsManage.tsx │ │ │ │ │ └── notification-component │ │ │ │ │ │ ├── LinkNotification.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ ├── oauth │ │ │ │ │ ├── OAuthLogo.tsx │ │ │ │ │ └── OAuthScope.tsx │ │ │ │ ├── plugin-context-menu │ │ │ │ │ ├── PluginContextMenu.tsx │ │ │ │ │ ├── PluginContextMenuManageDialog.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── FloatPlugin.tsx │ │ │ │ │ │ └── useFloatPluginPosition.tsx │ │ │ │ │ └── useActiveMenuPlugin.ts │ │ │ │ ├── plugin-panel │ │ │ │ │ ├── PluginLayout.tsx │ │ │ │ │ ├── PluginPanel.tsx │ │ │ │ │ ├── PluginPanelContainer.tsx │ │ │ │ │ ├── PluginPanelEmpty.tsx │ │ │ │ │ ├── PluginPanelHeader.tsx │ │ │ │ │ ├── PluginPanelSelector.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── CreatePluginDialog.tsx │ │ │ │ │ │ ├── CreatePluginPanelDialog.tsx │ │ │ │ │ │ └── PluginItem.tsx │ │ │ │ │ └── hooks │ │ │ │ │ │ ├── useActivePluginPanelId.tsx │ │ │ │ │ │ ├── usePluginPanelStorage.ts │ │ │ │ │ │ └── usePluginPanelStore.ts │ │ │ │ ├── plugin │ │ │ │ │ ├── PluginCenterDialog.tsx │ │ │ │ │ ├── PluginContent.tsx │ │ │ │ │ ├── PluginDetail.tsx │ │ │ │ │ ├── PluginHeader.tsx │ │ │ │ │ ├── PluginRender.tsx │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── iframe-url │ │ │ │ │ │ │ ├── useIframeUrl.tsx │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── useIframeSize.tsx │ │ │ │ │ │ ├── useSyncBasePermissions.ts │ │ │ │ │ │ ├── useSyncSelection.ts │ │ │ │ │ │ ├── useSyncUIConfig.ts │ │ │ │ │ │ ├── useSyncUrlParams.tsx │ │ │ │ │ │ ├── useUIEvent.ts │ │ │ │ │ │ ├── useUtilsEvent.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ └── getSelectionRecords.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── setting │ │ │ │ │ ├── Account.tsx │ │ │ │ │ ├── InteractionSelect.tsx │ │ │ │ │ ├── Notifications.tsx │ │ │ │ │ ├── SettingDialog.tsx │ │ │ │ │ ├── System.tsx │ │ │ │ │ ├── account │ │ │ │ │ │ ├── AddPassword.tsx │ │ │ │ │ │ ├── ChangeEmailDialog.tsx │ │ │ │ │ │ └── ChangePasswordDialog.tsx │ │ │ │ │ ├── integration │ │ │ │ │ │ ├── Detail.tsx │ │ │ │ │ │ ├── Integration.tsx │ │ │ │ │ │ ├── List.tsx │ │ │ │ │ │ └── RevokeButton.tsx │ │ │ │ │ └── useSettingStore.ts │ │ │ │ ├── sidebar │ │ │ │ │ ├── Sidebar.tsx │ │ │ │ │ ├── SidebarContent.tsx │ │ │ │ │ ├── SidebarHeader.tsx │ │ │ │ │ └── SidebarHeaderLeft.tsx │ │ │ │ ├── space │ │ │ │ │ ├── CreateBaseModal.tsx │ │ │ │ │ ├── SpaceActionBar.tsx │ │ │ │ │ ├── SpaceRenaming.tsx │ │ │ │ │ └── template │ │ │ │ │ │ ├── CategoryMenu.tsx │ │ │ │ │ │ ├── CategoryMenuItem.tsx │ │ │ │ │ │ ├── TemplateCard.tsx │ │ │ │ │ │ ├── TemplateDetail.tsx │ │ │ │ │ │ ├── TemplateList.tsx │ │ │ │ │ │ ├── TemplateMain.tsx │ │ │ │ │ │ ├── TemplateModal.tsx │ │ │ │ │ │ ├── TemplateSheet.tsx │ │ │ │ │ │ ├── context.ts │ │ │ │ │ │ ├── hooks │ │ │ │ │ │ └── use-space-id.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── toggle-side-bar │ │ │ │ │ ├── HoverWrapper.tsx │ │ │ │ │ ├── SheetWrapper.tsx │ │ │ │ │ └── constant.ts │ │ │ │ └── user │ │ │ │ │ ├── UserAvatar.tsx │ │ │ │ │ └── UserNav.tsx │ │ │ ├── dashboard │ │ │ │ ├── DashboardGrid.tsx │ │ │ │ ├── DashboardHeader.tsx │ │ │ │ ├── DashboardMain.tsx │ │ │ │ ├── EmptyDashboard.tsx │ │ │ │ ├── Pages.tsx │ │ │ │ ├── TestBaseQuery.tsx │ │ │ │ ├── components │ │ │ │ │ ├── AddPluginDialog.tsx │ │ │ │ │ ├── CreateDashboardDialog.tsx │ │ │ │ │ ├── DashboardSwitcher.tsx │ │ │ │ │ └── PluginItem.tsx │ │ │ │ └── hooks │ │ │ │ │ └── useIsExpandPlugin.ts │ │ │ ├── hooks │ │ │ │ ├── useAI.ts │ │ │ │ ├── useAutoFavicon.tsx │ │ │ │ ├── useBaseUsage.ts │ │ │ │ ├── useBillingLevelConfig.ts │ │ │ │ ├── useBrand.tsx │ │ │ │ ├── useDownLoad.ts │ │ │ │ ├── useEnv.ts │ │ │ │ ├── useHiddenFields.ts │ │ │ │ ├── useInitializationZodI18n.ts │ │ │ │ ├── useIsCloud.ts │ │ │ │ ├── useIsEE.ts │ │ │ │ ├── usePreviewUrl.ts │ │ │ │ ├── useSdkLocale.ts │ │ │ │ └── useSetting.ts │ │ │ ├── layouts │ │ │ │ ├── AdminLayout.tsx │ │ │ │ ├── AppLayout.tsx │ │ │ │ ├── BaseLayout.tsx │ │ │ │ ├── SettingLayout.tsx │ │ │ │ ├── SpaceLayout.tsx │ │ │ │ ├── SpacePageTitle.tsx │ │ │ │ ├── SpaceSettingLayout.tsx │ │ │ │ ├── index.ts │ │ │ │ └── useSettingRoute.tsx │ │ │ └── utils │ │ │ │ ├── clipboard.spec.ts │ │ │ │ ├── clipboard.ts │ │ │ │ ├── file.ts │ │ │ │ ├── get-mod-key-str.ts │ │ │ │ ├── index.ts │ │ │ │ ├── is-https.ts │ │ │ │ ├── is-local.ts │ │ │ │ └── uploadFile.ts │ │ ├── auth │ │ │ ├── components │ │ │ │ ├── DescContent.tsx │ │ │ │ ├── LayoutMain.tsx │ │ │ │ ├── Rectangles.tsx │ │ │ │ ├── SendVerificationButton.tsx │ │ │ │ ├── SignForm.tsx │ │ │ │ ├── SocialAuth.tsx │ │ │ │ ├── TeableFooter.tsx │ │ │ │ └── Terms.tsx │ │ │ ├── pages │ │ │ │ ├── ForgetPasswordPage.tsx │ │ │ │ ├── LoginPage.tsx │ │ │ │ └── ResetPasswordPage.tsx │ │ │ └── useDisallowSignUp.ts │ │ ├── i18n │ │ │ ├── auth.config.ts │ │ │ ├── automation.tsx │ │ │ ├── base.config.ts │ │ │ ├── dashboard.config.ts │ │ │ ├── developer.config.ts │ │ │ ├── oauth-app.config.ts │ │ │ ├── personal-access-token.config.ts │ │ │ ├── setting-plugin.config.ts │ │ │ ├── share.config.ts │ │ │ ├── space.config.ts │ │ │ ├── system.config.ts │ │ │ └── table.config.ts │ │ └── system │ │ │ └── pages │ │ │ ├── ErrorPage.tsx │ │ │ ├── ForbiddenPage.tsx │ │ │ ├── NotFoundPage.tsx │ │ │ ├── PaymentRequired.tsx │ │ │ ├── __tests__ │ │ │ ├── ErrorPage.test.tsx │ │ │ └── NotFoundPage.test.tsx │ │ │ └── index.ts │ ├── lib │ │ ├── emoji-color.ts │ │ ├── ensureLogin.ts │ │ ├── get-brand.ts │ │ ├── i18n │ │ │ ├── I18nNamespace.types.ts │ │ │ ├── acceptHeader.ts │ │ │ ├── getLocale.ts │ │ │ ├── getServerSideTranslations.ts │ │ │ ├── getTranslationsProps.ts │ │ │ └── index.ts │ │ ├── server-env.ts │ │ ├── space-role-checker.ts │ │ ├── type.ts │ │ ├── view-pages-data.ts │ │ ├── withAuthSSR.ts │ │ └── withEnv.ts │ ├── middleware.ts │ ├── pages │ │ ├── 402.tsx │ │ ├── 403.tsx │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── _document.tsx │ │ ├── _error.tsx │ │ ├── _monitor │ │ │ ├── preview │ │ │ │ └── error-page.tsx │ │ │ └── sentry │ │ │ │ ├── csr-page.tsx │ │ │ │ └── ssr-page.tsx │ │ ├── admin │ │ │ ├── setting.tsx │ │ │ └── template.tsx │ │ ├── api │ │ │ └── _monitor │ │ │ │ ├── healthcheck.ts │ │ │ │ └── sentry.ts │ │ ├── auth │ │ │ ├── forget-password.tsx │ │ │ ├── login.tsx │ │ │ ├── reset-password.tsx │ │ │ └── signup.tsx │ │ ├── base │ │ │ ├── [baseId].tsx │ │ │ └── [baseId] │ │ │ │ ├── [tableId].tsx │ │ │ │ ├── [tableId] │ │ │ │ └── [viewId].tsx │ │ │ │ ├── authority-matrix.tsx │ │ │ │ ├── automation.tsx │ │ │ │ ├── dashboard.tsx │ │ │ │ ├── design.tsx │ │ │ │ └── trash.tsx │ │ ├── developer │ │ │ └── tool │ │ │ │ └── query-builder.tsx │ │ ├── index.tsx │ │ ├── invite │ │ │ └── index.tsx │ │ ├── oauth │ │ │ └── decision.tsx │ │ ├── setting │ │ │ ├── index.tsx │ │ │ ├── oauth-app.tsx │ │ │ ├── personal-access-token.tsx │ │ │ └── plugin.tsx │ │ ├── share │ │ │ └── [shareId] │ │ │ │ └── view │ │ │ │ ├── auth.tsx │ │ │ │ └── index.tsx │ │ └── space │ │ │ ├── [spaceId].tsx │ │ │ ├── [spaceId] │ │ │ └── setting │ │ │ │ ├── collaborator.tsx │ │ │ │ ├── general.tsx │ │ │ │ └── integration.tsx │ │ │ ├── index.tsx │ │ │ ├── shared-base.tsx │ │ │ └── trash.tsx │ ├── store │ │ ├── message.ts │ │ └── user.ts │ ├── styles │ │ ├── github-markdown.css │ │ └── global.css │ ├── themes │ │ ├── colors │ │ │ └── index.ts │ │ ├── shared │ │ │ ├── __tests__ │ │ │ │ └── colors.test.ts │ │ │ ├── browser-fonts.js │ │ │ └── colors.js │ │ ├── tailwind │ │ │ └── tailwind.theme.js │ │ ├── type.ts │ │ └── utils.ts │ └── types.d │ │ ├── i18next.d.ts │ │ ├── next-i18next.d.ts │ │ ├── react-svgr.d.ts │ │ └── umami.d.ts │ ├── tailwind.config.js │ ├── tsconfig.eslint.json │ ├── tsconfig.json │ ├── tsconfig.scripts.json │ └── vitest.config.ts ├── commitlint.config.js ├── crowdin.yml ├── docker-bake.hcl ├── dockers ├── .env ├── cache-redis.yml ├── database-postgres.yml ├── examples │ ├── cluster │ │ ├── .env │ │ ├── README.md │ │ ├── docker-compose.yaml │ │ └── gateway │ │ │ └── conf.d │ │ │ ├── default.conf │ │ │ └── minio.conf │ ├── docker-swarm │ │ ├── .env │ │ ├── README.md │ │ ├── deploy.sh │ │ ├── docker-compose.app.yml │ │ ├── docker-compose.default.yml │ │ ├── docker-compose.gateway.yml │ │ ├── docker-compose.kit.yml │ │ └── gateway │ │ │ └── conf.d │ │ │ ├── default.conf │ │ │ └── minio.conf │ └── standalone │ │ ├── .env │ │ ├── README.md │ │ └── docker-compose.yaml ├── integration-test.yml ├── networks.yml ├── storage-minio.yml └── teable │ ├── Dockerfile │ └── Dockerfile.db-migrate ├── lint-staged.common.js ├── lint-staged.config.js ├── monorepo.code-workspace ├── package.json ├── packages ├── common-i18n │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .idea │ │ ├── common-i18n.iml │ │ └── modules.xml │ ├── LICENSE │ ├── lint-staged.config.js │ ├── package.json │ ├── src │ │ ├── I18nNamespaces.ts │ │ ├── index.ts │ │ └── locales │ │ │ ├── de │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── dashboard.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── plugin.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ ├── en │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── dashboard.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── plugin.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ ├── es │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── dashboard.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── plugin.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ ├── fr │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ ├── it │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── dashboard.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── plugin.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ ├── ja │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ ├── ru │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── dashboard.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── plugin.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ ├── tr │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── dashboard.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── plugin.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ ├── uk │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── dashboard.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── plugin.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ │ │ └── zh │ │ │ ├── auth.json │ │ │ ├── common.json │ │ │ ├── dashboard.json │ │ │ ├── developer.json │ │ │ ├── oauth.json │ │ │ ├── plugin.json │ │ │ ├── sdk.json │ │ │ ├── setting.json │ │ │ ├── share.json │ │ │ ├── space.json │ │ │ ├── system.json │ │ │ ├── table.json │ │ │ ├── token.json │ │ │ └── zod.json │ └── tsconfig.json ├── core │ ├── .escheckrc │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .idea │ │ ├── core.iml │ │ └── modules.xml │ ├── .size-limit.cjs │ ├── LICENSE │ ├── lint-staged.config.js │ ├── package.json │ ├── src │ │ ├── array │ │ │ ├── ArrayUtils.spec.ts │ │ │ ├── ArrayUtils.ts │ │ │ └── index.ts │ │ ├── asserts │ │ │ ├── __tests__ │ │ │ │ └── asserts.test.ts │ │ │ ├── asserts.ts │ │ │ ├── index.ts │ │ │ └── lang.ts │ │ ├── auth │ │ │ ├── actions.ts │ │ │ ├── anonymous.ts │ │ │ ├── index.ts │ │ │ ├── me-tag.ts │ │ │ ├── oauth.ts │ │ │ ├── permission.ts │ │ │ ├── role │ │ │ │ ├── base.ts │ │ │ │ ├── constant.ts │ │ │ │ ├── index.ts │ │ │ │ ├── share.ts │ │ │ │ ├── space.ts │ │ │ │ ├── table.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ ├── system.ts │ │ │ └── types.ts │ │ ├── convert │ │ │ ├── __tests__ │ │ │ │ └── string-convert.test.ts │ │ │ ├── index.ts │ │ │ ├── nulls-to-undefined.ts │ │ │ └── string-convert.ts │ │ ├── errors │ │ │ ├── http │ │ │ │ ├── constant.ts │ │ │ │ ├── http-response.types.ts │ │ │ │ ├── http.error.ts │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── formula │ │ │ ├── conversion.visitor.spec.ts │ │ │ ├── conversion.visitor.ts │ │ │ ├── error.listener.ts │ │ │ ├── evaluate.ts │ │ │ ├── field-reference.visitor.spec.ts │ │ │ ├── field-reference.visitor.ts │ │ │ ├── functions │ │ │ │ ├── array.spec.ts │ │ │ │ ├── array.ts │ │ │ │ ├── common.ts │ │ │ │ ├── date-time.spec.ts │ │ │ │ ├── date-time.ts │ │ │ │ ├── factory.ts │ │ │ │ ├── logical.spec.ts │ │ │ │ ├── logical.ts │ │ │ │ ├── numeric.spec.ts │ │ │ │ ├── numeric.ts │ │ │ │ ├── system.spec.ts │ │ │ │ ├── system.ts │ │ │ │ ├── text.spec.ts │ │ │ │ └── text.ts │ │ │ ├── index.ts │ │ │ ├── parser │ │ │ │ ├── Formula.g4 │ │ │ │ ├── Formula.interp │ │ │ │ ├── Formula.tokens │ │ │ │ ├── Formula.ts │ │ │ │ ├── FormulaLexer.g4 │ │ │ │ ├── FormulaLexer.interp │ │ │ │ ├── FormulaLexer.tokens │ │ │ │ ├── FormulaLexer.ts │ │ │ │ ├── FormulaVisitor.ts │ │ │ │ └── README.md │ │ │ ├── typed-value-converter.spec.ts │ │ │ ├── typed-value-converter.ts │ │ │ ├── typed-value.ts │ │ │ ├── visitor.spec.ts │ │ │ └── visitor.ts │ │ ├── index.ts │ │ ├── models │ │ │ ├── aggregation │ │ │ │ ├── index.ts │ │ │ │ ├── statistic.spec.ts │ │ │ │ ├── statistic.ts │ │ │ │ └── statistics-func.enum.ts │ │ │ ├── channel.ts │ │ │ ├── field │ │ │ │ ├── ai-config │ │ │ │ │ ├── attachment.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── multiple-select.ts │ │ │ │ │ ├── rating.ts │ │ │ │ │ ├── single-select.ts │ │ │ │ │ └── text.ts │ │ │ │ ├── cell-value-validation.ts │ │ │ │ ├── color-utils.spec.ts │ │ │ │ ├── color-utils.ts │ │ │ │ ├── colors.ts │ │ │ │ ├── constant.ts │ │ │ │ ├── derivate │ │ │ │ │ ├── abstract │ │ │ │ │ │ ├── formula.field.abstract.ts │ │ │ │ │ │ ├── select.field.abstract.spec.ts │ │ │ │ │ │ ├── select.field.abstract.ts │ │ │ │ │ │ └── user.field.abstract.ts │ │ │ │ │ ├── attachment.field.spec.ts │ │ │ │ │ ├── attachment.field.ts │ │ │ │ │ ├── auto-number.field.spec.ts │ │ │ │ │ ├── auto-number.field.ts │ │ │ │ │ ├── checkbox.field.spec.ts │ │ │ │ │ ├── checkbox.field.ts │ │ │ │ │ ├── created-by.field.ts │ │ │ │ │ ├── created-time.field.spec.ts │ │ │ │ │ ├── created-time.field.ts │ │ │ │ │ ├── date.field.spec.ts │ │ │ │ │ ├── date.field.ts │ │ │ │ │ ├── formula.field.spec.ts │ │ │ │ │ ├── formula.field.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── last-modified-by.field.ts │ │ │ │ │ ├── last-modified-time.field.spec.ts │ │ │ │ │ ├── last-modified-time.field.ts │ │ │ │ │ ├── link.field.spec.ts │ │ │ │ │ ├── link.field.ts │ │ │ │ │ ├── long-text.field.spec.ts │ │ │ │ │ ├── long-text.field.ts │ │ │ │ │ ├── multiple-select.field.spec.ts │ │ │ │ │ ├── multiple-select.field.ts │ │ │ │ │ ├── number.field.spec.ts │ │ │ │ │ ├── number.field.ts │ │ │ │ │ ├── rating.field.spec.ts │ │ │ │ │ ├── rating.field.ts │ │ │ │ │ ├── rollup.field.spec.ts │ │ │ │ │ ├── rollup.field.ts │ │ │ │ │ ├── single-line-text.field.spec.ts │ │ │ │ │ ├── single-line-text.field.ts │ │ │ │ │ ├── single-select.field.spec.ts │ │ │ │ │ ├── single-select.field.ts │ │ │ │ │ ├── user.field.spec.ts │ │ │ │ │ └── user.field.ts │ │ │ │ ├── field-validation.ts │ │ │ │ ├── field.schema.spec.ts │ │ │ │ ├── field.schema.ts │ │ │ │ ├── field.ts │ │ │ │ ├── formatting │ │ │ │ │ ├── datetime.spec.ts │ │ │ │ │ ├── datetime.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── number.spec.ts │ │ │ │ │ ├── number.ts │ │ │ │ │ └── time-zone.ts │ │ │ │ ├── index.ts │ │ │ │ ├── options.schema.ts │ │ │ │ └── show-as │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── number.ts │ │ │ │ │ └── text.ts │ │ │ ├── index.ts │ │ │ ├── interface.ts │ │ │ ├── notification │ │ │ │ ├── action-trigger.schema.ts │ │ │ │ ├── index.ts │ │ │ │ ├── notification.enum.ts │ │ │ │ └── notification.schema.ts │ │ │ ├── op.ts │ │ │ ├── record │ │ │ │ ├── index.ts │ │ │ │ └── record.ts │ │ │ ├── table │ │ │ │ ├── index.ts │ │ │ │ └── table.ts │ │ │ └── view │ │ │ │ ├── column-meta.schema.ts │ │ │ │ ├── constant.ts │ │ │ │ ├── derivate │ │ │ │ ├── calendar.view.ts │ │ │ │ ├── form.view.ts │ │ │ │ ├── gallery.view.ts │ │ │ │ ├── grid.view.ts │ │ │ │ ├── index.ts │ │ │ │ ├── kanban.view.ts │ │ │ │ └── plugin.view.ts │ │ │ │ ├── filter │ │ │ │ ├── conjunction.ts │ │ │ │ ├── filter-item.ts │ │ │ │ ├── filter.spec.ts │ │ │ │ ├── filter.ts │ │ │ │ ├── index.ts │ │ │ │ ├── operator.spec.ts │ │ │ │ └── operator.ts │ │ │ │ ├── group │ │ │ │ ├── group.ts │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── option.schema.spec.ts │ │ │ │ ├── option.schema.ts │ │ │ │ ├── query.replace.ts │ │ │ │ ├── sort │ │ │ │ ├── index.ts │ │ │ │ ├── sort-func.enum.ts │ │ │ │ ├── sort.schema.spec.ts │ │ │ │ └── sort.ts │ │ │ │ ├── view.schema.ts │ │ │ │ └── view.ts │ │ ├── op-builder │ │ │ ├── common.spec.ts │ │ │ ├── common.ts │ │ │ ├── field │ │ │ │ ├── add-column-meta.spec.ts │ │ │ │ ├── add-column-meta.ts │ │ │ │ ├── add-field.ts │ │ │ │ ├── delete-column-meta.spec.ts │ │ │ │ ├── delete-column-meta.ts │ │ │ │ ├── field-op-builder.ts │ │ │ │ ├── index.ts │ │ │ │ ├── set-field-property.spec.ts │ │ │ │ └── set-field-property.ts │ │ │ ├── index.ts │ │ │ ├── interface.ts │ │ │ ├── op-builder.abstract.ts │ │ │ ├── record │ │ │ │ ├── add-record.ts │ │ │ │ ├── index.ts │ │ │ │ ├── record-op-builder.ts │ │ │ │ └── set-record.ts │ │ │ ├── table │ │ │ │ ├── add-table.ts │ │ │ │ ├── index.ts │ │ │ │ ├── set-table-property.ts │ │ │ │ └── table-op-builder.ts │ │ │ └── view │ │ │ │ ├── add-view.ts │ │ │ │ ├── index.ts │ │ │ │ ├── set-view-property.ts │ │ │ │ ├── update-view-column-meta.ts │ │ │ │ └── view-op-builder.ts │ │ ├── query │ │ │ ├── index.ts │ │ │ ├── json-error.strategy.ts │ │ │ ├── json.visitor.spec.ts │ │ │ ├── json.visitor.ts │ │ │ └── parser │ │ │ │ ├── Query.g4 │ │ │ │ ├── Query.interp │ │ │ │ ├── Query.tokens │ │ │ │ ├── Query.ts │ │ │ │ ├── QueryLexer.g4 │ │ │ │ ├── QueryLexer.interp │ │ │ │ ├── QueryLexer.tokens │ │ │ │ ├── QueryLexer.ts │ │ │ │ └── QueryVisitor.ts │ │ ├── typeguards │ │ │ ├── __tests__ │ │ │ │ └── typeguards.test.ts │ │ │ ├── index.ts │ │ │ ├── json-api │ │ │ │ ├── __tests__ │ │ │ │ │ └── json-api-typeguard.test.ts │ │ │ │ ├── index.ts │ │ │ │ ├── json-api-response.types.ts │ │ │ │ └── json-api.typeguard.ts │ │ │ └── typeguards.ts │ │ ├── types │ │ │ ├── either-or.ts │ │ │ ├── ensure-keys.ts │ │ │ ├── index.ts │ │ │ ├── make-optional.ts │ │ │ ├── make-required.ts │ │ │ ├── remove-null.ts │ │ │ ├── snapshot-query.ts │ │ │ └── un-promisify.ts │ │ ├── utils │ │ │ ├── clipboard.spec.ts │ │ │ ├── clipboard.ts │ │ │ ├── date.spec.ts │ │ │ ├── date.ts │ │ │ ├── dsn-parser.ts │ │ │ ├── enum.ts │ │ │ ├── get-random-int.spec.ts │ │ │ ├── get-random-int.ts │ │ │ ├── get-uniq-name.spec.ts │ │ │ ├── get-uniq-name.ts │ │ │ ├── id-generator.spec.ts │ │ │ ├── id-generator.ts │ │ │ ├── index.ts │ │ │ ├── minidenticon.ts │ │ │ └── replace-suffix.ts │ │ └── zod.ts │ ├── tsconfig.build.json │ ├── tsconfig.eslint.json │ ├── tsconfig.json │ ├── vitest.config.ts │ └── vitest.setup.js ├── db-main-prisma │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .idea │ │ ├── db-main-prisma.iml │ │ └── modules.xml │ ├── LICENSE │ ├── README.md │ ├── lint-staged.config.js │ ├── package.json │ ├── prisma │ │ ├── postgres │ │ │ ├── migrations │ │ │ │ ├── 20240308114704_initial_database │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240313062534_add_credit │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240409081450_field_order │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240410190501_primary_field_visible │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240416092001_clean_useless_tables │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240528060827_add_pin_resource │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240625032002_add_admin │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240626072754_add_setting_table │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240628115120_add_space_invitation │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240702084258_add_oauth │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240708080014_oauth_revoke │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240712040045_remove_bucket │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240716070632_notification_url_path │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240806110415_add_record_history │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240814074637_update_collaborator │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240906084530_add_trash │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240913075702_add_dashboard_plugin │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240919032636_add_comment │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241008161823_share_meta │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241031080906_add_attachment_thumbnail │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241126085325_add_ref_meta │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241128112023_add_ai_config │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241205121129_add_table_trash │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241223100142_collaborator_support_org │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241226111824_remove_collaborator_foreign_user │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250115084212_add_enable_email_verification_setting │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250117105433_update_view │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250214080105_add_integration │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250217092955_add_table_plugin │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250218075500_add_plugin_context_menu │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250320062220_user_last_visit │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250328035739_brand │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250402105144_add_template │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250406145144_add_share_id_unique │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250409093339_add_task_tables │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250410102941_update_task_table │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250416113238_add_template_markdown_description │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250418091636_add_db_table_name_index │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250509062715_require_primary_key │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250513085306_add_ai_robot_user │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250520081803_update_user_last_visit │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250520103546_add_user_trial_used │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250526042029_repair_reference_caused_by_formula_duplicate │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250604101438_update_access_token_full_access │ │ │ │ │ └── migration.sql │ │ │ │ └── migration_lock.toml │ │ │ └── schema.prisma │ │ ├── seed.ts │ │ ├── sqlite │ │ │ ├── migrations │ │ │ │ ├── 20240308114656_initial_database │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240313061543_add_credit │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240409081445_field_order │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240416091909_clean_useless_tables │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240528055850_add_pin_resource │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240528060824_add_pin_resource │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240625031955_add_admin │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240626072703_add_setting_table │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240628115107_add_space_invitation │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240702084255_add_oauth │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240708080010_oauth_revoke │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240712040040_remove_bucket │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240716070608_notification_url_path │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240806110404_add_record_history │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240814074632_update_collaborator │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240906084521_add_trash │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240913075658_add_dashboard_plugin │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20240919032621_add_comment │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241031080903_add_attachment_thumbnail │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241126081006_add_ref_meta │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241128112016_add_ai_config │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241205121154_add_table_trash │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241223100135_collaborator_support_org │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241226111815_remove_collaborator_foreign_user │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250115084207_add_enable_email_verification_setting │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250117105406_update_view │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250214080102_add_integration │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250217092948_add_table_plugin │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250218075455_add_plugin_context_menu │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250320062213_user_last_visit │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250328040207_brand │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250402105138_add_template │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250406145126_add_share_id_unique │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250409093334_add_task_tables │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250410102938_update_task_table │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250416113234_add_template_markdown_description │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250418091633_add_db_table_name_index │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250509062710_require_primary_key │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250513085303_add_ai_robot_user │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250520081750_update_user_last_visit │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250520103541_add_user_trial_used │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250526042154_repair_reference_caused_by_formula_duplicate │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20250604101438_update_access_token_full_access │ │ │ │ │ └── migration.sql │ │ │ │ └── migration_lock.toml │ │ │ └── schema.prisma │ │ └── template.prisma │ ├── src │ │ ├── index.ts │ │ ├── prisma.module.ts │ │ ├── prisma.service.ts │ │ ├── seeds │ │ │ ├── e2e │ │ │ │ ├── space-seeds.ts │ │ │ │ └── user-seeds.ts │ │ │ └── seed.abstract.ts │ │ └── utils.ts │ ├── tsconfig.eslint.json │ └── tsconfig.json ├── eslint-config-bases │ ├── .eslintrc.cjs │ ├── .idea │ │ ├── eslint-config-bases.iml │ │ └── modules.xml │ ├── LICENSE │ ├── lint-staged.config.js │ ├── package.json │ ├── src │ │ ├── bases │ │ │ ├── index.js │ │ │ ├── jest.js │ │ │ ├── mdx.js │ │ │ ├── playwright.js │ │ │ ├── prettier-config.js │ │ │ ├── prettier-plugin.js │ │ │ ├── react-query.js │ │ │ ├── react.js │ │ │ ├── regexp.js │ │ │ ├── rtl.js │ │ │ ├── sonar.js │ │ │ ├── storybook.js │ │ │ ├── tailwind.js │ │ │ └── typescript.js │ │ ├── helpers │ │ │ ├── getDefaultIgnorePatterns.js │ │ │ ├── getPrettierConfig.js │ │ │ └── index.js │ │ ├── index.js │ │ ├── patch │ │ │ └── modern-module-resolution.js │ │ └── prettier.base.config.js │ └── tsconfig.json ├── icons │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .idea │ │ ├── icons.iml │ │ └── modules.xml │ ├── LICENSE │ ├── package.json │ ├── scripts │ │ └── generate.mjs │ ├── src │ │ ├── components │ │ │ ├── A.tsx │ │ │ ├── Admin.tsx │ │ │ ├── AiAction.tsx │ │ │ ├── AlertCircle.tsx │ │ │ ├── AlertTriangle.tsx │ │ │ ├── Anthropic.tsx │ │ │ ├── Apple.tsx │ │ │ ├── Array.tsx │ │ │ ├── ArrowDown.tsx │ │ │ ├── ArrowLeft.tsx │ │ │ ├── ArrowRight.tsx │ │ │ ├── ArrowUp.tsx │ │ │ ├── ArrowUpDown.tsx │ │ │ ├── ArrowUpRight.tsx │ │ │ ├── Audio.tsx │ │ │ ├── Azure.tsx │ │ │ ├── BarChart2.tsx │ │ │ ├── Bell.tsx │ │ │ ├── Boolean.tsx │ │ │ ├── Building2.tsx │ │ │ ├── Calendar.tsx │ │ │ ├── Check.tsx │ │ │ ├── CheckCircle2.tsx │ │ │ ├── CheckSquare.tsx │ │ │ ├── Checked.tsx │ │ │ ├── ChevronDown.tsx │ │ │ ├── ChevronLeft.tsx │ │ │ ├── ChevronRight.tsx │ │ │ ├── ChevronUp.tsx │ │ │ ├── ChevronsLeft.tsx │ │ │ ├── ChevronsRight.tsx │ │ │ ├── ChevronsUpDown.tsx │ │ │ ├── Circle.tsx │ │ │ ├── ClipboardList.tsx │ │ │ ├── Clock4.tsx │ │ │ ├── Code.tsx │ │ │ ├── Code2.tsx │ │ │ ├── Cohere.tsx │ │ │ ├── Component.tsx │ │ │ ├── Condition.tsx │ │ │ ├── Copy.tsx │ │ │ ├── CreateRecord.tsx │ │ │ ├── CreditCard.tsx │ │ │ ├── Database.tsx │ │ │ ├── DeepThinking.tsx │ │ │ ├── Deepseek.tsx │ │ │ ├── DivideCircle.tsx │ │ │ ├── DivideSquare.tsx │ │ │ ├── DollarSign.tsx │ │ │ ├── Download.tsx │ │ │ ├── DraggableHandle.tsx │ │ │ ├── Edit.tsx │ │ │ ├── Expand.tsx │ │ │ ├── ExpandAll.tsx │ │ │ ├── Export.tsx │ │ │ ├── Eye.tsx │ │ │ ├── EyeOff.tsx │ │ │ ├── File.tsx │ │ │ ├── FileAudio.tsx │ │ │ ├── FileCsv.tsx │ │ │ ├── FileDocument.tsx │ │ │ ├── FileExcel.tsx │ │ │ ├── FileFont.tsx │ │ │ ├── FileImage.tsx │ │ │ ├── FileJson.tsx │ │ │ ├── FilePack.tsx │ │ │ ├── FilePdf.tsx │ │ │ ├── FilePresentation.tsx │ │ │ ├── FileQuestion.tsx │ │ │ ├── FileScript.tsx │ │ │ ├── FileSpreadsheet.tsx │ │ │ ├── FileText.tsx │ │ │ ├── FileUnknown.tsx │ │ │ ├── FileVideo.tsx │ │ │ ├── Filter.tsx │ │ │ ├── Flame.tsx │ │ │ ├── FreezeColumn.tsx │ │ │ ├── Frown.tsx │ │ │ ├── Gauge.tsx │ │ │ ├── GetRecord.tsx │ │ │ ├── Github.tsx │ │ │ ├── GithubLogo.tsx │ │ │ ├── GoogleLogo.tsx │ │ │ ├── Hash.tsx │ │ │ ├── Heart.tsx │ │ │ ├── HelpCircle.tsx │ │ │ ├── History.tsx │ │ │ ├── Home.tsx │ │ │ ├── HttpRequest.tsx │ │ │ ├── Image.tsx │ │ │ ├── ImageGeneration.tsx │ │ │ ├── Import.tsx │ │ │ ├── Inbox.tsx │ │ │ ├── Integration.tsx │ │ │ ├── Kanban.tsx │ │ │ ├── Key.tsx │ │ │ ├── Layers.tsx │ │ │ ├── LayoutGrid.tsx │ │ │ ├── LayoutList.tsx │ │ │ ├── LayoutTemplate.tsx │ │ │ ├── License.tsx │ │ │ ├── Lingyiwanwu.tsx │ │ │ ├── Link.tsx │ │ │ ├── ListChecks.tsx │ │ │ ├── ListOrdered.tsx │ │ │ ├── Loader2.tsx │ │ │ ├── Lock.tsx │ │ │ ├── LongText.tsx │ │ │ ├── MagicAi.tsx │ │ │ ├── Mail.tsx │ │ │ ├── MarkUnread.tsx │ │ │ ├── Maximize2.tsx │ │ │ ├── Menu.tsx │ │ │ ├── MessageSquare.tsx │ │ │ ├── Minimize2.tsx │ │ │ ├── Mistral.tsx │ │ │ ├── Moon.tsx │ │ │ ├── MoreHorizontal.tsx │ │ │ ├── Network.tsx │ │ │ ├── Object.tsx │ │ │ ├── Ollama.tsx │ │ │ ├── Openai.tsx │ │ │ ├── PackageCheck.tsx │ │ │ ├── PaintBucket.tsx │ │ │ ├── Pencil.tsx │ │ │ ├── Percent.tsx │ │ │ ├── Phone.tsx │ │ │ ├── Play.tsx │ │ │ ├── Plus.tsx │ │ │ ├── PlusCircle.tsx │ │ │ ├── Puzzle.tsx │ │ │ ├── Qrcode.tsx │ │ │ ├── Qwen.tsx │ │ │ ├── Redo2.tsx │ │ │ ├── RefreshCcw.tsx │ │ │ ├── RotateCw.tsx │ │ │ ├── Search.tsx │ │ │ ├── SendMail.tsx │ │ │ ├── Settings.tsx │ │ │ ├── Share2.tsx │ │ │ ├── Sheet.tsx │ │ │ ├── ShieldCheck.tsx │ │ │ ├── Sidebar.tsx │ │ │ ├── SortAsc.tsx │ │ │ ├── Square.tsx │ │ │ ├── Star.tsx │ │ │ ├── StretchHorizontal.tsx │ │ │ ├── Sun.tsx │ │ │ ├── SunMedium.tsx │ │ │ ├── Table2.tsx │ │ │ ├── Teable.tsx │ │ │ ├── TeableNew.tsx │ │ │ ├── ThumbsUp.tsx │ │ │ ├── Translation.tsx │ │ │ ├── Trash.tsx │ │ │ ├── Trash2.tsx │ │ │ ├── Undo2.tsx │ │ │ ├── UpdateRecord.tsx │ │ │ ├── User.tsx │ │ │ ├── UserEdit.tsx │ │ │ ├── UserPlus.tsx │ │ │ ├── Users.tsx │ │ │ ├── Video.tsx │ │ │ ├── Webhook.tsx │ │ │ ├── X.tsx │ │ │ ├── Xai.tsx │ │ │ ├── Zap.tsx │ │ │ ├── Zhipu.tsx │ │ │ ├── ZoomIn.tsx │ │ │ └── ZoomOut.tsx │ │ └── index.ts │ ├── tsconfig.eslint.json │ └── tsconfig.json ├── openapi │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .idea │ │ ├── modules.xml │ │ └── openapi.iml │ ├── LICENSE │ ├── lint-staged.config.js │ ├── package.json │ ├── src │ │ ├── access-token │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── list.ts │ │ │ ├── refresh.ts │ │ │ ├── types.ts │ │ │ └── update.ts │ │ ├── admin │ │ │ ├── index.ts │ │ │ ├── plugin │ │ │ │ ├── index.ts │ │ │ │ ├── publish.ts │ │ │ │ └── unpublish.ts │ │ │ └── setting │ │ │ │ ├── get-public.ts │ │ │ │ ├── get.ts │ │ │ │ ├── index.ts │ │ │ │ ├── update.ts │ │ │ │ └── upload-logo.ts │ │ ├── aggregation │ │ │ ├── get-aggregation.ts │ │ │ ├── get-calendar-daily-collection.ts │ │ │ ├── get-group-points.ts │ │ │ ├── get-row-count.ts │ │ │ ├── get-search-by-index.ts │ │ │ ├── get-search-count.ts │ │ │ ├── get-task-status-collection.ts │ │ │ ├── index.ts │ │ │ └── type.ts │ │ ├── ai │ │ │ ├── generate-stream.ts │ │ │ ├── get-config.ts │ │ │ └── index.ts │ │ ├── attachment │ │ │ ├── index.ts │ │ │ ├── notify.ts │ │ │ ├── read-file.ts │ │ │ ├── signature.ts │ │ │ └── upload-file.ts │ │ ├── auth │ │ │ ├── add-password.ts │ │ │ ├── change-email.ts │ │ │ ├── change-password.ts │ │ │ ├── index.ts │ │ │ ├── reset-password.ts │ │ │ ├── send-change-email-code.ts │ │ │ ├── send-reset-password-email.ts │ │ │ ├── send-signup-verification-code.ts │ │ │ ├── signin.ts │ │ │ ├── signout.ts │ │ │ ├── signup.ts │ │ │ ├── temp-token.ts │ │ │ ├── types.ts │ │ │ ├── user-me.ts │ │ │ └── user.ts │ │ ├── axios.ts │ │ ├── base │ │ │ ├── all-list.ts │ │ │ ├── collaborator-add.ts │ │ │ ├── collaborator-delete.ts │ │ │ ├── collaborator-get-list-user.ts │ │ │ ├── collaborator-get-list.ts │ │ │ ├── collaborator-update.ts │ │ │ ├── create-from-template.ts │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── duplicate.ts │ │ │ ├── export.ts │ │ │ ├── get-permission.ts │ │ │ ├── get-shared-base.ts │ │ │ ├── get.ts │ │ │ ├── import.ts │ │ │ ├── index.ts │ │ │ ├── invitation-create-link.ts │ │ │ ├── invitation-delete-link.ts │ │ │ ├── invitation-email.ts │ │ │ ├── invitation-get-link-list.ts │ │ │ ├── invitation-update-link.ts │ │ │ ├── move.ts │ │ │ ├── permanent-delete.ts │ │ │ ├── query-data │ │ │ │ ├── index.ts │ │ │ │ ├── route.ts │ │ │ │ └── types.ts │ │ │ ├── update-order.ts │ │ │ └── update.ts │ │ ├── billing │ │ │ ├── index.ts │ │ │ └── subscription │ │ │ │ ├── get-subscription-summary-list.ts │ │ │ │ ├── get-subscription-summary.ts │ │ │ │ └── index.ts │ │ ├── chat │ │ │ ├── chat-delete.ts │ │ │ ├── chat-rename.ts │ │ │ ├── get-messages.ts │ │ │ ├── history.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── comment │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── get-attachment-url.ts │ │ │ ├── get-count.ts │ │ │ ├── get-counts-by-query.ts │ │ │ ├── get-list.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── reaction │ │ │ │ ├── constant.ts │ │ │ │ ├── create-reaction.ts │ │ │ │ ├── delete-reaction.ts │ │ │ │ └── index.ts │ │ │ ├── subscribe │ │ │ │ ├── create-subscribe.ts │ │ │ │ ├── delete-subscribe.ts │ │ │ │ ├── get-subscribe.ts │ │ │ │ └── index.ts │ │ │ ├── types.ts │ │ │ └── update.ts │ │ ├── dashboard │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── duplicate-installed.ts │ │ │ ├── duplicate.ts │ │ │ ├── get-list.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── plugin-get.ts │ │ │ ├── plugin-install.ts │ │ │ ├── plugin-remove.ts │ │ │ ├── plugin-rename.ts │ │ │ ├── plugin-update-storage.ts │ │ │ ├── rename.ts │ │ │ ├── types.ts │ │ │ └── update-layout.ts │ │ ├── db-connection │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── get.ts │ │ │ └── index.ts │ │ ├── export │ │ │ ├── export-csv.ts │ │ │ └── index.ts │ │ ├── field │ │ │ ├── auto-fill-field.ts │ │ │ ├── convert.ts │ │ │ ├── create.ts │ │ │ ├── delete-list.ts │ │ │ ├── delete.ts │ │ │ ├── duplicate.ts │ │ │ ├── filter-link-records.ts │ │ │ ├── get-list.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── stop-fill-field.ts │ │ │ └── update.ts │ │ ├── generate.schema.ts │ │ ├── import │ │ │ ├── analyze.ts │ │ │ ├── constant.ts │ │ │ ├── import-table.ts │ │ │ ├── index.ts │ │ │ ├── inplace-import-table.ts │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── integrity │ │ │ ├── index.ts │ │ │ ├── link-check.ts │ │ │ └── link-fix.ts │ │ ├── invitation │ │ │ ├── accept.ts │ │ │ └── index.ts │ │ ├── notification │ │ │ ├── get-list.ts │ │ │ ├── index.ts │ │ │ ├── read-all.ts │ │ │ ├── unread-count.ts │ │ │ └── update-status.ts │ │ ├── oauth │ │ │ ├── authorized-list.ts │ │ │ ├── create.ts │ │ │ ├── decision-info.ts │ │ │ ├── delete.ts │ │ │ ├── get-list.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── revoke.ts │ │ │ ├── secret-delete.ts │ │ │ ├── secret-generate.ts │ │ │ └── update.ts │ │ ├── openapi-snippet │ │ │ ├── index.js │ │ │ └── openapi-to-har.js │ │ ├── organization │ │ │ ├── departments.ts │ │ │ ├── get-me.ts │ │ │ ├── index.ts │ │ │ └── user-get.ts │ │ ├── pin │ │ │ ├── add.ts │ │ │ ├── delete.ts │ │ │ ├── get-list.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── update-order.ts │ │ ├── plan │ │ │ ├── index.ts │ │ │ ├── plan-convert.ts │ │ │ ├── plan-create.ts │ │ │ └── plan.ts │ │ ├── plugin-context-menu │ │ │ ├── index.ts │ │ │ ├── plugin-get-list.ts │ │ │ ├── plugin-get-storage.ts │ │ │ ├── plugin-get.ts │ │ │ ├── plugin-install.ts │ │ │ ├── plugin-move.ts │ │ │ ├── plugin-remove.ts │ │ │ ├── plugin-rename.ts │ │ │ └── plugin-update-storage.ts │ │ ├── plugin-panel │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── duplicate-panel-installed.ts │ │ │ ├── duplicate.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── list.ts │ │ │ ├── plugin-get.ts │ │ │ ├── plugin-install.ts │ │ │ ├── plugin-remove.ts │ │ │ ├── plugin-rename.ts │ │ │ ├── plugin-update-storage.ts │ │ │ ├── rename.ts │ │ │ └── update-layout.ts │ │ ├── plugin │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── get-auth-code.ts │ │ │ ├── get-center-list.ts │ │ │ ├── get-list.ts │ │ │ ├── get-token.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── refresh-token.ts │ │ │ ├── regenerate-secret.ts │ │ │ ├── submit.ts │ │ │ ├── types.ts │ │ │ ├── unpublish.ts │ │ │ └── update.ts │ │ ├── record │ │ │ ├── README.ts │ │ │ ├── auto-fill-cell.ts │ │ │ ├── create.ts │ │ │ ├── delete-list.ts │ │ │ ├── delete.ts │ │ │ ├── duplicate.ts │ │ │ ├── get-list.ts │ │ │ ├── get-record-history.ts │ │ │ ├── get-record-list-history.ts │ │ │ ├── get-record-status.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── record.schema.spec.ts │ │ │ ├── update-records.ts │ │ │ ├── update.ts │ │ │ └── upload-attachment.ts │ │ ├── selection │ │ │ ├── clear.ts │ │ │ ├── copy.ts │ │ │ ├── delete.ts │ │ │ ├── index.ts │ │ │ ├── paste.ts │ │ │ ├── range.ts │ │ │ └── temporary-paste.ts │ │ ├── share │ │ │ ├── index.ts │ │ │ ├── view-aggregations.ts │ │ │ ├── view-auth.ts │ │ │ ├── view-calendar-daily-collection.ts │ │ │ ├── view-collaborators.ts │ │ │ ├── view-copy.ts │ │ │ ├── view-form-submit.ts │ │ │ ├── view-get.ts │ │ │ ├── view-group-points.ts │ │ │ ├── view-link-records.ts │ │ │ ├── view-row-count.ts │ │ │ ├── view-search-count.ts │ │ │ └── view-search-index.ts │ │ ├── space │ │ │ ├── collaborator-add.ts │ │ │ ├── collaborator-delete.ts │ │ │ ├── collaborator-get-list.ts │ │ │ ├── collaborator-update.ts │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── get-base-list.ts │ │ │ ├── get-list.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── integration-create.ts │ │ │ ├── integration-delete.ts │ │ │ ├── integration-get-list.ts │ │ │ ├── integration-update.ts │ │ │ ├── invitation-create-link.ts │ │ │ ├── invitation-delete-link.ts │ │ │ ├── invitation-email.ts │ │ │ ├── invitation-get-link-list.ts │ │ │ ├── invitation-update-link.ts │ │ │ ├── permanent-delete.ts │ │ │ ├── types.ts │ │ │ └── update.ts │ │ ├── table │ │ │ ├── create.ts │ │ │ ├── default-view-id.ts │ │ │ ├── delete.ts │ │ │ ├── duplicate.ts │ │ │ ├── get-abnormal-index.ts │ │ │ ├── get-activated-index.ts │ │ │ ├── get-list.ts │ │ │ ├── get-permission.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── permanent-delete.ts │ │ │ ├── repair-table-index.ts │ │ │ ├── toggle-table-index.ts │ │ │ ├── update-db-table-name.ts │ │ │ ├── update-description.ts │ │ │ ├── update-icon.ts │ │ │ ├── update-name.ts │ │ │ └── update-order.ts │ │ ├── template │ │ │ ├── category │ │ │ │ ├── create.ts │ │ │ │ ├── delete.ts │ │ │ │ ├── get-published.ts │ │ │ │ ├── get.ts │ │ │ │ ├── index.ts │ │ │ │ └── update.ts │ │ │ ├── create-snapshot.ts │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── get-published.ts │ │ │ ├── get-template-detail.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── pin-top.ts │ │ │ └── update.ts │ │ ├── trash │ │ │ ├── get-items.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── reset-items.ts │ │ │ └── restore.ts │ │ ├── types.ts │ │ ├── undo-redo │ │ │ ├── index.ts │ │ │ ├── redo.ts │ │ │ └── undo.ts │ │ ├── usage │ │ │ ├── get-base-usage.ts │ │ │ ├── get-instance-usage.ts │ │ │ ├── get-space-usage.ts │ │ │ └── index.ts │ │ ├── user │ │ │ ├── index.ts │ │ │ ├── last-visit │ │ │ │ ├── get.ts │ │ │ │ ├── getMap.ts │ │ │ │ ├── index.ts │ │ │ │ ├── list-base.ts │ │ │ │ └── update.ts │ │ │ ├── update-avatar.ts │ │ │ ├── update-name.ts │ │ │ └── update-notify-meta.ts │ │ ├── utils.ts │ │ ├── view │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── filter-link-records.ts │ │ │ ├── get-list.ts │ │ │ ├── get.ts │ │ │ ├── index.ts │ │ │ ├── manual-sort.ts │ │ │ ├── plugin-get.ts │ │ │ ├── plugin-install.ts │ │ │ ├── plugin-update-storage.ts │ │ │ ├── refresh-share-id.ts │ │ │ ├── share-disable.ts │ │ │ ├── share-enable.ts │ │ │ ├── update-description.ts │ │ │ ├── update-fields-column-meta.ts │ │ │ ├── update-filter.ts │ │ │ ├── update-group.ts │ │ │ ├── update-locked.ts │ │ │ ├── update-name.ts │ │ │ ├── update-options.ts │ │ │ ├── update-order.ts │ │ │ ├── update-record-order.ts │ │ │ ├── update-share-meta.ts │ │ │ └── update-sort.ts │ │ └── zod.ts │ ├── tsconfig.build.json │ ├── tsconfig.eslint.json │ ├── tsconfig.json │ ├── vitest.config.ts │ └── vitest.setup.js ├── sdk │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .idea │ │ ├── modules.xml │ │ └── sdk.iml │ ├── LICENSE │ ├── components.json │ ├── config │ │ └── tests │ │ │ └── setupVitest.ts │ ├── lint-staged.config.js │ ├── package.json │ ├── plate-components.json │ ├── src │ │ ├── components │ │ │ ├── FileZone.tsx │ │ │ ├── base-query │ │ │ │ ├── FormItem.tsx │ │ │ │ ├── QueryBuilder.tsx │ │ │ │ ├── QueryEditor.tsx │ │ │ │ ├── QueryEditorContainer.tsx │ │ │ │ ├── QueryFom.tsx │ │ │ │ ├── QueryOperators.tsx │ │ │ │ ├── common │ │ │ │ │ ├── ContextColumnCommand.tsx │ │ │ │ │ ├── ContextColumnSelector.tsx │ │ │ │ │ ├── NewPopover.tsx │ │ │ │ │ └── useAllColumns.ts │ │ │ │ ├── constant.ts │ │ │ │ ├── context │ │ │ │ │ ├── QueryEditorContext.tsx │ │ │ │ │ ├── QueryEditorProvider.tsx │ │ │ │ │ ├── QueryFormContext.tsx │ │ │ │ │ └── QueryFormProvider.tsx │ │ │ │ ├── editors │ │ │ │ │ ├── QueryAggregation.tsx │ │ │ │ │ ├── QueryFilter │ │ │ │ │ │ ├── FieldComponent.tsx │ │ │ │ │ │ ├── OperatorComponent.tsx │ │ │ │ │ │ ├── QueryFilter.tsx │ │ │ │ │ │ ├── ValueComponent.tsx │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── QueryGroup.tsx │ │ │ │ │ ├── QueryJoin.tsx │ │ │ │ │ ├── QueryOrder.tsx │ │ │ │ │ ├── QuerySelect.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── query-from │ │ │ │ │ ├── QueryFrom.tsx │ │ │ │ │ ├── QueryFromValue.tsx │ │ │ │ │ └── useQueryFromTableValidation.ts │ │ │ │ ├── useQueryContext.ts │ │ │ │ └── useQueryOperatorsStatic.ts │ │ │ ├── billing │ │ │ │ └── store │ │ │ │ │ ├── index.ts │ │ │ │ │ └── usage-limit-modal.ts │ │ │ ├── cell-value-editor │ │ │ │ ├── CellEditor.tsx │ │ │ │ ├── CellEditorMain.tsx │ │ │ │ ├── index.ts │ │ │ │ └── type.ts │ │ │ ├── cell-value │ │ │ │ ├── CellValue.tsx │ │ │ │ ├── cell-attachment │ │ │ │ │ ├── CellAttachment.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── cell-checkbox │ │ │ │ │ ├── CellCheckbox.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── cell-date │ │ │ │ │ ├── CellDate.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── cell-link │ │ │ │ │ ├── CellLink.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── cell-number │ │ │ │ │ ├── CellNumber.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── cell-rating │ │ │ │ │ ├── CellRating.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── cell-select │ │ │ │ │ ├── CellSelect.tsx │ │ │ │ │ ├── SelectTag.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── cell-text │ │ │ │ │ ├── CellText.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── cell-user │ │ │ │ │ ├── CellUser.tsx │ │ │ │ │ ├── UserAvatar.tsx │ │ │ │ │ ├── UserTag.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── components │ │ │ │ │ ├── OverflowTooltip.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ └── useTagVisibility.ts │ │ │ │ ├── index.ts │ │ │ │ └── type.ts │ │ │ ├── collaborator │ │ │ │ ├── CollaboratorWithHoverCard.tsx │ │ │ │ └── index.ts │ │ │ ├── color │ │ │ │ ├── Color.tsx │ │ │ │ └── index.ts │ │ │ ├── comment │ │ │ │ ├── CommentHeader.tsx │ │ │ │ ├── CommentPanel.tsx │ │ │ │ ├── comment-editor │ │ │ │ │ ├── CommentEditor.tsx │ │ │ │ │ ├── CommentQuote.tsx │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── transform.tsx │ │ │ │ ├── comment-list │ │ │ │ │ ├── CommentContent.tsx │ │ │ │ │ ├── CommentItem.tsx │ │ │ │ │ ├── CommentList.tsx │ │ │ │ │ ├── CommentSkeleton.tsx │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── node │ │ │ │ │ │ ├── block-element │ │ │ │ │ │ │ ├── Image.tsx │ │ │ │ │ │ │ ├── Paragraph.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── inline-element │ │ │ │ │ │ │ ├── Link.tsx │ │ │ │ │ │ │ ├── MentionUser.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── type.ts │ │ │ │ │ ├── reaction │ │ │ │ │ │ ├── Reaction.tsx │ │ │ │ │ │ ├── ReactionPicker.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── useCommentPatchListener.ts │ │ │ │ │ └── useIsMe.ts │ │ │ │ ├── context.ts │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useBaseId.ts │ │ │ │ │ ├── useRecordCommentCount.ts │ │ │ │ │ └── useRecordId.ts │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── useCommentStore.ts │ │ │ ├── create-record │ │ │ │ ├── CreateRecordModal.tsx │ │ │ │ └── index.ts │ │ │ ├── editor │ │ │ │ ├── attachment │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── upload-attachment │ │ │ │ │ │ ├── AttachmentItem.tsx │ │ │ │ │ │ ├── FileInput.tsx │ │ │ │ │ │ ├── UploadAttachment.tsx │ │ │ │ │ │ └── uploadManage.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── checkbox │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── date │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── EditorMain.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── formula │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── AiPromptContainer.tsx │ │ │ │ │ │ ├── CodeEditor.tsx │ │ │ │ │ │ ├── FunctionGuide.tsx │ │ │ │ │ │ ├── FunctionHelper.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── extensions │ │ │ │ │ │ ├── ai.ts │ │ │ │ │ │ ├── autocomplete.ts │ │ │ │ │ │ ├── history.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── theme.ts │ │ │ │ │ │ ├── token.ts │ │ │ │ │ │ └── variable.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── interface.ts │ │ │ │ │ └── visitor.ts │ │ │ │ ├── index.ts │ │ │ │ ├── link │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── EditorMain.tsx │ │ │ │ │ ├── LinkCard.tsx │ │ │ │ │ ├── LinkList.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── interface.ts │ │ │ │ ├── long-text │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── number │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── rating │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── select │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── EditorMain.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── OptionList.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── text │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── type.ts │ │ │ │ └── user │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── EditorBase.tsx │ │ │ │ │ ├── EditorMain.tsx │ │ │ │ │ ├── UserOption.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ ├── expand-record │ │ │ │ ├── CellEditorWrap.tsx │ │ │ │ ├── ExpandRecord.tsx │ │ │ │ ├── ExpandRecordHeader.tsx │ │ │ │ ├── ExpandRecordWrap.tsx │ │ │ │ ├── ExpandRecorder.tsx │ │ │ │ ├── Modal.tsx │ │ │ │ ├── ModalContext.ts │ │ │ │ ├── Panel.tsx │ │ │ │ ├── RecordEditor.tsx │ │ │ │ ├── RecordEditorItem.tsx │ │ │ │ ├── RecordHistory.tsx │ │ │ │ ├── TooltipWrap.tsx │ │ │ │ ├── components │ │ │ │ │ ├── CopyButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── type.ts │ │ │ │ └── useModalRefElement.ts │ │ │ ├── field │ │ │ │ ├── FieldCommand.tsx │ │ │ │ ├── FieldSelector.tsx │ │ │ │ └── index.ts │ │ │ ├── filter │ │ │ │ ├── BaseFilter.tsx │ │ │ │ ├── condition │ │ │ │ │ ├── Condition.tsx │ │ │ │ │ ├── Conjunction.tsx │ │ │ │ │ ├── ConjunctionSelect.tsx │ │ │ │ │ ├── condition-item │ │ │ │ │ │ ├── ConditionGroup.tsx │ │ │ │ │ │ ├── ConditionItem.tsx │ │ │ │ │ │ ├── base-component │ │ │ │ │ │ │ ├── FieldSelect.tsx │ │ │ │ │ │ │ ├── FieldValue.tsx │ │ │ │ │ │ │ ├── OperatorSelect.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── context.ts │ │ │ │ ├── filter-with-table │ │ │ │ │ ├── FilterWithTable.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useCallbackRef.ts │ │ │ │ │ ├── useComponent.ts │ │ │ │ │ ├── useControllableState.ts │ │ │ │ │ ├── useCrud.ts │ │ │ │ │ └── useDepth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── view-filter │ │ │ │ │ ├── BaseViewFilter.tsx │ │ │ │ │ ├── ViewFilter.tsx │ │ │ │ │ ├── component │ │ │ │ │ ├── DefaultErrorLabel.tsx │ │ │ │ │ ├── FileTypeSelect.tsx │ │ │ │ │ ├── FilterCheckBox.tsx │ │ │ │ │ ├── FilterInput.tsx │ │ │ │ │ ├── FilterMultipleSelect.tsx │ │ │ │ │ ├── FilterSingleSelect.tsx │ │ │ │ │ ├── FilterUserSelect.tsx │ │ │ │ │ ├── base │ │ │ │ │ │ ├── BaseMultipleSelect.tsx │ │ │ │ │ │ ├── BaseSingleSelect.tsx │ │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ │ ├── BaseMultipleSelect.test.tsx │ │ │ │ │ │ │ └── BaseSingleSelect.test.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── filter-link │ │ │ │ │ │ ├── DefaultList.tsx │ │ │ │ │ │ ├── DefaultTrigger.tsx │ │ │ │ │ │ ├── FilterLink.tsx │ │ │ │ │ │ ├── FilterLinkInput.tsx │ │ │ │ │ │ ├── FilterLinkSelect.tsx │ │ │ │ │ │ ├── StandDefaultList.tsx │ │ │ │ │ │ ├── constant.ts │ │ │ │ │ │ ├── context.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── storage.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── filterDatePicker │ │ │ │ │ │ ├── DatePicker.tsx │ │ │ │ │ │ ├── FilterDatePicker.tsx │ │ │ │ │ │ ├── constant.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── custom-component │ │ │ │ │ ├── BaseFieldValue.tsx │ │ │ │ │ ├── FieldSelect.tsx │ │ │ │ │ ├── FieldValue.tsx │ │ │ │ │ ├── OperatorSelect.tsx │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useDateI18nMap.ts │ │ │ │ │ ├── useFieldFilterLinkContext.ts │ │ │ │ │ ├── useFields.ts │ │ │ │ │ ├── useFilterNode.ts │ │ │ │ │ ├── useOperatorI18nMap.ts │ │ │ │ │ ├── useOperators.ts │ │ │ │ │ ├── useViewFilterContext.ts │ │ │ │ │ └── useViewFilterLinkContext.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── type-guard.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils.ts │ │ │ ├── grid-enhancements │ │ │ │ ├── components │ │ │ │ │ ├── grid-tooltip │ │ │ │ │ │ ├── GridTooltip.tsx │ │ │ │ │ │ ├── grid-tooltip.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── row-counter │ │ │ │ │ │ ├── RowCounter.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ ├── editor │ │ │ │ │ ├── GridAttachmentEditor.tsx │ │ │ │ │ ├── GridDateEditor.tsx │ │ │ │ │ ├── GridFilePreviewer.tsx │ │ │ │ │ ├── GridLinkEditor.tsx │ │ │ │ │ ├── GridNumberEditor.tsx │ │ │ │ │ ├── GridSelectEditor.tsx │ │ │ │ │ ├── GridUserEditor.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── use-grid-async-records.ts │ │ │ │ │ ├── use-grid-collapsed-group.ts │ │ │ │ │ ├── use-grid-column-order.ts │ │ │ │ │ ├── use-grid-column-resize.ts │ │ │ │ │ ├── use-grid-column-statistics.ts │ │ │ │ │ ├── use-grid-columns.tsx │ │ │ │ │ ├── use-grid-file-event.ts │ │ │ │ │ ├── use-grid-group-collection.ts │ │ │ │ │ ├── use-grid-icons.ts │ │ │ │ │ ├── use-grid-popup-position.tsx │ │ │ │ │ ├── use-grid-prefilling-row.ts │ │ │ │ │ ├── use-grid-row-order.ts │ │ │ │ │ ├── use-grid-selection.ts │ │ │ │ │ └── use-grid-theme.ts │ │ │ │ ├── index.ts │ │ │ │ ├── store │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── type.ts │ │ │ │ │ ├── useGridCollapsedGroupStore.ts │ │ │ │ │ └── useGridViewStore.ts │ │ │ │ └── utils │ │ │ │ │ ├── generate-id.ts │ │ │ │ │ ├── group-value.ts │ │ │ │ │ ├── image-handler.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── persist-editing.ts │ │ │ ├── grid │ │ │ │ ├── CellScroller.tsx │ │ │ │ ├── Grid.tsx │ │ │ │ ├── InfiniteScroller.tsx │ │ │ │ ├── InteractionLayer.tsx │ │ │ │ ├── RenderLayer.tsx │ │ │ │ ├── TouchLayer.tsx │ │ │ │ ├── components │ │ │ │ │ ├── LoadingIndicator.tsx │ │ │ │ │ ├── editor │ │ │ │ │ │ ├── BooleanEditor.tsx │ │ │ │ │ │ ├── EditorContainer.tsx │ │ │ │ │ │ ├── RatingEditor.tsx │ │ │ │ │ │ ├── SelectEditor.tsx │ │ │ │ │ │ ├── TextEditor.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── configs │ │ │ │ │ ├── grid.ts │ │ │ │ │ ├── gridTheme.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useAutoScroll.ts │ │ │ │ │ ├── useColumnFreeze.ts │ │ │ │ │ ├── useColumnResize.ts │ │ │ │ │ ├── useDrag.ts │ │ │ │ │ ├── useEventListener.ts │ │ │ │ │ ├── useKeyboardSelection.ts │ │ │ │ │ ├── useResizeObserver.ts │ │ │ │ │ ├── useScrollFrameRate.ts │ │ │ │ │ ├── useSelection.ts │ │ │ │ │ └── useVisibleRegion.ts │ │ │ │ ├── index.ts │ │ │ │ ├── interface.ts │ │ │ │ ├── managers │ │ │ │ │ ├── coordinate-manager │ │ │ │ │ │ ├── Coordinate-manager.spec.ts │ │ │ │ │ │ ├── CoordinateManager.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── interface.ts │ │ │ │ │ ├── image-manager │ │ │ │ │ │ ├── ImageManager.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── performance-tracker │ │ │ │ │ │ ├── PerformanceTracker.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── selection-manager │ │ │ │ │ │ ├── CombinedSelection.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── sprite-manager │ │ │ │ │ │ ├── SpriteManager.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── sprites.tsx │ │ │ │ ├── renderers │ │ │ │ │ ├── base-renderer │ │ │ │ │ │ ├── baseRenderer.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── interface.ts │ │ │ │ │ ├── cell-renderer │ │ │ │ │ │ ├── booleanCellRenderer.ts │ │ │ │ │ │ ├── chartCellRenderer.ts │ │ │ │ │ │ ├── imageCellRenderer.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── interface.ts │ │ │ │ │ │ ├── linkCellRenderer.ts │ │ │ │ │ │ ├── loadingCellRenderer.ts │ │ │ │ │ │ ├── numberCellRenderer.ts │ │ │ │ │ │ ├── ratingCellRenderer.ts │ │ │ │ │ │ ├── selectCellRenderer.ts │ │ │ │ │ │ ├── textCellRenderer.ts │ │ │ │ │ │ ├── userCellRenderer.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── layout-renderer │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── interface.ts │ │ │ │ │ │ └── layoutRenderer.ts │ │ │ │ └── utils │ │ │ │ │ ├── element.ts │ │ │ │ │ ├── group.ts │ │ │ │ │ ├── hotkey.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── measure.ts │ │ │ │ │ ├── range.ts │ │ │ │ │ ├── region.ts │ │ │ │ │ └── utils.ts │ │ │ ├── group │ │ │ │ ├── Group.tsx │ │ │ │ └── index.ts │ │ │ ├── hide-fields │ │ │ │ ├── HideFields.tsx │ │ │ │ ├── HideFieldsBase.tsx │ │ │ │ ├── VisibleFields.tsx │ │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── useAttachmentPreviewI18Map.ts │ │ │ ├── index.ts │ │ │ ├── markdown-editor │ │ │ │ ├── EditorContainer.tsx │ │ │ │ ├── MarkDownEditor.tsx │ │ │ │ ├── MarkDownPreview.tsx │ │ │ │ └── index.ts │ │ │ ├── member-selector │ │ │ │ ├── DepartmentList.tsx │ │ │ │ ├── DepartmentSelector.tsx │ │ │ │ ├── MemberContent.tsx │ │ │ │ ├── MemberSelected.tsx │ │ │ │ ├── MemberSelectorDialog.tsx │ │ │ │ ├── SearchInput.tsx │ │ │ │ ├── components │ │ │ │ │ ├── DepartmentItem.tsx │ │ │ │ │ └── UserItem.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── use-debounce.ts │ │ │ ├── plate │ │ │ │ └── ui │ │ │ │ │ ├── button.tsx │ │ │ │ │ ├── hooks │ │ │ │ │ ├── useMounted.ts │ │ │ │ │ └── useUploadFile.ts │ │ │ │ │ ├── image-element.tsx │ │ │ │ │ ├── image-preview.tsx │ │ │ │ │ ├── inline-combobox.tsx │ │ │ │ │ ├── input.tsx │ │ │ │ │ ├── link-element-static.tsx │ │ │ │ │ ├── link-element.tsx │ │ │ │ │ ├── link-floating-toolbar.tsx │ │ │ │ │ ├── link-toolbar-button.tsx │ │ │ │ │ ├── media-placeholder-element.tsx │ │ │ │ │ ├── media-toolbar-button.tsx │ │ │ │ │ ├── media-upload-toast.tsx │ │ │ │ │ ├── mention-element-static.tsx │ │ │ │ │ ├── mention-element.tsx │ │ │ │ │ ├── mention-input-element.tsx │ │ │ │ │ ├── paragraph-element.tsx │ │ │ │ │ ├── popover.tsx │ │ │ │ │ ├── resize-handle.tsx │ │ │ │ │ ├── separator.tsx │ │ │ │ │ ├── toolbar.tsx │ │ │ │ │ └── tooltip.tsx │ │ │ ├── record-list │ │ │ │ ├── ApiRecordList.tsx │ │ │ │ ├── RecordItem.tsx │ │ │ │ ├── RecordList.tsx │ │ │ │ ├── RecordSearch.tsx │ │ │ │ ├── SocketRecordList.tsx │ │ │ │ └── index.ts │ │ │ ├── row-height │ │ │ │ ├── RowHeight.tsx │ │ │ │ ├── RowHeightBase.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── useFieldNameDisplayLinesNodes.ts │ │ │ │ ├── useRowHeightNode.ts │ │ │ │ └── useRowHeightNodes.ts │ │ │ ├── search │ │ │ │ ├── SearchInput.tsx │ │ │ │ └── index.ts │ │ │ ├── select-field-dialog │ │ │ │ ├── FieldCreateOrSelectModal.tsx │ │ │ │ ├── FieldCreator.tsx │ │ │ │ └── index.ts │ │ │ ├── sort │ │ │ │ ├── DraggableSortList.tsx │ │ │ │ ├── OrderSelect.tsx │ │ │ │ ├── Sort.tsx │ │ │ │ ├── SortBase.tsx │ │ │ │ ├── SortConfig.tsx │ │ │ │ ├── SortContent.tsx │ │ │ │ ├── SortFieldAddButton.tsx │ │ │ │ ├── SortItem.tsx │ │ │ │ ├── index.ts │ │ │ │ └── useSortNode.ts │ │ │ ├── table │ │ │ │ ├── InfiniteTable.tsx │ │ │ │ ├── VirtualizedInfiniteTable.tsx │ │ │ │ └── index.ts │ │ │ └── view │ │ │ │ ├── ViewSelect.tsx │ │ │ │ ├── constant.ts │ │ │ │ └── index.ts │ │ ├── config │ │ │ ├── index.ts │ │ │ ├── local-storage-keys.ts │ │ │ └── react-query-keys.ts │ │ ├── context │ │ │ ├── __tests__ │ │ │ │ ├── createAppContext.tsx │ │ │ │ ├── createConnectionContext.tsx │ │ │ │ └── createSessionContext.tsx │ │ │ ├── aggregation │ │ │ │ ├── AggregationContext.ts │ │ │ │ ├── AggregationProvider.tsx │ │ │ │ ├── CalendarDailyCollectionContext.ts │ │ │ │ ├── CalendarDailyCollectionProvider.tsx │ │ │ │ ├── GroupPointContext.ts │ │ │ │ ├── GroupPointProvider.tsx │ │ │ │ ├── RowCountContext.ts │ │ │ │ ├── RowCountProvider.tsx │ │ │ │ ├── TaskStatusCollectionContext.ts │ │ │ │ ├── TaskStatusCollectionProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── anchor │ │ │ │ ├── AnchorContext.ts │ │ │ │ └── index.ts │ │ │ ├── app │ │ │ │ ├── AppContext.ts │ │ │ │ ├── AppProvider.tsx │ │ │ │ ├── ConnectionContext.tsx │ │ │ │ ├── ConnectionProvider.tsx │ │ │ │ ├── QueryClientProvider.tsx │ │ │ │ ├── i18n │ │ │ │ │ ├── const.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── useTranslation.ts │ │ │ │ ├── index.ts │ │ │ │ ├── queryClient.tsx │ │ │ │ └── useConnection.tsx │ │ │ ├── base │ │ │ │ ├── BaseContext.ts │ │ │ │ ├── BaseProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── field │ │ │ │ ├── FieldContext.ts │ │ │ │ ├── FieldProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── notification │ │ │ │ ├── NotificationContext.ts │ │ │ │ ├── NotificationProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── query │ │ │ │ ├── LinkFilterContext.ts │ │ │ │ ├── LinkFilterProvider.tsx │ │ │ │ ├── SearchContext.ts │ │ │ │ ├── SearchProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── record │ │ │ │ ├── RecordContext.ts │ │ │ │ ├── RecordProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── session │ │ │ │ ├── SessionContext.ts │ │ │ │ ├── SessionProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── table-permission │ │ │ │ ├── TablePermissionContext.ts │ │ │ │ ├── TablePermissionProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── table │ │ │ │ ├── LinkViewProvider.tsx │ │ │ │ ├── ShareViewContext.tsx │ │ │ │ ├── ShareViewProxy.tsx │ │ │ │ ├── StandaloneViewProvider.tsx │ │ │ │ ├── TableContext.ts │ │ │ │ ├── TableProvider.tsx │ │ │ │ └── index.ts │ │ │ ├── use-instances │ │ │ │ ├── index.ts │ │ │ │ ├── opListener.ts │ │ │ │ ├── reducer.ts │ │ │ │ ├── use-instances.spec.tsx │ │ │ │ └── useInstances.ts │ │ │ └── view │ │ │ │ ├── PersonalViewContext.tsx │ │ │ │ ├── PersonalViewProvider.tsx │ │ │ │ ├── PersonalViewProxy.tsx │ │ │ │ ├── ViewContext.ts │ │ │ │ ├── ViewProvider.tsx │ │ │ │ ├── index.ts │ │ │ │ └── store │ │ │ │ ├── index.ts │ │ │ │ └── usePersonalViewStore.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-aggregation.ts │ │ │ ├── use-ai.ts │ │ │ ├── use-base-id.ts │ │ │ ├── use-base-permission.ts │ │ │ ├── use-base.ts │ │ │ ├── use-comment-count-map.ts │ │ │ ├── use-connection.ts │ │ │ ├── use-deep-compare-memoize.ts │ │ │ ├── use-field-operations.ts │ │ │ ├── use-field-permission.ts │ │ │ ├── use-field-static-getter.ts │ │ │ ├── use-field.ts │ │ │ ├── use-fields.ts │ │ │ ├── use-group-point.ts │ │ │ ├── use-infinite-records.ts │ │ │ ├── use-is-hydrated.ts │ │ │ ├── use-is-mobile.ts │ │ │ ├── use-is-touch-device.ts │ │ │ ├── use-lan-dayjs.ts │ │ │ ├── use-link-filter.ts │ │ │ ├── use-notification.ts │ │ │ ├── use-organization.ts │ │ │ ├── use-permission-actions-static.spec.ts │ │ │ ├── use-permission-actions-static.ts │ │ │ ├── use-permission-update-listener.ts │ │ │ ├── use-personal-view.ts │ │ │ ├── use-presence.ts │ │ │ ├── use-record-operations.ts │ │ │ ├── use-record.ts │ │ │ ├── use-records.ts │ │ │ ├── use-row-count.ts │ │ │ ├── use-search.ts │ │ │ ├── use-session.ts │ │ │ ├── use-ssr-record.ts │ │ │ ├── use-ssr-records.ts │ │ │ ├── use-table-id.ts │ │ │ ├── use-table-listener.ts │ │ │ ├── use-table-permission.ts │ │ │ ├── use-table.ts │ │ │ ├── use-tables.ts │ │ │ ├── use-undo-redo.ts │ │ │ ├── use-view-id.ts │ │ │ ├── use-view-listener.ts │ │ │ ├── use-view.ts │ │ │ └── use-views.ts │ │ ├── index.ts │ │ ├── model │ │ │ ├── base.ts │ │ │ ├── field │ │ │ │ ├── attachment.field.ts │ │ │ │ ├── auto-number.field.ts │ │ │ │ ├── checkbox.field.ts │ │ │ │ ├── created-by.field.ts │ │ │ │ ├── created-time.field.ts │ │ │ │ ├── date.field.ts │ │ │ │ ├── factory.ts │ │ │ │ ├── field.ts │ │ │ │ ├── formula.field.ts │ │ │ │ ├── index.ts │ │ │ │ ├── last-modified-by.field.ts │ │ │ │ ├── last-modified-time.field.ts │ │ │ │ ├── link.field.ts │ │ │ │ ├── long-text.field.ts │ │ │ │ ├── mixin │ │ │ │ │ └── select.field.ts │ │ │ │ ├── multiple-select.field.ts │ │ │ │ ├── number.field.ts │ │ │ │ ├── rating.field.ts │ │ │ │ ├── rollup.field.ts │ │ │ │ ├── single-line-text.field.ts │ │ │ │ ├── single-select.field.ts │ │ │ │ └── user.field.ts │ │ │ ├── index.ts │ │ │ ├── record │ │ │ │ ├── factory.ts │ │ │ │ ├── index.ts │ │ │ │ └── record.ts │ │ │ ├── table │ │ │ │ ├── factory.ts │ │ │ │ ├── index.ts │ │ │ │ └── table.ts │ │ │ └── view │ │ │ │ ├── calendar.view.ts │ │ │ │ ├── factory.ts │ │ │ │ ├── form.view.ts │ │ │ │ ├── gallery.view.ts │ │ │ │ ├── grid.view.ts │ │ │ │ ├── index.ts │ │ │ │ ├── kanban.view.ts │ │ │ │ ├── plugin.view.ts │ │ │ │ └── view.ts │ │ ├── plugin-bridge │ │ │ ├── bridge.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-bridge.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── store │ │ │ ├── index.ts │ │ │ └── use-interaction-mode-store.ts │ │ └── utils │ │ │ ├── copy.ts │ │ │ ├── fieldType.ts │ │ │ ├── filterWithDefaultValue.ts │ │ │ ├── index.ts │ │ │ ├── order.ts │ │ │ ├── personalView.ts │ │ │ ├── requestWrap.ts │ │ │ ├── sprite.tsx │ │ │ ├── statistic.ts │ │ │ └── urlParams.ts │ ├── tailwind.config.js │ ├── tsconfig.build.json │ ├── tsconfig.eslint.json │ ├── tsconfig.json │ ├── ui.config.d.ts │ ├── ui.config.js │ └── vitest.config.ts └── ui-lib │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .idea │ ├── modules.xml │ └── ui-lib.iml │ ├── .storybook │ ├── main.js │ └── preview.js │ ├── LICENSE │ ├── components.json │ ├── lint-staged.config.js │ ├── package.json │ ├── postcss.config.js │ ├── scripts │ ├── shadcn-ui.mjs │ └── update-shadcn-ui.mjs │ ├── src │ ├── _stories │ │ ├── Introduction.stories.mdx │ │ ├── icons │ │ │ ├── code-brackets.svg │ │ │ ├── colors.svg │ │ │ ├── comments.svg │ │ │ ├── direction.svg │ │ │ ├── flow.svg │ │ │ ├── plugin.svg │ │ │ ├── repo.svg │ │ │ └── stackalt.svg │ │ └── tailwind.css │ ├── async-message.tsx │ ├── base │ │ ├── Error.tsx │ │ ├── card │ │ │ └── BasicCard.tsx │ │ ├── dialog │ │ │ ├── ConfirmDialog.tsx │ │ │ └── index.ts │ │ ├── dnd-kit │ │ │ └── index.tsx │ │ ├── file │ │ │ ├── index.ts │ │ │ └── preview │ │ │ │ ├── FilePreview.tsx │ │ │ │ ├── FilePreviewContent.tsx │ │ │ │ ├── FilePreviewContext.tsx │ │ │ │ ├── FilePreviewDialog.tsx │ │ │ │ ├── FilePreviewItem.tsx │ │ │ │ ├── FilePreviewProvider.tsx │ │ │ │ ├── Thumb.tsx │ │ │ │ ├── audio │ │ │ │ └── AudioPreview.tsx │ │ │ │ ├── genFileId.ts │ │ │ │ ├── getFileIcon.ts │ │ │ │ ├── image │ │ │ │ └── ImagePreview.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── office │ │ │ │ ├── ExcelPreview.tsx │ │ │ │ ├── WordPreview.tsx │ │ │ │ └── utils.ts │ │ │ │ ├── pdf │ │ │ │ ├── PDFPreview.tsx │ │ │ │ └── utils.ts │ │ │ │ ├── utils.ts │ │ │ │ └── video │ │ │ │ └── VideoPreview.tsx │ │ ├── index.ts │ │ ├── selector │ │ │ └── Selector.tsx │ │ └── spin │ │ │ └── Spin.tsx │ ├── icons │ │ ├── app │ │ │ ├── 3column.svg │ │ │ ├── add-bold.svg │ │ │ ├── add-circle.svg │ │ │ ├── add.svg │ │ │ ├── adjust.svg │ │ │ ├── arrow-double-left.svg │ │ │ ├── arrow-double-right.svg │ │ │ ├── arrow-down-bold.svg │ │ │ ├── arrow-down.svg │ │ │ ├── arrow-left-bold.svg │ │ │ ├── arrow-left-circle.svg │ │ │ ├── arrow-right-bold.svg │ │ │ ├── arrow-right-circle.svg │ │ │ ├── arrow-right.svg │ │ │ ├── arrow-up-bold.svg │ │ │ ├── arrow-up-circle.svg │ │ │ ├── ashbin.svg │ │ │ ├── attachment.svg │ │ │ ├── back.svg │ │ │ ├── bad.svg │ │ │ ├── bottom.svg │ │ │ ├── browse.svg │ │ │ ├── calendar.svg │ │ │ ├── camera.svg │ │ │ ├── caps-lock.svg │ │ │ ├── chart-bar.svg │ │ │ ├── chart-pie.svg │ │ │ ├── check-item.svg │ │ │ ├── close-bold.svg │ │ │ ├── close.svg │ │ │ ├── code.svg │ │ │ ├── color.svg │ │ │ ├── column-4.svg │ │ │ ├── column-horizontal.svg │ │ │ ├── column-vertical.svg │ │ │ ├── comment.svg │ │ │ ├── complete.svg │ │ │ ├── copy.svg │ │ │ ├── copy1.svg │ │ │ ├── cry.svg │ │ │ ├── customer-service.svg │ │ │ ├── cut.svg │ │ │ ├── dashboard.svg │ │ │ ├── data-view.svg │ │ │ ├── delete.svg │ │ │ ├── direction-down-circle.svg │ │ │ ├── direction-down.svg │ │ │ ├── direction-left.svg │ │ │ ├── direction-right.svg │ │ │ ├── direction-up.svg │ │ │ ├── discount.svg │ │ │ ├── download.svg │ │ │ ├── drag.svg │ │ │ ├── duplicate.svg │ │ │ ├── duplicate1.svg │ │ │ ├── edit.svg │ │ │ ├── electronics.svg │ │ │ ├── elipsis.svg │ │ │ ├── email.svg │ │ │ ├── error.svg │ │ │ ├── explain.svg │ │ │ ├── export.svg │ │ │ ├── eye-close.svg │ │ │ ├── fabulous.svg │ │ │ ├── favorite.svg │ │ │ ├── field-number.svg │ │ │ ├── field-select.svg │ │ │ ├── field-text.svg │ │ │ ├── file-add.svg │ │ │ ├── file-common.svg │ │ │ ├── file-delete.svg │ │ │ ├── file-open.svg │ │ │ ├── file.svg │ │ │ ├── film.svg │ │ │ ├── filter.svg │ │ │ ├── folder-close.svg │ │ │ ├── forward.svg │ │ │ ├── fullscreen-expand.svg │ │ │ ├── fullscreen-shrink.svg │ │ │ ├── good.svg │ │ │ ├── group.svg │ │ │ ├── help.svg │ │ │ ├── hide.svg │ │ │ ├── history.svg │ │ │ ├── home.svg │ │ │ ├── image-text.svg │ │ │ ├── import.svg │ │ │ ├── keyboard-26.svg │ │ │ ├── keyboard-9.svg │ │ │ ├── layers.svg │ │ │ ├── layout.svg │ │ │ ├── link.svg │ │ │ ├── loading.svg │ │ │ ├── lock.svg │ │ │ ├── map.svg │ │ │ ├── meh.svg │ │ │ ├── menu.svg │ │ │ ├── mic.svg │ │ │ ├── minus-bold.svg │ │ │ ├── minus-circle.svg │ │ │ ├── minus.svg │ │ │ ├── mobile-phone.svg │ │ │ ├── modular.svg │ │ │ ├── more.svg │ │ │ ├── move.svg │ │ │ ├── navigation.svg │ │ │ ├── notification.svg │ │ │ ├── operation.svg │ │ │ ├── pad.svg │ │ │ ├── pdf.svg │ │ │ ├── picture.svg │ │ │ ├── pin.svg │ │ │ ├── play.svg │ │ │ ├── print.svg │ │ │ ├── prompt.svg │ │ │ ├── refresh.svg │ │ │ ├── row-height.svg │ │ │ ├── run-in.svg │ │ │ ├── run-up.svg │ │ │ ├── save.svg │ │ │ ├── scanning.svg │ │ │ ├── search.svg │ │ │ ├── security.svg │ │ │ ├── select-bold.svg │ │ │ ├── select.svg │ │ │ ├── send.svg │ │ │ ├── setting.svg │ │ │ ├── share.svg │ │ │ ├── shouye-zhihui.svg │ │ │ ├── sign-out.svg │ │ │ ├── skip.svg │ │ │ ├── smile.svg │ │ │ ├── sorting.svg │ │ │ ├── stop.svg │ │ │ ├── success.svg │ │ │ ├── survey.svg │ │ │ ├── switch.svg │ │ │ ├── task.svg │ │ │ ├── telephone-out.svg │ │ │ ├── telephone.svg │ │ │ ├── text.svg │ │ │ ├── time.svg │ │ │ ├── toggle-left.svg │ │ │ ├── toggle-right.svg │ │ │ ├── top.svg │ │ │ ├── training.svg │ │ │ ├── unknown-file.svg │ │ │ ├── unlock.svg │ │ │ ├── upload.svg │ │ │ ├── user.svg │ │ │ ├── warning.svg │ │ │ ├── work.svg │ │ │ ├── zoom-in.svg │ │ │ └── zoom-out.svg │ │ └── social │ │ │ ├── README.md │ │ │ └── github.svg │ ├── index.ts │ ├── message.tsx │ └── shadcn │ │ ├── global.shadcn.css │ │ ├── index.ts │ │ ├── ui │ │ ├── accordion.tsx │ │ ├── alert-dialog.tsx │ │ ├── alert.tsx │ │ ├── avatar.tsx │ │ ├── badge.tsx │ │ ├── breadcrumb.tsx │ │ ├── button.tsx │ │ ├── calendar.tsx │ │ ├── card.tsx │ │ ├── carousel.tsx │ │ ├── chart.tsx │ │ ├── checkbox.tsx │ │ ├── collapsible.tsx │ │ ├── command.tsx │ │ ├── context-menu.tsx │ │ ├── dialog.tsx │ │ ├── dropdown-menu.tsx │ │ ├── form.tsx │ │ ├── hover-card.tsx │ │ ├── input-otp.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── popover.tsx │ │ ├── progress.tsx │ │ ├── radio-group.tsx │ │ ├── resizable.tsx │ │ ├── scroll-area.tsx │ │ ├── select.tsx │ │ ├── separator.tsx │ │ ├── sheet.tsx │ │ ├── skeleton.tsx │ │ ├── slider.tsx │ │ ├── sonner.tsx │ │ ├── switch.tsx │ │ ├── table.tsx │ │ ├── tabs.tsx │ │ ├── textarea.tsx │ │ ├── toast.tsx │ │ ├── toaster.tsx │ │ ├── toggle-group.tsx │ │ ├── toggle.tsx │ │ ├── tooltip.tsx │ │ └── use-toast.ts │ │ └── utils.ts │ ├── tailwind.config.js │ ├── tailwind.shadcnui.config.js │ ├── tsconfig.build.json │ ├── tsconfig.eslint.json │ ├── tsconfig.json │ ├── ui.config.d.ts │ └── ui.config.js ├── plugins ├── .eslintrc.js ├── .gitignore ├── .idea │ ├── modules.xml │ └── plugins.iml ├── LICENSE ├── README.md ├── next-env.d.ts ├── next.config.mjs ├── package.json ├── postcss.config.js ├── scripts │ └── build-replace.js ├── src │ ├── api.ts │ ├── app │ │ ├── api │ │ │ ├── backend.ts │ │ │ └── plugin │ │ │ │ └── getToken │ │ │ │ └── route.ts │ │ ├── chart │ │ │ ├── components │ │ │ │ ├── ChartProvider.tsx │ │ │ │ ├── Hydrated.tsx │ │ │ │ ├── Pages.tsx │ │ │ │ ├── chart │ │ │ │ │ ├── ChartLayout.tsx │ │ │ │ │ ├── ChartPage.tsx │ │ │ │ │ ├── ChartQuery.tsx │ │ │ │ │ ├── chart-config │ │ │ │ │ │ ├── ChartForm.tsx │ │ │ │ │ │ ├── ChartSetting.tsx │ │ │ │ │ │ ├── QueryStatus.tsx │ │ │ │ │ │ ├── TypeSelector.tsx │ │ │ │ │ │ ├── common │ │ │ │ │ │ │ ├── AxisDisplayBaseContent.tsx │ │ │ │ │ │ │ ├── ColumnSelector.tsx │ │ │ │ │ │ │ ├── ComboLineStyleEditor.tsx │ │ │ │ │ │ │ ├── ComboTypeEditor.tsx │ │ │ │ │ │ │ ├── ComboXAxisDisplayEditor.tsx │ │ │ │ │ │ │ ├── ComboYAisxDisplayEditor.tsx │ │ │ │ │ │ │ ├── ConfigItem.tsx │ │ │ │ │ │ │ ├── GoalLineEditor.tsx │ │ │ │ │ │ │ ├── NumberInput.tsx │ │ │ │ │ │ │ ├── PaddingEditor.tsx │ │ │ │ │ │ │ ├── SwitchEditor.tsx │ │ │ │ │ │ │ └── YAxisPositionEditor.tsx │ │ │ │ │ │ └── form │ │ │ │ │ │ │ ├── AreaForm.tsx │ │ │ │ │ │ │ ├── BarForm.tsx │ │ │ │ │ │ │ ├── ComboForm.tsx │ │ │ │ │ │ │ ├── ComboXAxisEditor.tsx │ │ │ │ │ │ │ ├── ComboYAxisEditor.tsx │ │ │ │ │ │ │ ├── LineForm.tsx │ │ │ │ │ │ │ ├── PieForm.tsx │ │ │ │ │ │ │ ├── TableForm.tsx │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── chart-show │ │ │ │ │ │ ├── ChartDisplay.tsx │ │ │ │ │ │ ├── combo │ │ │ │ │ │ │ ├── Combo.tsx │ │ │ │ │ │ │ ├── TooltipItem.tsx │ │ │ │ │ │ │ └── useComboConfig.ts │ │ │ │ │ │ ├── pie │ │ │ │ │ │ │ ├── Pie.tsx │ │ │ │ │ │ │ ├── PieLegendContent.tsx │ │ │ │ │ │ │ ├── usePieConfig.tsx │ │ │ │ │ │ │ └── useRefObserve.ts │ │ │ │ │ │ ├── table │ │ │ │ │ │ │ └── ChartTable.tsx │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ └── utils.ts │ │ │ │ └── types.ts │ │ │ ├── constant.ts │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── hooks │ │ │ │ ├── useBasePermissions.ts │ │ │ │ ├── useBaseQueryData.ts │ │ │ │ ├── useFilterNumberColumns.ts │ │ │ │ └── useUIConfig.ts │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ └── query.ts │ │ └── sheet-form-view │ │ │ ├── components │ │ │ ├── CopyButton.tsx │ │ │ ├── Pages.tsx │ │ │ ├── SharePopover.tsx │ │ │ ├── SheetShareView.tsx │ │ │ ├── SheetView.tsx │ │ │ ├── sheet │ │ │ │ ├── DesignPanel.tsx │ │ │ │ ├── PreviewPanel.tsx │ │ │ │ ├── SheetSkeleton.tsx │ │ │ │ ├── UniverSheet.tsx │ │ │ │ ├── constant.ts │ │ │ │ └── utils.ts │ │ │ └── theme.ts │ │ │ ├── favicon.ico │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── components │ │ ├── EnvProvider.tsx │ │ ├── I18nProvider.tsx │ │ ├── QueryClientProvider.tsx │ │ ├── get-query-client.ts │ │ └── types.ts │ ├── hooks │ │ ├── useEnv.ts │ │ └── useInitializationZodI18n.ts │ ├── locales │ │ ├── chart │ │ │ ├── en.json │ │ │ ├── es.json │ │ │ ├── it.json │ │ │ └── zh.json │ │ └── sheet-form-view │ │ │ ├── en.json │ │ │ ├── es.json │ │ │ ├── it.json │ │ │ └── zh.json │ ├── types.d │ │ └── i18next.d.ts │ └── types.ts ├── tailwind.config.ts └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── renovate.json5 ├── scripts ├── build-image.mjs ├── build-yaml-doc.sh ├── db-migrate.mjs ├── entrypoint │ └── docker-entrypoint.sh ├── generate-openapi-types.mjs ├── post-build-cleanup.mjs ├── publish.mjs ├── start.sh └── wait-for ├── static └── assets │ ├── example │ ├── Boy1.png │ ├── Boy3.png │ ├── Girl1.png │ ├── Girl2.png │ └── Girl3.png │ └── images │ ├── comments.png │ ├── dashboard.png │ ├── record-history.png │ ├── search.png │ ├── teable-interface-dark.png │ ├── teable-interface-light.png │ ├── teable-vertical-dark.png │ ├── teable-vertical-light.png │ ├── view-calendar.png │ ├── view-form.png │ ├── view-gallery.png │ ├── view-grid.png │ └── view-kanban.png └── tsconfig.base.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: teableio 2 | ko_fi: teable 3 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: pnpm install 3 | command: make sqlite-mode && cd apps/nestjs-backend && pnpm dev 4 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | pnpm commitlint --edit $1 -------------------------------------------------------------------------------- /.husky/install.mjs: -------------------------------------------------------------------------------- 1 | // Skip Husky install in production and CI 2 | if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') { 3 | process.exit(0); 4 | } 5 | const husky = (await import('husky')).default; 6 | console.log(husky()); 7 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | pnpm g:lint-staged-files --debug -------------------------------------------------------------------------------- /.ncurc.yml: -------------------------------------------------------------------------------- 1 | # npm-check-updates configuration used by yarn deps:check && yarn deps:update 2 | # convenience scripts. 3 | # @link https://github.com/raineorshine/npm-check-updates 4 | 5 | # Add here exclusions on packages if any 6 | reject: [ 7 | 'vite-plugin-svgr', 8 | 9 | # Too early cause in esm 10 | 'is-port-reachable', 11 | 'nanoid', 12 | 'node-fetch', 13 | ] 14 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | strict-peer-dependencies=false 3 | auto-install-peers=true 4 | lockfile=true 5 | # force use npmjs.org registry 6 | registry=https://registry.npmjs.org/ 7 | use-node-version=20.9.0 8 | save-prefix='' 9 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | pnpm-lock.yaml 4 | **/.next 5 | **/.out 6 | **/dist 7 | **/build 8 | **/.tmp 9 | **/.cache 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["bradlc.vscode-tailwindcss"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/nestjs-backend/.gitignore: -------------------------------------------------------------------------------- 1 | # build 2 | build 3 | dist 4 | 5 | # testing 6 | /coverage 7 | 8 | # misc 9 | .DS_Store 10 | *.pem 11 | .assets 12 | .temporary -------------------------------------------------------------------------------- /apps/nestjs-backend/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/README.md: -------------------------------------------------------------------------------- 1 | # NestJS backend for teable 2 | -------------------------------------------------------------------------------- /apps/nestjs-backend/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "entryFile": "index", 6 | "flat": true, 7 | "compilerOptions": { 8 | "builder": "webpack" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/const.ts: -------------------------------------------------------------------------------- 1 | export const X_REQUEST_ID = 'X-Request-Id'; 2 | export const AUTH_SESSION_COOKIE_NAME = 'auth_session'; 3 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/db-provider/aggregation-query/aggregation-query.interface.ts: -------------------------------------------------------------------------------- 1 | import type { Knex } from 'knex'; 2 | 3 | export interface IAggregationQueryInterface { 4 | appendBuilder(): Knex.QueryBuilder; 5 | } 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/db-provider/base-query/abstract.ts: -------------------------------------------------------------------------------- 1 | import type { Knex } from 'knex'; 2 | 3 | export abstract class BaseQueryAbstract { 4 | constructor(protected readonly knex: Knex) {} 5 | 6 | abstract jsonSelect( 7 | queryBuilder: Knex.QueryBuilder, 8 | dbFieldName: string, 9 | alias: string 10 | ): Knex.QueryBuilder; 11 | } 12 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/db-provider/filter-query/filter-query.interface.ts: -------------------------------------------------------------------------------- 1 | import type { Knex } from 'knex'; 2 | 3 | export interface IFilterQueryInterface { 4 | appendQueryBuilder(): Knex.QueryBuilder; 5 | } 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/db-provider/group-query/group-query.interface.ts: -------------------------------------------------------------------------------- 1 | import type { Knex } from 'knex'; 2 | 3 | export interface IGroupQueryInterface { 4 | appendGroupBuilder(): Knex.QueryBuilder; 5 | } 6 | 7 | export interface IGroupQueryExtra { 8 | isDistinct?: boolean; 9 | } 10 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/db-provider/search-query/get-offset.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import 'dayjs/plugin/utc'; 3 | 4 | export function getOffset(timeZone: string) { 5 | const offsetMinutes = dayjs().tz(timeZone).utcOffset(); 6 | 7 | const offsetHours = offsetMinutes / 60; 8 | return offsetHours >= 0 ? `+${offsetHours}` : `${offsetHours}`; 9 | } 10 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/db-provider/sort-query/function/sort-function.interface.ts: -------------------------------------------------------------------------------- 1 | import type { Knex } from 'knex'; 2 | 3 | export type ISortFunctionHandler = (builderClient: Knex.QueryBuilder) => Knex.QueryBuilder; 4 | 5 | export interface ISortFunctionInterface { 6 | asc: ISortFunctionHandler; 7 | desc: ISortFunctionHandler; 8 | getAscSQL: () => string; 9 | getDescSQL: () => string; 10 | } 11 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/db-provider/sort-query/sort-query.interface.ts: -------------------------------------------------------------------------------- 1 | import type { Knex } from 'knex'; 2 | 3 | export interface ISortQueryInterface { 4 | appendSortBuilder(): Knex.QueryBuilder; 5 | getRawSortSQLText(): string; 6 | } 7 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/event-emitter/event-job/fallback/event-emitter.ts: -------------------------------------------------------------------------------- 1 | import EventEmitter from 'events'; 2 | 3 | export const localQueueEventEmitter = new EventEmitter(); 4 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/event-emitter/events/index.ts: -------------------------------------------------------------------------------- 1 | export * from './event.enum'; 2 | export * from './core-event'; 3 | export * from './op-event'; 4 | export * from './base/base.event'; 5 | export * from './space/space.event'; 6 | export * from './space/collaborator.event'; 7 | export * from './table'; 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/event-emitter/events/table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './table.event'; 2 | export * from './field.event'; 3 | export * from './view.event'; 4 | export * from './record.event'; 5 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/event-emitter/events/user/user.event.ts: -------------------------------------------------------------------------------- 1 | import { Events } from '../event.enum'; 2 | 3 | export class UserSignUpEvent { 4 | public readonly name = Events.USER_SIGNUP; 5 | 6 | constructor(public readonly userId: string) {} 7 | } 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/ai/constant.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import { Task } from '@teable/openapi'; 3 | 4 | export const TASK_MODEL_MAP = { 5 | [Task.Coding]: 'codingModel', 6 | [Task.Embedding]: 'embeddingModel', 7 | [Task.Translation]: 'translationModel', 8 | }; 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/attachments/constant.ts: -------------------------------------------------------------------------------- 1 | export const ATTACHMENT_SM_THUMBNAIL_HEIGHT = 56; 2 | export const ATTACHMENT_LG_THUMBNAIL_HEIGHT = 525; 3 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/attachments/plugins/storage.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { storageAdapterProvider } from './storage'; 3 | 4 | @Module({ 5 | providers: [storageAdapterProvider], 6 | exports: [storageAdapterProvider], 7 | }) 8 | export class StorageModule {} 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/decorators/disabled-permission.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | 3 | export const IS_DISABLED_PERMISSION = 'isDisabledPermission'; 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const DisabledPermission = () => SetMetadata(IS_DISABLED_PERMISSION, true); 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/decorators/ensure-login.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | 3 | export const ENSURE_LOGIN = 'ensureLogin'; 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const EnsureLogin = () => SetMetadata(ENSURE_LOGIN, true); 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/decorators/permissions.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | import type { Action } from '@teable/core'; 3 | 4 | export const PERMISSIONS_KEY = 'permissions'; 5 | 6 | // eslint-disable-next-line @typescript-eslint/naming-convention 7 | export const Permissions = (...permissions: Action[]) => SetMetadata(PERMISSIONS_KEY, permissions); 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/decorators/public.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | 3 | export const IS_PUBLIC_KEY = 'isPublic'; 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/decorators/token.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | 3 | export const IS_TOKEN_ACCESS = 'isTokenAccess'; 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const TokenAccess = () => SetMetadata(IS_TOKEN_ACCESS, true); 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/guard/github.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { AuthGuard } from '@nestjs/passport'; 3 | 4 | @Injectable() 5 | export class GithubGuard extends AuthGuard('github') {} 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/guard/google.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { AuthGuard } from '@nestjs/passport'; 3 | 4 | @Injectable() 5 | export class GoogleGuard extends AuthGuard('google') {} 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/guard/oidc.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { AuthGuard } from '@nestjs/passport'; 3 | 4 | @Injectable() 5 | export class OIDCGuard extends AuthGuard('openidconnect') {} 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/session/session-handle.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { SessionHandleService } from './session-handle.service'; 3 | import { SessionStoreService } from './session-store.service'; 4 | 5 | @Module({ 6 | providers: [SessionStoreService, SessionHandleService], 7 | exports: [SessionHandleService], 8 | }) 9 | export class SessionHandleModule {} 10 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/strategies/constant.ts: -------------------------------------------------------------------------------- 1 | export const ACCESS_TOKEN_STRATEGY_NAME = 'access-token'; 2 | 3 | export const JWT_TOKEN_STRATEGY_NAME = 'auth-jwt-token'; 4 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/auth/strategies/types.ts: -------------------------------------------------------------------------------- 1 | import type { Request } from 'express'; 2 | 3 | export interface IPayloadUser { 4 | id: string; 5 | } 6 | 7 | export type IFromExtractor = (req: Request) => string | null; 8 | 9 | export interface IJwtAuthInfo { 10 | userId: string; 11 | } 12 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/base-sql-executor/base-sql-executor.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { BaseSqlExecutorService } from './base-sql-executor.service'; 3 | 4 | @Module({ 5 | providers: [BaseSqlExecutorService], 6 | exports: [BaseSqlExecutorService], 7 | }) 8 | export class BaseSqlExecutorModule {} 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/base-sql-executor/const.ts: -------------------------------------------------------------------------------- 1 | export const BASE_READ_ONLY_ROLE_PREFIX = 'base_read_only_role_'; 2 | export const BASE_SCHEMA_TABLE_READ_ONLY_ROLE_NAME = 'base_schema_table_read_only_role'; 3 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/base/constant.ts: -------------------------------------------------------------------------------- 1 | export const EXCLUDE_SYSTEM_FIELDS = [ 2 | '__auto_number', 3 | '__created_time', 4 | '__last_modified_time', 5 | '__last_modified_by', 6 | '__created_by', 7 | '__version', 8 | ]; 9 | 10 | export const DEFAULT_EXPRESSION = `"TRIM('')"`; 11 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/chat/chart-completion.ro.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | 3 | export class CompletionRo { 4 | @ApiProperty({ 5 | description: 'The prompt message.', 6 | example: 'List table', 7 | }) 8 | message!: string; 9 | } 10 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/collaborator/collaborator.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common'; 2 | 3 | @Controller('collaborator') 4 | export class CollaboratorController {} 5 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/health/health.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TerminusModule } from '@nestjs/terminus'; 3 | import { HealthController } from './health.controller'; 4 | 5 | @Module({ 6 | imports: [TerminusModule], 7 | controllers: [HealthController], 8 | }) 9 | export class HealthModule {} 10 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/mail-sender/templates/partials/email-verify-code.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 |

{{title}}

4 |

{{message}}

5 | 6 | 7 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/mail-sender/templates/partials/footer.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

©{{currentYear}} {{brandName}}

5 | Help Center 6 | 7 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/mail-sender/templates/partials/html-body.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 |

{{title}}

4 | {{{message}}} 5 | 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/next/plugin/plugin.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PluginProxyModule } from './plugin-proxy.module'; 3 | @Module({ 4 | imports: [PluginProxyModule], 5 | providers: [], 6 | controllers: [], 7 | }) 8 | export class NextPluginModule {} 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/organization/organization.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { OrganizationController } from './organization.controller'; 3 | 4 | @Module({ 5 | controllers: [OrganizationController], 6 | }) 7 | export class OrganizationModule {} 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/pin/pin.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PinController } from './pin.controller'; 3 | import { PinService } from './pin.service'; 4 | 5 | @Module({ 6 | providers: [PinService], 7 | controllers: [PinController], 8 | }) 9 | export class PinModule {} 10 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/record/open-api/record-undo-redo-service.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nestjs-backend/src/features/record/open-api/record-undo-redo-service.ts -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/record/type.ts: -------------------------------------------------------------------------------- 1 | import type { Field } from '@prisma/client'; 2 | 3 | export type IFieldRaws = Pick< 4 | Field, 5 | | 'id' 6 | | 'name' 7 | | 'type' 8 | | 'options' 9 | | 'unique' 10 | | 'notNull' 11 | | 'isComputed' 12 | | 'isLookup' 13 | | 'dbFieldName' 14 | >[]; 15 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/share/guard/constant.ts: -------------------------------------------------------------------------------- 1 | export const SHARE_JWT_STRATEGY = 'share-jwt-strategy'; 2 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/share/guard/submit.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | 3 | export const IS_SHARE_SUBMIT_KEY = 'isShareSubmit'; 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const ShareSubmit = () => SetMetadata(IS_SHARE_SUBMIT_KEY, true); 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/view/model/calendar-view.dto.ts: -------------------------------------------------------------------------------- 1 | import type { IShareViewMeta } from '@teable/core'; 2 | import { CalendarViewCore } from '@teable/core'; 3 | 4 | export class CalendarViewDto extends CalendarViewCore { 5 | defaultShareMeta: IShareViewMeta = { 6 | includeRecords: true, 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/view/model/form-view.dto.ts: -------------------------------------------------------------------------------- 1 | import type { IShareViewMeta } from '@teable/core'; 2 | import { FormViewCore } from '@teable/core'; 3 | 4 | export class FormViewDto extends FormViewCore { 5 | defaultShareMeta: IShareViewMeta = { 6 | submit: { 7 | allow: true, 8 | }, 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/view/model/gallery-view.dto.ts: -------------------------------------------------------------------------------- 1 | import type { IShareViewMeta } from '@teable/core'; 2 | import { GalleryViewCore } from '@teable/core'; 3 | 4 | export class GalleryViewDto extends GalleryViewCore { 5 | defaultShareMeta: IShareViewMeta = { 6 | includeRecords: true, 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/view/model/grid-view.dto.ts: -------------------------------------------------------------------------------- 1 | import type { IShareViewMeta } from '@teable/core'; 2 | import { GridViewCore } from '@teable/core'; 3 | 4 | export class GridViewDto extends GridViewCore { 5 | defaultShareMeta: IShareViewMeta = { 6 | includeRecords: true, 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/view/model/kanban-view.dto.ts: -------------------------------------------------------------------------------- 1 | import type { IShareViewMeta } from '@teable/core'; 2 | import { KanbanViewCore } from '@teable/core'; 3 | 4 | export class KanbanViewDto extends KanbanViewCore { 5 | defaultShareMeta: IShareViewMeta = { 6 | includeRecords: true, 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/features/view/model/plugin-view.dto.ts: -------------------------------------------------------------------------------- 1 | import type { IShareViewMeta } from '@teable/core'; 2 | import { PluginViewCore } from '@teable/core'; 3 | 4 | export class PluginViewDto extends PluginViewCore { 5 | defaultShareMeta: IShareViewMeta = { 6 | includeRecords: true, 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/global/knex/index.ts: -------------------------------------------------------------------------------- 1 | export * from './knex.extend'; 2 | export * from './knex.module'; 3 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { INestApplication } from '@nestjs/common'; 2 | import { bootstrap } from './bootstrap'; 3 | 4 | let nestApp: INestApplication | undefined; 5 | 6 | (async () => { 7 | nestApp = await bootstrap(); 8 | })(); 9 | 10 | export const app = nestApp; 11 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/types/session.ts: -------------------------------------------------------------------------------- 1 | import type { SessionData } from 'express-session'; 2 | 3 | export interface ISessionData extends SessionData { 4 | passport: { 5 | user: { 6 | id: string; 7 | }; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/utils/code-generate.ts: -------------------------------------------------------------------------------- 1 | import { createHmac } from 'crypto'; 2 | import { baseConfig } from '../configs/base.config'; 3 | 4 | export const generateInvitationCode = (invitationId: string) => { 5 | const hmac = createHmac('sha256', baseConfig().secretKey); 6 | return hmac.update(invitationId).digest('hex'); 7 | }; 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/utils/extract-field-reference.ts: -------------------------------------------------------------------------------- 1 | export const extractFieldReferences = (prompt: string): string[] => { 2 | const fieldRefRegex = /\{(fld[a-zA-Z0-9]+)\}/g; 3 | const fieldIds: string[] = []; 4 | let match; 5 | while ((match = fieldRefRegex.exec(prompt)) !== null) { 6 | fieldIds.push(match[1]); 7 | } 8 | return [...new Set(fieldIds)]; 9 | }; 10 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/utils/get-max-level-role.ts: -------------------------------------------------------------------------------- 1 | import { canManageRole, type IRole } from '@teable/core'; 2 | 3 | export const getMaxLevelRole = (collaborators: { roleName: string | IRole }[]): IRole => { 4 | return collaborators.sort((a, b) => { 5 | return canManageRole(a.roleName as IRole, b.roleName as IRole) ? -1 : 1; 6 | })[0].roleName as IRole; 7 | }; 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './name-conversion'; 2 | export * from './string-hash'; 3 | export * from './file-utils'; 4 | export * from './value-convert'; 5 | export * from './extract-field-reference'; 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/utils/is-user-or-link.ts: -------------------------------------------------------------------------------- 1 | import { FieldType } from '@teable/core'; 2 | 3 | export const isUserOrLink = (type: FieldType) => { 4 | return [FieldType.Link, FieldType.User, FieldType.CreatedBy, FieldType.LastModifiedBy].includes( 5 | type 6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/utils/second.ts: -------------------------------------------------------------------------------- 1 | import ms from 'ms'; 2 | 3 | export const second = (value: string) => { 4 | return Math.floor(ms(value) / 1000); 5 | }; 6 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/utils/string-hash.ts: -------------------------------------------------------------------------------- 1 | export const string2Hash = (str: string) => { 2 | let hash = 5381; 3 | let i = str.length; 4 | 5 | while (i) { 6 | hash = (hash * 33) ^ str.charCodeAt(--i); 7 | } 8 | 9 | return hash >>> 0; 10 | }; 11 | -------------------------------------------------------------------------------- /apps/nestjs-backend/src/ws/ws.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class WsService {} 5 | -------------------------------------------------------------------------------- /apps/nestjs-backend/static/plugin/chart-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nestjs-backend/static/plugin/chart-logo.png -------------------------------------------------------------------------------- /apps/nestjs-backend/static/plugin/chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nestjs-backend/static/plugin/chart.png -------------------------------------------------------------------------------- /apps/nestjs-backend/static/plugin/sheet-form-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nestjs-backend/static/plugin/sheet-form-logo.png -------------------------------------------------------------------------------- /apps/nestjs-backend/static/system/anonymous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nestjs-backend/static/system/anonymous.png -------------------------------------------------------------------------------- /apps/nestjs-backend/static/system/automation-robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nestjs-backend/static/system/automation-robot.png -------------------------------------------------------------------------------- /apps/nestjs-backend/test/data-helpers/caces/aggregation-query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './text-field'; 2 | export * from './number-field'; 3 | export * from './single-select-field'; 4 | export * from './multiple-select-field'; 5 | export * from './checkbox-field'; 6 | export * from './date-field'; 7 | export * from './user-field'; 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/test/data-helpers/caces/record-filter-query/date-field/index.ts: -------------------------------------------------------------------------------- 1 | export * from './is-sets'; 2 | export * from './is-not-sets'; 3 | export * from './is-with-in-sets'; 4 | export * from './is-before-sets'; 5 | export * from './is-on-or-before-sets'; 6 | export * from './is-after-sets'; 7 | export * from './is-on-or-after-sets'; 8 | export * from './date-field'; 9 | -------------------------------------------------------------------------------- /apps/nestjs-backend/test/data-helpers/caces/record-filter-query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './text-field'; 2 | export * from './number-field'; 3 | export * from './single-select-field'; 4 | export * from './date-field'; 5 | export * from './checkbox-field'; 6 | export * from './user-field'; 7 | export * from './multiple-select-field'; 8 | -------------------------------------------------------------------------------- /apps/nestjs-backend/test/utils/get-error.ts: -------------------------------------------------------------------------------- 1 | import type { HttpError } from '@teable/core'; 2 | 3 | export const getError = async (call: () => unknown) => { 4 | try { 5 | await call(); 6 | return; 7 | } catch (error: unknown) { 8 | return error as HttpError; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /apps/nestjs-backend/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": [ 4 | "node_modules", 5 | "test", 6 | "dist", 7 | "**/*spec.ts", 8 | "vitest-e2e.setup.ts", 9 | "vitest-e2e.config.ts", 10 | "vitest.config.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /apps/nextjs-app/.escheckrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaVersion": "es2018", 3 | "module": false, 4 | "files": "./.next/static/chunks/**/*.js", 5 | "not": ["./.next/static/chunks/**/89fde0c3*.js"] 6 | } -------------------------------------------------------------------------------- /apps/nextjs-app/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /apps/nextjs-app/README.md: -------------------------------------------------------------------------------- 1 | # The web-app 2 | 3 | You don't need start this app when developing locally, it's started by the `nestjs-backend`. 4 | 5 | all env is maintained in the .env\* file, it is shared with the backend. 6 | -------------------------------------------------------------------------------- /apps/nextjs-app/babel.config.backup.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | // const isTest = api.env('test'); 3 | // const isDevelopment = api.env('development'); 4 | // const isServer = api.caller((caller) => caller?.isServer); 5 | // const isCallerDevelopment = api.caller((caller) => caller?.isDev); 6 | 7 | api.cache(true); 8 | 9 | return { 10 | presets: [['next/babel']], 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /apps/nextjs-app/config/tests/setupVitest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. 6 | -------------------------------------------------------------------------------- /apps/nextjs-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/favicon.ico -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/example/Boy1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/example/Boy1.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/example/Boy3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/example/Boy3.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/example/Girl1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/example/Girl1.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/example/Girl2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/example/Girl2.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/example/Girl3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/example/Girl3.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/.readme: -------------------------------------------------------------------------------- 1 | icons generate by https://cthedot.de/icongen/ 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-144x144.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-192x192.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-36x36.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-48x48.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-72x72.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-96x96.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-chrome-maskable-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-chrome-maskable-192x192.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/android-chrome-maskable-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/android-chrome-maskable-512x512.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/favicon.ico -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /apps/nextjs-app/public/images/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/apps/nextjs-app/public/images/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /apps/nextjs-app/src/backend/api/rest/axios.ts: -------------------------------------------------------------------------------- 1 | import { createAxios } from '@teable/openapi'; 2 | 3 | export const getAxios = () => { 4 | const axios = createAxios(); 5 | axios.defaults.baseURL = `http://localhost:${process.env.PORT}/api`; 6 | return axios; 7 | }; 8 | 9 | export const axios = getAxios(); 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/backend/api/rest/get-user.ts: -------------------------------------------------------------------------------- 1 | import type { IUser } from '@teable/sdk'; 2 | import { axios } from './axios'; 3 | 4 | export async function getUserMe(cookie?: string) { 5 | return await axios 6 | .get(`/auth/user/me`, { 7 | headers: { cookie }, 8 | }) 9 | .then(({ data }) => data); 10 | } 11 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/components/layout/MainLayout.tsx: -------------------------------------------------------------------------------- 1 | import type { FC, ReactNode } from 'react'; 2 | 3 | export const MainLayout: FC<{ children: ReactNode }> = (props) => { 4 | const { children } = props; 5 | return ( 6 |
7 |
{children}
8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/components/layout/index.ts: -------------------------------------------------------------------------------- 1 | export { MainLayout } from './MainLayout'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/components/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './guide'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/admin/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setting'; 2 | export * from './template'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/admin/setting/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CopyInstance'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/admin/setting/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SettingPage'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/admin/template/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TemplateTable'; 2 | export * from './BaseSelectPanel'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/admin/template/components/upload-panel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Process'; 2 | export * from './Trigger'; 3 | export * from './UploadPanel'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/admin/template/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TemplatePage'; 2 | export * from './components'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CollapsePanel'; 2 | export * from './new-create-panel/FieldConfigPanel'; 3 | export * from './new-create-panel/PreviewColumn'; 4 | export * from './inplace-panel/InplaceFieldConfigPanel'; 5 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/import-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableImport'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/import-table/upload-panel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Process'; 2 | export * from './Trigger'; 3 | export * from './UploadPanel'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/index.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/setting/components/RequireCom.tsx: -------------------------------------------------------------------------------- 1 | export const RequireCom = () => *; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/setting/oauth-app/constant.ts: -------------------------------------------------------------------------------- 1 | import { ActionPrefix } from '@teable/core'; 2 | 3 | export const OAuthActionsPrefixes = [ 4 | ActionPrefix.Table, 5 | ActionPrefix.View, 6 | ActionPrefix.Field, 7 | ActionPrefix.Record, 8 | ActionPrefix.Automation, 9 | ActionPrefix.User, 10 | ]; 11 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/share/view/component/calendar/toolbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Toolbar'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/share/view/component/gallery/toolbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Toolbar'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/share/view/component/grid/aggregation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AggregationProvider'; 2 | export * from './GroupPointProvider'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/share/view/component/grid/toolbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Toolbar'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/share/view/component/kanban/toolbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Toolbar'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/share/view/component/share-view-filter/filter-link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FilterLink'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/share/view/component/share-view-filter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ShareViewFilter'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/space-setting/collaborator/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CollaboratorPage'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/space-setting/general/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GeneralPage'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/space-setting/index.ts: -------------------------------------------------------------------------------- 1 | export * from './general'; 2 | export * from './integration'; 3 | export * from './collaborator'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/space-setting/integration/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IntegrationCard'; 2 | export * from './AiConfig'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/space-setting/integration/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IntegrationPage'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/space/component/upload-panel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Process'; 2 | export * from './Trigger'; 3 | export * from './UploadPanel'; 4 | export * from './UploadPanelDialog'; 5 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/space/index.ts: -------------------------------------------------------------------------------- 1 | export { SpacePage } from './SpacePage'; 2 | export { SpaceInnerPage } from './SpaceInnerPage'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/table/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-locked-view-tip-store'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/calendar/context/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CalendarContext'; 2 | export * from './CalendarProvider'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/calendar/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useCalendar'; 2 | export * from './useCalendarFields'; 3 | export * from './useEventMenuStore'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/calendar/hooks/useCalendar.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { CalendarContext } from '../context'; 3 | 4 | export const useCalendar = () => { 5 | return useContext(CalendarContext); 6 | }; 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/calendar/type.ts: -------------------------------------------------------------------------------- 1 | export interface ICalendarPermission { 2 | eventCreatable: boolean; 3 | eventResizable: boolean; 4 | eventDeletable: boolean; 5 | eventDraggable: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/form/FormView.tsx: -------------------------------------------------------------------------------- 1 | import { FormToolBar } from '../tool-bar/FormToolBar'; 2 | import { FormViewBase } from './FormViewBase'; 3 | 4 | export const FormView = () => { 5 | return ( 6 | <> 7 | 8 |
9 | 10 |
11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/form/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FormSidebar'; 2 | export * from './FormEditorMain'; 3 | export * from './FormEditor'; 4 | export * from './FormPreviewer'; 5 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/form/constant.ts: -------------------------------------------------------------------------------- 1 | export const FORM_SIDEBAR_DROPPABLE_ID = 'form-sidebar'; 2 | export const FORM_EDITOR_DROPPABLE_ID = 'form-editor'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/form/util.ts: -------------------------------------------------------------------------------- 1 | export const generateUniqLocalKey = (tableId?: string, viewId?: string) => `${tableId}-${viewId}`; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/gallery/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Card'; 2 | export * from './CardCarousel'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/gallery/context/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GalleryContext'; 2 | export * from './GalleryProvider'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/gallery/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useGallery'; 2 | export * from './useCacheRecords'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/gallery/hooks/useGallery.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { GalleryContext } from '../context'; 3 | 4 | export const useGallery = () => { 5 | return useContext(GalleryContext); 6 | }; 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/gallery/type.ts: -------------------------------------------------------------------------------- 1 | export interface IGalleryPermission { 2 | cardCreatable: boolean; 3 | cardEditable: boolean; 4 | cardDeletable: boolean; 5 | cardDraggable: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/gallery/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './card'; 2 | export * from './columns'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/grid/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldMenu'; 2 | export * from './RecordMenu'; 3 | export * from './StatisticMenu'; 4 | export * from './GroupHeaderMenu'; 5 | export * from './PrefillingRowContainer'; 6 | export * from './PresortRowContainer'; 7 | export * from '../../field/FieldSetting'; 8 | export * from './AiGenerateButton'; 9 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/grid/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useSelectionOperation'; 2 | export * from './useCollaborate'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/grid/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './selection'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/kanban/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './KanbanContainer'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/kanban/components/interface.ts: -------------------------------------------------------------------------------- 1 | import type { Record as IRecord } from '@teable/sdk/model'; 2 | 3 | export type ICardMap = Record; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/kanban/constant.ts: -------------------------------------------------------------------------------- 1 | import { FieldType } from '@teable/core'; 2 | 3 | export const UNCATEGORIZED_STACK_ID = 't_kanban_uncategorized'; 4 | export const UNCATEGORIZED_STACK_NAME = 'Uncategorized'; 5 | export const UNCATEGORIZED_STACK_EMAIL = 'unknown@teable.io'; 6 | 7 | export const KANBAN_STACK_DISABLED_FIELD_TYPES = [FieldType.Attachment]; 8 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/kanban/context/index.ts: -------------------------------------------------------------------------------- 1 | export * from './KanbanContext'; 2 | export * from './KanbanProvider'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/kanban/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useInView'; 2 | export * from './useKanban'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/kanban/hooks/useKanban.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { KanbanContext } from '../context'; 3 | 4 | export const useKanban = () => { 5 | return useContext(KanbanContext); 6 | }; 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/kanban/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useKanbanStackCollapsed'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/kanban/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './card'; 2 | export * from './drag'; 3 | export * from './filter'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/tool-bar/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GridViewOperators'; 2 | export * from './KanbanViewOperators'; 3 | export * from './GalleryViewOperators'; 4 | export * from './CalendarViewOperators'; 5 | export * from './PersonalViewSwitch'; 6 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/tool-bar/hook/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useViewConfigurable'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/tool-bar/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useFormModeStore'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/blocks/view/types.ts: -------------------------------------------------------------------------------- 1 | import type { IRecord } from '@teable/core'; 2 | import type { IGroupPointsVo } from '@teable/openapi'; 3 | 4 | export interface IViewBaseProps { 5 | recordsServerData: { records: IRecord[] }; 6 | recordServerData?: IRecord; 7 | groupPointsServerDataMap?: { [viewId: string]: IGroupPointsVo | undefined }; 8 | } 9 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/Welcom.tsx: -------------------------------------------------------------------------------- 1 | export const Welcome = () => { 2 | return
welcome
; 3 | }; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/ai-chat/components/types.ts: -------------------------------------------------------------------------------- 1 | import type { IChatMessageUsage } from '@teable/openapi'; 2 | 3 | export interface IMessageMeta { 4 | timeCost?: number; 5 | usage?: IChatMessageUsage; 6 | } 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/ai-chat/context/useChatContext.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ChatContext } from './ChatContext'; 3 | 4 | export const useChatContext = () => { 5 | return useContext(ChatContext); 6 | }; 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/ai-chat/hooks/useChatEnabled.ts: -------------------------------------------------------------------------------- 1 | import { useBaseUsage } from '@/features/app/hooks/useBaseUsage'; 2 | 3 | export const useChatEnabled = () => { 4 | const usage = useBaseUsage(); 5 | const { chatAIEnable = false } = usage?.limit ?? {}; 6 | return chatAIEnable; 7 | }; 8 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/ai-chat/utils.ts: -------------------------------------------------------------------------------- 1 | export const getCreditUsage = ( 2 | promptTokens: number, 3 | completionTokens: number, 4 | modelOptions: { 5 | inputRate?: number; 6 | outputRate?: number; 7 | } 8 | ) => { 9 | const { inputRate = 0.01, outputRate = 0.01 } = modelOptions; 10 | return Math.ceil(promptTokens * inputRate + completionTokens * outputRate); 11 | }; 12 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/collaborator-manage/types.ts: -------------------------------------------------------------------------------- 1 | import type { IRole } from '@teable/core'; 2 | 3 | export interface IRoleStatic { 4 | role: IRole; 5 | name: string; 6 | description: string; 7 | level: number; 8 | } 9 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/expand-record-container/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ExpandRecordContainer'; 2 | export * from './ExpandRecordContainerBase'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/expand-record-container/types.ts: -------------------------------------------------------------------------------- 1 | export interface IExpandRecordContainerRef { 2 | updateRecordIds: (recordIds: string[] | undefined) => void; 3 | } 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/field-ai-config/components/attachment-select/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AttachmentSelect'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/field-ai-config/components/field-select/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldSelect'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/field-ai-config/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './field-select'; 2 | export * from './prompt-editor'; 3 | export * from './attachment-select'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/field-ai-config/components/prompt-editor/extensions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './variable'; 2 | export * from './theme'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/field-ai-config/components/prompt-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PromptEditor'; 2 | export * from './PromptEditorContainer'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/field-ai-config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldAiConfig'; 2 | export * from './TextFieldAiConfig'; 3 | export * from './SingleSelectFieldAiConfig'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldSetting'; 2 | export * from './type'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/options/LinkOptions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LinkOptions'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/field-setting/options/SelectOptions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ChoiceItem'; 2 | export * from './ColorPicker'; 3 | export * from './SelectOptions'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/index.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/notifications/notification-component/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LinkNotification'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/space/template/context.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface ITemplateContext { 4 | spaceId?: string; 5 | } 6 | 7 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 8 | export const TemplateContext = React.createContext({}); 9 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/space/template/hooks/use-space-id.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { TemplateContext } from '../context'; 3 | 4 | export const useSpaceId = () => { 5 | const { spaceId } = useContext(TemplateContext); 6 | return spaceId; 7 | }; 8 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/space/template/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TemplateModal'; 2 | export * from './TemplateMain'; 3 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/components/toggle-side-bar/constant.ts: -------------------------------------------------------------------------------- 1 | export const SIDE_BAR_WIDTH = 288; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/hooks/useEnv.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { EnvContext } from '@/lib/server-env'; 3 | 4 | export function useEnv() { 5 | return useContext(EnvContext); 6 | } 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/hooks/useIsCloud.ts: -------------------------------------------------------------------------------- 1 | import { useEnv } from './useEnv'; 2 | 3 | export const useIsCloud = () => { 4 | const { edition } = useEnv(); 5 | 6 | return edition?.toUpperCase() === 'CLOUD'; 7 | }; 8 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/hooks/useIsEE.ts: -------------------------------------------------------------------------------- 1 | import { useEnv } from './useEnv'; 2 | 3 | export const useIsEE = () => { 4 | const { edition } = useEnv(); 5 | 6 | return edition?.toUpperCase() === 'EE'; 7 | }; 8 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/hooks/useSdkLocale.ts: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'next-i18next'; 2 | 3 | export const useSdkLocale = () => { 4 | const { i18n } = useTranslation(); 5 | return i18n.getDataByLanguage(i18n.language)?.sdk; 6 | }; 7 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/layouts/index.ts: -------------------------------------------------------------------------------- 1 | export { AppLayout } from './AppLayout'; 2 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './file'; 2 | export * from './is-https'; 3 | export * from './is-local'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/utils/is-https.ts: -------------------------------------------------------------------------------- 1 | export function isHTTPS() { 2 | const protocol = window.location.protocol; 3 | 4 | return protocol === 'https:'; 5 | } 6 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/app/utils/is-local.ts: -------------------------------------------------------------------------------- 1 | export function isLocalhost() { 2 | const hostname = window.location.hostname; 3 | 4 | return hostname === 'localhost' || hostname === '127.0.0.1'; 5 | } 6 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/auth.config.ts: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface IAuthConfig { 4 | // Define namespaces in use in both the type and the config. 5 | i18nNamespaces: I18nActiveNamespaces<'common' | 'auth' | 'space' | 'zod'>; 6 | } 7 | 8 | export const authConfig: IAuthConfig = { 9 | i18nNamespaces: ['common', 'auth', 'space', 'zod'], 10 | }; 11 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/automation.tsx: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface IAutomationConfig { 4 | i18nNamespaces: I18nActiveNamespaces<'common' | 'space' | 'sdk'>; 5 | } 6 | 7 | export const automationConfig: IAutomationConfig = { 8 | i18nNamespaces: ['common', 'space', 'sdk'], 9 | }; 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/base.config.ts: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface IBaseConfig { 4 | i18nNamespaces: I18nActiveNamespaces<'common' | 'space' | 'sdk' | 'table'>; 5 | } 6 | 7 | export const baseConfig: IBaseConfig = { 8 | i18nNamespaces: ['common', 'space', 'sdk', 'table'], 9 | }; 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/dashboard.config.ts: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface IDashboardConfig { 4 | i18nNamespaces: I18nActiveNamespaces<'common' | 'space' | 'sdk' | 'table' | 'dashboard' | 'zod'>; 5 | } 6 | 7 | export const dashboardConfig: IDashboardConfig = { 8 | i18nNamespaces: ['common', 'space', 'sdk', 'table', 'dashboard', 'zod'], 9 | }; 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/developer.config.ts: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface IDeveloperConfig { 4 | i18nNamespaces: I18nActiveNamespaces<'common' | 'setting' | 'sdk' | 'developer'>; 5 | } 6 | 7 | export const developerConfig: IDeveloperConfig = { 8 | i18nNamespaces: ['common', 'setting', 'sdk', 'developer'], 9 | }; 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/oauth-app.config.ts: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface IOAuthAppConfig { 4 | i18nNamespaces: I18nActiveNamespaces<'common' | 'setting' | 'sdk' | 'oauth' | 'zod'>; 5 | } 6 | 7 | export const oauthAppConfig: IOAuthAppConfig = { 8 | i18nNamespaces: ['common', 'sdk', 'setting', 'oauth', 'zod'], 9 | }; 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/setting-plugin.config.ts: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface ISettingPluginConfig { 4 | i18nNamespaces: I18nActiveNamespaces<'common' | 'sdk' | 'setting' | 'plugin' | 'zod'>; 5 | } 6 | 7 | export const settingPluginConfig: ISettingPluginConfig = { 8 | i18nNamespaces: ['common', 'sdk', 'setting', 'plugin', 'zod'], 9 | }; 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/space.config.ts: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface ISpaceConfig { 4 | i18nNamespaces: I18nActiveNamespaces<'common' | 'space' | 'sdk'>; 5 | } 6 | 7 | export const spaceConfig: ISpaceConfig = { 8 | i18nNamespaces: ['common', 'space', 'sdk'], 9 | }; 10 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/i18n/system.config.ts: -------------------------------------------------------------------------------- 1 | import type { I18nActiveNamespaces } from '@/lib/i18n'; 2 | 3 | export interface ISystemConfig { 4 | // Define namespaces in use in both the type and the config. 5 | i18nNamespaces: I18nActiveNamespaces<'system'>; 6 | } 7 | 8 | export const systemConfig: ISystemConfig = { 9 | i18nNamespaces: ['system'], 10 | }; 11 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/features/system/pages/index.ts: -------------------------------------------------------------------------------- 1 | export { NotFoundPage } from './NotFoundPage'; 2 | export { ErrorPage } from './ErrorPage'; 3 | export { ForbiddenPage } from './ForbiddenPage'; 4 | export { PaymentRequiredPage } from './PaymentRequired'; 5 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/lib/i18n/I18nNamespace.types.ts: -------------------------------------------------------------------------------- 1 | import type { CustomTypeOptions } from 'i18next'; 2 | 3 | export type I18nNamespace = keyof CustomTypeOptions['resources']; 4 | 5 | /** 6 | * Helper to get fully typed namespaced keys 7 | */ 8 | export type I18nActiveNamespaces = Extract< 9 | I18nNamespace, 10 | NamespacesUnion 11 | >[]; 12 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/lib/i18n/index.ts: -------------------------------------------------------------------------------- 1 | export { getServerSideTranslations } from './getServerSideTranslations'; 2 | export type { I18nActiveNamespaces, I18nNamespace } from './I18nNamespace.types'; 3 | export * from './getTranslationsProps'; 4 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/lib/type.ts: -------------------------------------------------------------------------------- 1 | import type { NextPage } from 'next'; 2 | import type { ReactElement, ReactNode } from 'react'; 3 | 4 | export type NextPageWithLayout

, IP = P> = NextPage & { 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 6 | getLayout?: (page: ReactElement, appProps: any) => ReactNode; 7 | }; 8 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/pages/auth/signup.tsx: -------------------------------------------------------------------------------- 1 | import LoginRoute from './login'; 2 | 3 | export { getServerSideProps } from './login'; 4 | 5 | export default LoginRoute; 6 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/themes/tailwind/tailwind.theme.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Keep this file as '.js' as it's included in tailwind.config.js 3 | 4 | const { browserFonts } = require('../shared/browser-fonts'); 5 | 6 | module.exports = { 7 | fontFamily: { 8 | sans: ['Inter Variable', ...browserFonts.sans], 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/themes/type.ts: -------------------------------------------------------------------------------- 1 | import type { IColor } from './colors'; 2 | 3 | export enum ThemeName { 4 | Light = 'light', 5 | Dark = 'dark', 6 | } 7 | 8 | export interface ITheme { 9 | color: IColor; 10 | } 11 | -------------------------------------------------------------------------------- /apps/nextjs-app/src/types.d/umami.d.ts: -------------------------------------------------------------------------------- 1 | declare interface Window { 2 | umami?: { 3 | identify: (props: { email?: string; id?: string; name?: string }) => void; 4 | }; 5 | } 6 | -------------------------------------------------------------------------------- /apps/nextjs-app/tsconfig.scripts.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strictNullChecks": true, 4 | "module": "NodeNext", 5 | "esModuleInterop": true 6 | }, 7 | "include": ["**/*.ts", "**/*.tsx"] 8 | } 9 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /packages/common-i18n/src/locales/en/*.json 3 | translation: /packages/common-i18n/src/locales/%two_letters_code%/%original_file_name% 4 | -------------------------------------------------------------------------------- /dockers/.env: -------------------------------------------------------------------------------- 1 | TIMEZONE=Asia/Singapore 2 | 3 | # PostgreSQL Env 4 | POSTGRES_DB=teable 5 | POSTGRES_USER=teable 6 | POSTGRES_PASSWORD=teable 7 | 8 | # Redis env 9 | REDIS_PASSWORD=teable 10 | 11 | # Minio env 12 | MINIO_ACCESS_KEY=teable 13 | MINIO_SECRET_KEY=teable123 -------------------------------------------------------------------------------- /dockers/examples/docker-swarm/docker-compose.default.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | networks: 4 | teable-swarm: 5 | external: true 6 | 7 | volumes: 8 | teable-db: 9 | teable-cache: 10 | teable-storage: 11 | -------------------------------------------------------------------------------- /dockers/examples/standalone/README.md: -------------------------------------------------------------------------------- 1 | # Example with teable standalone 2 | 3 | Look into the `.env` file and update the vaiables before executing `docker compose up -d`. 4 | 5 | ## Teable 6 | 7 | - Accessible via `http://127.0.0.1:3000` 8 | - Uses postgres db for storage 9 | - Telemetry is disabled 10 | -------------------------------------------------------------------------------- /dockers/networks.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | networks: 4 | teable-net: 5 | name: ${NETWORK_MODE:-teablenet} 6 | external: true 7 | -------------------------------------------------------------------------------- /dockers/teable/Dockerfile.db-migrate: -------------------------------------------------------------------------------- 1 | FROM alpine:3.19 2 | CMD echo "[DEPRECATED] db-migrate image is deprecated and no longer needed. This image will be removed in v2.0.0." && exit 0 3 | -------------------------------------------------------------------------------- /packages/common-i18n/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # build 4 | /dist 5 | 6 | # dependencies 7 | node_modules 8 | 9 | # testing 10 | /coverage 11 | 12 | # misc 13 | .DS_Store 14 | *.pem 15 | -------------------------------------------------------------------------------- /packages/common-i18n/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/common-i18n/src/index.ts: -------------------------------------------------------------------------------- 1 | export type { I18nNamespaces } from './I18nNamespaces'; 2 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/de/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "Persönliche Zugangstoken", 3 | "oauthApps": "OAuth Apps", 4 | "plugins": "Plugins" 5 | } 6 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/en/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "Personal access tokens", 3 | "oauthApps": "OAuth Apps", 4 | "plugins": "Plugins" 5 | } 6 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/en/share.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "title": "Enter your password to view this page", 4 | "submit": "Submit", 5 | "password": "Password" 6 | }, 7 | "toolbar": { 8 | "filterLinkSelectPlaceholder": "Select..." 9 | }, 10 | "openOnNewPage": "Open on new page", 11 | "errorTips": "Sharing source has enabled a Authority Matrix, viewing is not allowed" 12 | } 13 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/es/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "Tokens de acceso personal", 3 | "oauthApps": "Aplicaciones OAuth", 4 | "plugins": "Complementos" 5 | } 6 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/fr/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "Jetons d'accès personnel", 3 | "oauthApps": "Applications OAuth" 4 | } 5 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/it/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "Token di accesso personale", 3 | "oauthApps": "App OAuth", 4 | "plugins": "Plugin" 5 | } 6 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/ja/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "個人アクセストークン", 3 | "oauthApps": "OAuthアプリ" 4 | } 5 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/ja/share.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "title": "このページを表示するにはパスワードを入力してください", 4 | "submit": "送信", 5 | "password": "パスワード" 6 | }, 7 | "toolbar": { 8 | "filterLinkSelectPlaceholder": "選択..." 9 | }, 10 | "openOnNewPage": "新しいページで開く", 11 | "errorTips": "ソースの共有により権限マトリックスが有効になりましたが、表示は許可されていません" 12 | } 13 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/ru/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "Персональные токены доступа", 3 | "oauthApps": "OAuth приложения", 4 | "plugins": "Плагины" 5 | } 6 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/tr/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "Kişisel erişim tokenleri", 3 | "oauthApps": "OAuth Uygulamaları", 4 | "plugins": "Eklentiler" 5 | } 6 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/uk/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "Персональні токени доступу", 3 | "oauthApps": "OAuth Додатки", 4 | "plugins": "Плагіни" 5 | } 6 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/zh/dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty": { 3 | "title": "暂无仪表盘", 4 | "description": "看起来您还没有创建任何仪表盘。仪表盘可以帮助您更有效地可视化和管理数据。", 5 | "create": "创建您的第一个仪表盘" 6 | }, 7 | "addPlugin": "添加插件", 8 | "createDashboard": { 9 | "button": "创建仪表盘", 10 | "title": "创建新仪表盘", 11 | "placeholder": "输入仪表盘名称" 12 | }, 13 | "findDashboard": "查找仪表盘..." 14 | } 15 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/zh/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "personalAccessToken": "个人访问令牌", 3 | "oauthApps": "OAuth 应用", 4 | "plugins": "插件" 5 | } 6 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/zh/share.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "title": "输入您的密码查看此页面", 4 | "submit": "提交", 5 | "password": "密码" 6 | }, 7 | "toolbar": { 8 | "filterLinkSelectPlaceholder": "请选择..." 9 | }, 10 | "openOnNewPage": "在新页面查看", 11 | "errorTips": "分享来源已启用权限矩阵,无法查看" 12 | } 13 | -------------------------------------------------------------------------------- /packages/common-i18n/src/locales/zh/system.json: -------------------------------------------------------------------------------- 1 | { 2 | "notFound": { 3 | "title": "404 - 找不到页面" 4 | }, 5 | "links": { 6 | "backToHome": "返回主页" 7 | }, 8 | "forbidden": { 9 | "title": "403 - 禁止访问", 10 | "description": "您没有权限访问此页面" 11 | }, 12 | "paymentRequired": { 13 | "title": "402 - 需要升级订阅", 14 | "description": "您当前的订阅计划不支持访问此功能,请升级您的订阅以继续使用" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/.escheckrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaVersion": "es2017", 3 | "module": true, 4 | "files": "./dist/**/*.js" 5 | } -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # build 4 | /dist 5 | 6 | # dependencies 7 | node_modules 8 | 9 | # testing 10 | /coverage 11 | 12 | # misc 13 | .DS_Store 14 | *.pem 15 | 16 | # antlr 17 | .antlr/ 18 | -------------------------------------------------------------------------------- /packages/core/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/core/.size-limit.cjs: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | name: 'JS', 4 | path: ['dist/index.js'], 5 | limit: '3KB', 6 | }, 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/core/src/array/index.ts: -------------------------------------------------------------------------------- 1 | export { ArrayUtils } from './ArrayUtils'; 2 | -------------------------------------------------------------------------------- /packages/core/src/asserts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './asserts'; 2 | export * from './lang'; 3 | -------------------------------------------------------------------------------- /packages/core/src/asserts/lang.ts: -------------------------------------------------------------------------------- 1 | export const LOCALES = ['en', 'zh', 'fr'] as const; 2 | -------------------------------------------------------------------------------- /packages/core/src/auth/anonymous.ts: -------------------------------------------------------------------------------- 1 | export const ANONYMOUS_USER_ID = 'anonymous'; 2 | 3 | export const isAnonymous = (userId: string) => userId === ANONYMOUS_USER_ID; 4 | -------------------------------------------------------------------------------- /packages/core/src/auth/index.ts: -------------------------------------------------------------------------------- 1 | export * from './actions'; 2 | export * from './role'; 3 | export * from './permission'; 4 | export * from './anonymous'; 5 | export * from './system'; 6 | export * from './me-tag'; 7 | export * from './types'; 8 | export * from './oauth'; 9 | -------------------------------------------------------------------------------- /packages/core/src/auth/me-tag.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/naming-convention 2 | export const Me = 'Me'; 3 | 4 | export const isMeTag = (str: string) => str === Me; 5 | -------------------------------------------------------------------------------- /packages/core/src/auth/role/index.ts: -------------------------------------------------------------------------------- 1 | export * from './space'; 2 | export * from './base'; 3 | export * from './share'; 4 | export * from './types'; 5 | export * from './table'; 6 | export * from './constant'; 7 | export * from './utils'; 8 | -------------------------------------------------------------------------------- /packages/core/src/auth/role/space.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from '../actions'; 2 | 3 | export type ISpaceAction = Action; 4 | -------------------------------------------------------------------------------- /packages/core/src/auth/role/utils.ts: -------------------------------------------------------------------------------- 1 | import { RoleLevel } from './types'; 2 | 3 | export const canManageRole = (managerRole: string, targetRole: string) => { 4 | return RoleLevel.indexOf(managerRole) < RoleLevel.indexOf(targetRole); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/core/src/auth/system.ts: -------------------------------------------------------------------------------- 1 | export const SYSTEM_USER_ID = 'system'; 2 | 3 | export const getPluginEmail = (pluginId: string) => `${pluginId.toLowerCase()}@plugin.teable.io`; 4 | -------------------------------------------------------------------------------- /packages/core/src/auth/types.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/naming-convention 2 | export type ExcludeAction = T extends F ? never : T; 3 | 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export type PickAction = T extends F ? T : never; 6 | -------------------------------------------------------------------------------- /packages/core/src/convert/index.ts: -------------------------------------------------------------------------------- 1 | export * from './string-convert'; 2 | export * from './nulls-to-undefined'; 3 | -------------------------------------------------------------------------------- /packages/core/src/errors/http/index.ts: -------------------------------------------------------------------------------- 1 | export * from './http-response.types'; 2 | export * from './http.error'; 3 | export * from './constant'; 4 | -------------------------------------------------------------------------------- /packages/core/src/errors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './http'; 2 | -------------------------------------------------------------------------------- /packages/core/src/models/aggregation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './statistics-func.enum'; 2 | export * from './statistic'; 3 | -------------------------------------------------------------------------------- /packages/core/src/models/index.ts: -------------------------------------------------------------------------------- 1 | export * from './field'; 2 | export * from './table'; 3 | export * from './view'; 4 | export * from './interface'; 5 | export * from './record'; 6 | export * from './op'; 7 | export * from './aggregation'; 8 | export * from './notification'; 9 | export * from './channel'; 10 | -------------------------------------------------------------------------------- /packages/core/src/models/interface.ts: -------------------------------------------------------------------------------- 1 | export interface ISnapshotBase { 2 | id: string; 3 | v: number; 4 | type: string | null; 5 | data: T; 6 | m?: unknown; 7 | } 8 | -------------------------------------------------------------------------------- /packages/core/src/models/notification/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notification.schema'; 2 | export * from './notification.enum'; 3 | export * from './action-trigger.schema'; 4 | -------------------------------------------------------------------------------- /packages/core/src/models/notification/notification.enum.ts: -------------------------------------------------------------------------------- 1 | export enum NotificationTypeEnum { 2 | System = 'system', 3 | CollaboratorCellTag = 'collaboratorCellTag', 4 | CollaboratorMultiRowTag = 'collaboratorMultiRowTag', 5 | Comment = 'comment', 6 | ExportBase = 'exportBase', 7 | } 8 | 9 | export enum NotificationStatesEnum { 10 | Unread = 'unread', 11 | Read = 'read', 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/src/models/record/index.ts: -------------------------------------------------------------------------------- 1 | export * from './record'; 2 | -------------------------------------------------------------------------------- /packages/core/src/models/table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './table'; 2 | -------------------------------------------------------------------------------- /packages/core/src/models/table/table.ts: -------------------------------------------------------------------------------- 1 | export class TableCore { 2 | id!: string; 3 | 4 | name!: string; 5 | 6 | dbTableName!: string; 7 | 8 | icon?: string; 9 | 10 | description?: string; 11 | 12 | lastModifiedTime!: string; 13 | 14 | defaultViewId!: string; 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/src/models/view/derivate/index.ts: -------------------------------------------------------------------------------- 1 | export * from './grid.view'; 2 | export * from './kanban.view'; 3 | export * from './gallery.view'; 4 | export * from './calendar.view'; 5 | export * from './form.view'; 6 | export * from './plugin.view'; 7 | -------------------------------------------------------------------------------- /packages/core/src/models/view/filter/conjunction.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | export const and = z.literal('and'); 4 | export const or = z.literal('or'); 5 | 6 | export const conjunctionSchema = z.union([and, or]); 7 | export type IConjunction = z.infer; 8 | -------------------------------------------------------------------------------- /packages/core/src/models/view/filter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './conjunction'; 2 | export * from './filter-item'; 3 | export * from './operator'; 4 | export * from './filter'; 5 | -------------------------------------------------------------------------------- /packages/core/src/models/view/group/index.ts: -------------------------------------------------------------------------------- 1 | export * from './group'; 2 | -------------------------------------------------------------------------------- /packages/core/src/models/view/index.ts: -------------------------------------------------------------------------------- 1 | export * from './view.schema'; 2 | export * from './view'; 3 | export * from './constant'; 4 | export * from './derivate'; 5 | export * from './filter'; 6 | export * from './sort'; 7 | export * from './group'; 8 | export * from './option.schema'; 9 | export * from './column-meta.schema'; 10 | export * from './query.replace'; 11 | -------------------------------------------------------------------------------- /packages/core/src/models/view/sort/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sort'; 2 | export * from './sort-func.enum'; 3 | -------------------------------------------------------------------------------- /packages/core/src/models/view/sort/sort-func.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SortFunc { 2 | Asc = 'asc', 3 | Desc = 'desc', 4 | } 5 | -------------------------------------------------------------------------------- /packages/core/src/op-builder/field/add-field.ts: -------------------------------------------------------------------------------- 1 | import type { IFieldVo } from '../../models'; 2 | import { OpName } from '../common'; 3 | import type { ICreateOpBuilder } from '../interface'; 4 | 5 | export class AddFieldBuilder implements ICreateOpBuilder { 6 | name: OpName.AddField = OpName.AddField; 7 | 8 | build(field: IFieldVo): IFieldVo { 9 | return field; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/op-builder/field/index.ts: -------------------------------------------------------------------------------- 1 | // export all in this folder 2 | export * from './field-op-builder'; 3 | export * from './add-column-meta'; 4 | export * from './add-field'; 5 | export * from './delete-column-meta'; 6 | export * from './set-field-property'; 7 | -------------------------------------------------------------------------------- /packages/core/src/op-builder/index.ts: -------------------------------------------------------------------------------- 1 | export type { IOpBuilder, ICreateOpBuilder, IOpContextBase } from './interface'; 2 | 3 | export * from './view'; 4 | export * from './field'; 5 | export * from './record'; 6 | export * from './table'; 7 | 8 | export { OpName } from './common'; 9 | -------------------------------------------------------------------------------- /packages/core/src/op-builder/record/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-record'; 2 | export * from './record-op-builder'; 3 | export * from './set-record'; 4 | -------------------------------------------------------------------------------- /packages/core/src/op-builder/table/add-table.ts: -------------------------------------------------------------------------------- 1 | import { OpName } from '../common'; 2 | import type { ICreateOpBuilder } from '../interface'; 3 | import type { ITableOp } from './set-table-property'; 4 | 5 | export class AddTableBuilder implements ICreateOpBuilder { 6 | name: OpName.AddTable = OpName.AddTable; 7 | 8 | build(table: ITableOp): ITableOp { 9 | return table; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/op-builder/table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-table'; 2 | export * from './table-op-builder'; 3 | export * from './set-table-property'; 4 | -------------------------------------------------------------------------------- /packages/core/src/op-builder/view/add-view.ts: -------------------------------------------------------------------------------- 1 | import type { IViewVo } from '../../models'; 2 | import { OpName } from '../common'; 3 | import type { ICreateOpBuilder } from '../interface'; 4 | 5 | export class AddViewBuilder implements ICreateOpBuilder { 6 | name: OpName.AddView = OpName.AddView; 7 | 8 | build(view: IViewVo): IViewVo { 9 | return view; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/op-builder/view/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-view'; 2 | export * from './view-op-builder'; 3 | export * from './update-view-column-meta'; 4 | export * from './set-view-property'; 5 | -------------------------------------------------------------------------------- /packages/core/src/query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './json.visitor'; 2 | -------------------------------------------------------------------------------- /packages/core/src/typeguards/index.ts: -------------------------------------------------------------------------------- 1 | export * from './typeguards'; 2 | export * from './json-api'; 3 | -------------------------------------------------------------------------------- /packages/core/src/typeguards/json-api/index.ts: -------------------------------------------------------------------------------- 1 | export * from './json-api-response.types'; 2 | export * from './json-api.typeguard'; 3 | -------------------------------------------------------------------------------- /packages/core/src/types/ensure-keys.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2 | export type IEnsureKeysMatchInterface = K extends readonly (keyof T)[] 3 | ? keyof T extends K[number] 4 | ? K[number] extends keyof T 5 | ? true 6 | : never 7 | : never 8 | : never; 9 | -------------------------------------------------------------------------------- /packages/core/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './un-promisify'; 2 | export * from './remove-null'; 3 | export * from './snapshot-query'; 4 | export * from './either-or'; 5 | export * from './make-required'; 6 | export * from './make-optional'; 7 | export * from './ensure-keys'; 8 | -------------------------------------------------------------------------------- /packages/core/src/types/make-optional.ts: -------------------------------------------------------------------------------- 1 | export type IMakeOptional = Omit & Partial>; 2 | -------------------------------------------------------------------------------- /packages/core/src/types/make-required.ts: -------------------------------------------------------------------------------- 1 | export type IMakeRequired = { 2 | [P in K]-?: T[P]; 3 | } & Omit; 4 | -------------------------------------------------------------------------------- /packages/core/src/types/remove-null.ts: -------------------------------------------------------------------------------- 1 | export type IRecursivelyReplaceNullWithUndefined = T extends null 2 | ? undefined 3 | : T extends Date 4 | ? T 5 | : { 6 | [K in keyof T]: T[K] extends (infer U)[] 7 | ? IRecursivelyReplaceNullWithUndefined[] 8 | : IRecursivelyReplaceNullWithUndefined; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/core/src/types/snapshot-query.ts: -------------------------------------------------------------------------------- 1 | export interface IExtraResult { 2 | [key: string]: unknown; 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/types/un-promisify.ts: -------------------------------------------------------------------------------- 1 | export type IUnPromisify = T extends Promise ? U : T; 2 | -------------------------------------------------------------------------------- /packages/core/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-random-int'; 2 | export * from './id-generator'; 3 | export * from './get-uniq-name'; 4 | export * from './date'; 5 | export * from './dsn-parser'; 6 | export * from './clipboard'; 7 | export * from './minidenticon'; 8 | export * from './replace-suffix'; 9 | -------------------------------------------------------------------------------- /packages/core/src/zod.ts: -------------------------------------------------------------------------------- 1 | import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi'; 2 | import { z } from 'zod'; 3 | 4 | extendZodWithOpenApi(z); 5 | 6 | export { z }; 7 | -------------------------------------------------------------------------------- /packages/core/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./tsconfig.json", 4 | "exclude": ["dist", "**/__tests__/*", "**/*spec.ts"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/vitest.setup.js: -------------------------------------------------------------------------------- 1 | const { extendZodWithOpenApi } = require('@asteasolutions/zod-to-openapi'); 2 | const dayjs = require('dayjs'); 3 | const timezone = require('dayjs/plugin/timezone'); 4 | const utc = require('dayjs/plugin/utc'); 5 | const { z } = require('zod'); 6 | 7 | extendZodWithOpenApi(z); 8 | dayjs.extend(utc); 9 | dayjs.extend(timezone); 10 | -------------------------------------------------------------------------------- /packages/db-main-prisma/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # generated 4 | 5 | /src/generated 6 | 7 | # build 8 | /dist 9 | 10 | # dependencies 11 | node_modules 12 | 13 | # testing 14 | /coverage 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | 20 | /db 21 | -------------------------------------------------------------------------------- /packages/db-main-prisma/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20240313062534_add_credit/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "space" ADD COLUMN "credit" INTEGER; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20240625032002_add_admin/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "users" ADD COLUMN "deactivated_time" TIMESTAMP(3), 3 | ADD COLUMN "is_admin" BOOLEAN; 4 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20240628115120_add_space_invitation/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "setting" ADD COLUMN "disallow_space_invitation" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20241031080906_add_attachment_thumbnail/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "attachments" ADD COLUMN "thumbnail_path" TEXT; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20241128112023_add_ai_config/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "setting" ADD COLUMN "ai_config" TEXT; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20241226111824_remove_collaborator_foreign_user/migration.sql: -------------------------------------------------------------------------------- 1 | -- DropForeignKey 2 | ALTER TABLE "collaborator" DROP CONSTRAINT "collaborator_principal_id_fkey"; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20250115084212_add_enable_email_verification_setting/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "setting" ADD COLUMN "enable_email_verification" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20250117105433_update_view/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "view" ADD COLUMN "is_locked" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20250328035739_brand/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "setting" ADD COLUMN "brand_logo" TEXT, 3 | ADD COLUMN "brand_name" TEXT; 4 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20250406145144_add_share_id_unique/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - A unique constraint covering the columns `[share_id]` on the table `view` will be added. If there are existing duplicate values, this will fail. 5 | 6 | */ 7 | -- CreateIndex 8 | CREATE UNIQUE INDEX "view_share_id_key" ON "view"("share_id"); 9 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20250416113238_add_template_markdown_description/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "template" ADD COLUMN "markdown_description" TEXT; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20250418091636_add_db_table_name_index/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateIndex 2 | CREATE INDEX "table_meta_db_table_name_idx" ON "table_meta"("db_table_name"); 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20250520103546_add_user_trial_used/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "users" ADD COLUMN "is_trial_used" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/20250604101438_update_access_token_full_access/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "access_token" ADD COLUMN "has_full_access" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/postgres/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (e.g., Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20240313061543_add_credit/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "space" ADD COLUMN "credit" INTEGER; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20240625031955_add_admin/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "users" ADD COLUMN "deactivated_time" DATETIME; 3 | ALTER TABLE "users" ADD COLUMN "is_admin" BOOLEAN; 4 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20240628115107_add_space_invitation/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "setting" ADD COLUMN "disallow_space_invitation" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20241031080903_add_attachment_thumbnail/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "attachments" ADD COLUMN "thumbnail_path" TEXT; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20241128112016_add_ai_config/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "setting" ADD COLUMN "ai_config" TEXT; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20250115084207_add_enable_email_verification_setting/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "setting" ADD COLUMN "enable_email_verification" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20250117105406_update_view/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "view" ADD COLUMN "is_locked" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20250328040207_brand/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "setting" ADD COLUMN "brand_logo" TEXT; 3 | ALTER TABLE "setting" ADD COLUMN "brand_name" TEXT; 4 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20250406145126_add_share_id_unique/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - A unique constraint covering the columns `[share_id]` on the table `view` will be added. If there are existing duplicate values, this will fail. 5 | 6 | */ 7 | -- CreateIndex 8 | CREATE UNIQUE INDEX "view_share_id_key" ON "view"("share_id"); 9 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20250416113234_add_template_markdown_description/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "template" ADD COLUMN "markdown_description" TEXT; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20250418091633_add_db_table_name_index/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateIndex 2 | CREATE INDEX "table_meta_db_table_name_idx" ON "table_meta"("db_table_name"); 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20250520103541_add_user_trial_used/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "users" ADD COLUMN "is_trial_used" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/20250604101438_update_access_token_full_access/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "access_token" ADD COLUMN "has_full_access" BOOLEAN; 3 | -------------------------------------------------------------------------------- /packages/db-main-prisma/prisma/sqlite/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (e.g., Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /packages/db-main-prisma/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@prisma/client'; 2 | export * from './utils'; 3 | export * from './prisma.module'; 4 | export * from './prisma.service'; 5 | -------------------------------------------------------------------------------- /packages/eslint-config-bases/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/eslint-config-bases/src/bases/prettier-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Custom config base for projects using prettier. 3 | * @see https://github.com/belgattitude/nextjs-monorepo-example/tree/main/packages/eslint-config-bases 4 | */ 5 | 6 | module.exports = { 7 | extends: ['prettier'], 8 | rules: { 9 | 'arrow-body-style': 'off', 10 | 'prefer-arrow-callback': 'off', 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/eslint-config-bases/src/helpers/getPrettierConfig.js: -------------------------------------------------------------------------------- 1 | const prettierBaseConfig = require('../prettier.base.config'); 2 | 3 | const getPrettierConfig = () => { 4 | return prettierBaseConfig; 5 | }; 6 | 7 | module.exports = { 8 | getPrettierConfig, 9 | }; 10 | -------------------------------------------------------------------------------- /packages/eslint-config-bases/src/helpers/index.js: -------------------------------------------------------------------------------- 1 | const { getDefaultIgnorePatterns } = require('./getDefaultIgnorePatterns'); 2 | const { getPrettierConfig } = require('./getPrettierConfig'); 3 | 4 | module.exports = { 5 | getDefaultIgnorePatterns, 6 | getPrettierConfig, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/eslint-config-bases/src/index.js: -------------------------------------------------------------------------------- 1 | const { typescript } = require('./bases'); 2 | 3 | module.exports = typescript; 4 | -------------------------------------------------------------------------------- /packages/eslint-config-bases/src/patch/modern-module-resolution.js: -------------------------------------------------------------------------------- 1 | // See https://www.npmjs.com/package/@rushstack/eslint-patch 2 | // @ts-ignore 3 | require('@rushstack/eslint-patch/modern-module-resolution'); 4 | -------------------------------------------------------------------------------- /packages/eslint-config-bases/src/prettier.base.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** 4 | * @type {import('prettier').Config} 5 | */ 6 | module.exports = { 7 | singleQuote: true, 8 | semi: true, 9 | printWidth: 100, 10 | tabWidth: 2, 11 | bracketSpacing: true, 12 | trailingComma: 'es5', 13 | bracketSameLine: false, 14 | useTabs: false, 15 | endOfLine: 'lf', 16 | overrides: [], 17 | }; 18 | -------------------------------------------------------------------------------- /packages/icons/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # build 4 | /dist 5 | /build 6 | /storybook-static 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # testing 12 | /coverage 13 | 14 | # misc 15 | .DS_Store 16 | *.pem 17 | 18 | .env 19 | -------------------------------------------------------------------------------- /packages/icons/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/openapi/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # build 4 | /dist 5 | 6 | # dependencies 7 | node_modules 8 | 9 | # testing 10 | /coverage 11 | 12 | # misc 13 | .DS_Store 14 | *.pem 15 | 16 | # antlr 17 | .antlr/ 18 | -------------------------------------------------------------------------------- /packages/openapi/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/openapi/src/access-token/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create'; 2 | export * from './refresh'; 3 | export * from './delete'; 4 | export * from './list'; 5 | export * from './update'; 6 | export * from './get'; 7 | -------------------------------------------------------------------------------- /packages/openapi/src/admin/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setting'; 2 | export * from './plugin'; 3 | -------------------------------------------------------------------------------- /packages/openapi/src/admin/plugin/index.ts: -------------------------------------------------------------------------------- 1 | export * from './publish'; 2 | export * from './unpublish'; 3 | -------------------------------------------------------------------------------- /packages/openapi/src/admin/setting/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get'; 2 | export * from './get-public'; 3 | export * from './update'; 4 | export * from './upload-logo'; 5 | -------------------------------------------------------------------------------- /packages/openapi/src/aggregation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-aggregation'; 2 | export * from './get-row-count'; 3 | export * from './get-group-points'; 4 | export * from './get-calendar-daily-collection'; 5 | export * from './type'; 6 | export * from './get-search-count'; 7 | export * from './get-search-by-index'; 8 | export * from './get-task-status-collection'; 9 | -------------------------------------------------------------------------------- /packages/openapi/src/ai/index.ts: -------------------------------------------------------------------------------- 1 | export * from './generate-stream'; 2 | export * from './get-config'; 3 | -------------------------------------------------------------------------------- /packages/openapi/src/attachment/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notify'; 2 | export * from './read-file'; 3 | export * from './signature'; 4 | export * from './upload-file'; 5 | -------------------------------------------------------------------------------- /packages/openapi/src/auth/types.ts: -------------------------------------------------------------------------------- 1 | import { z } from '../zod'; 2 | 3 | export const passwordSchema = z.string().min(8).openapi({ 4 | description: 'Minimum 8 chars', 5 | }); 6 | 7 | export const signupPasswordSchema = passwordSchema.regex( 8 | /^(?=.*[A-Z])(?=.*\d).{8,}$/i, 9 | 'Must contain at least one letter and one number' 10 | ); 11 | -------------------------------------------------------------------------------- /packages/openapi/src/base/query-data/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './route'; 3 | -------------------------------------------------------------------------------- /packages/openapi/src/billing/index.ts: -------------------------------------------------------------------------------- 1 | export * from './subscription'; 2 | -------------------------------------------------------------------------------- /packages/openapi/src/billing/subscription/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-subscription-summary'; 2 | export * from './get-subscription-summary-list'; 3 | -------------------------------------------------------------------------------- /packages/openapi/src/chat/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-messages'; 2 | export * from './history'; 3 | export * from './types'; 4 | export * from './chat-delete'; 5 | export * from './chat-rename'; 6 | -------------------------------------------------------------------------------- /packages/openapi/src/comment/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-list'; 2 | export * from './types'; 3 | export * from './create'; 4 | export * from './update'; 5 | export * from './get'; 6 | export * from './delete'; 7 | export * from './reaction'; 8 | export * from './subscribe'; 9 | export * from './get-attachment-url'; 10 | export * from './get-counts-by-query'; 11 | export * from './get-count'; 12 | -------------------------------------------------------------------------------- /packages/openapi/src/comment/reaction/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-reaction'; 2 | export * from './delete-reaction'; 3 | export * from './constant'; 4 | -------------------------------------------------------------------------------- /packages/openapi/src/comment/subscribe/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-subscribe'; 2 | export * from './delete-subscribe'; 3 | export * from './get-subscribe'; 4 | -------------------------------------------------------------------------------- /packages/openapi/src/db-connection/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create'; 2 | export * from './delete'; 3 | export * from './get'; 4 | -------------------------------------------------------------------------------- /packages/openapi/src/export/index.ts: -------------------------------------------------------------------------------- 1 | export * from './export-csv'; 2 | -------------------------------------------------------------------------------- /packages/openapi/src/field/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create'; 2 | export * from './delete'; 3 | export * from './get-list'; 4 | export * from './get'; 5 | export * from './update'; 6 | export * from './convert'; 7 | export * from './delete-list'; 8 | export * from './filter-link-records'; 9 | export * from './auto-fill-field'; 10 | export * from './stop-fill-field'; 11 | export * from './duplicate'; 12 | -------------------------------------------------------------------------------- /packages/openapi/src/import/index.ts: -------------------------------------------------------------------------------- 1 | export * from './analyze'; 2 | export * from './import-table'; 3 | export * from './inplace-import-table'; 4 | export * from './constant'; 5 | export * from './types'; 6 | -------------------------------------------------------------------------------- /packages/openapi/src/integrity/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link-check'; 2 | export * from './link-fix'; 3 | -------------------------------------------------------------------------------- /packages/openapi/src/invitation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './accept'; 2 | -------------------------------------------------------------------------------- /packages/openapi/src/notification/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-list'; 2 | export * from './update-status'; 3 | export * from './read-all'; 4 | export * from './unread-count'; 5 | -------------------------------------------------------------------------------- /packages/openapi/src/oauth/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create'; 2 | export * from './delete'; 3 | export * from './get-list'; 4 | export * from './get'; 5 | export * from './update'; 6 | 7 | export * from './secret-delete'; 8 | export * from './secret-generate'; 9 | 10 | export * from './decision-info'; 11 | export * from './revoke'; 12 | export * from './authorized-list'; 13 | -------------------------------------------------------------------------------- /packages/openapi/src/organization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-me'; 2 | export * from './departments'; 3 | export * from './user-get'; 4 | -------------------------------------------------------------------------------- /packages/openapi/src/pin/index.ts: -------------------------------------------------------------------------------- 1 | export * from './delete'; 2 | export * from './add'; 3 | export * from './get-list'; 4 | export * from './types'; 5 | export * from './update-order'; 6 | -------------------------------------------------------------------------------- /packages/openapi/src/pin/types.ts: -------------------------------------------------------------------------------- 1 | export enum PinType { 2 | Space = 'space', 3 | Base = 'base', 4 | Table = 'table', 5 | View = 'view', 6 | } 7 | -------------------------------------------------------------------------------- /packages/openapi/src/plan/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plan'; 2 | export * from './plan-create'; 3 | export * from './plan-convert'; 4 | -------------------------------------------------------------------------------- /packages/openapi/src/plugin-context-menu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugin-get'; 2 | export * from './plugin-install'; 3 | export * from './plugin-move'; 4 | export * from './plugin-remove'; 5 | export * from './plugin-rename'; 6 | export * from './plugin-update-storage'; 7 | export * from './plugin-get-list'; 8 | export * from './plugin-get-storage'; 9 | -------------------------------------------------------------------------------- /packages/openapi/src/selection/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clear'; 2 | export * from './copy'; 3 | export * from './paste'; 4 | export * from './range'; 5 | export * from './delete'; 6 | export * from './temporary-paste'; 7 | -------------------------------------------------------------------------------- /packages/openapi/src/template/category/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create'; 2 | export * from './get'; 3 | export * from './delete'; 4 | export * from './update'; 5 | export * from './get-published'; 6 | -------------------------------------------------------------------------------- /packages/openapi/src/template/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create'; 2 | export * from './get'; 3 | export * from './get-published'; 4 | export * from './delete'; 5 | export * from './update'; 6 | export * from './create-snapshot'; 7 | export * from './category'; 8 | export * from './pin-top'; 9 | export * from './get-template-detail'; 10 | -------------------------------------------------------------------------------- /packages/openapi/src/trash/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get'; 2 | export * from './get-items'; 3 | export * from './reset-items'; 4 | export * from './restore'; 5 | -------------------------------------------------------------------------------- /packages/openapi/src/types.ts: -------------------------------------------------------------------------------- 1 | import { z } from './zod'; 2 | 3 | export const getListSchemaVo = (item: z.ZodType) => { 4 | return z.object({ 5 | total: z.number(), 6 | list: z.array(item), 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/openapi/src/undo-redo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './redo'; 2 | export * from './undo'; 3 | -------------------------------------------------------------------------------- /packages/openapi/src/usage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-space-usage'; 2 | export * from './get-instance-usage'; 3 | export * from './get-base-usage'; 4 | -------------------------------------------------------------------------------- /packages/openapi/src/user/index.ts: -------------------------------------------------------------------------------- 1 | export * from './update-name'; 2 | export * from './update-avatar'; 3 | export * from './update-notify-meta'; 4 | export * from './last-visit'; 5 | -------------------------------------------------------------------------------- /packages/openapi/src/user/last-visit/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get'; 2 | export * from './update'; 3 | export * from './getMap'; 4 | export * from './list-base'; 5 | -------------------------------------------------------------------------------- /packages/openapi/src/zod.ts: -------------------------------------------------------------------------------- 1 | import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi'; 2 | import { z } from 'zod'; 3 | 4 | extendZodWithOpenApi(z); 5 | 6 | export { z }; 7 | -------------------------------------------------------------------------------- /packages/openapi/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "rootDir": "src", 6 | "paths": {}, 7 | "types": ["@ai-sdk/ui-utils"] 8 | }, 9 | "exclude": ["**/node_modules", "**/.*/", "**/*spec.ts", "./dist", "./coverage"], 10 | "include": ["src"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/openapi/vitest.setup.js: -------------------------------------------------------------------------------- 1 | const { extendZodWithOpenApi } = require('@asteasolutions/zod-to-openapi'); 2 | const { z } = require('zod'); 3 | 4 | extendZodWithOpenApi(z); 5 | -------------------------------------------------------------------------------- /packages/sdk/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # build 4 | /dist 5 | 6 | # dependencies 7 | node_modules 8 | 9 | # testing 10 | /coverage 11 | 12 | # misc 13 | .DS_Store 14 | *.pem 15 | -------------------------------------------------------------------------------- /packages/sdk/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/sdk/config/tests/setupVitest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | -------------------------------------------------------------------------------- /packages/sdk/plate-components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://platejs.org/schema.json", 3 | "aliases": { 4 | "components": "src/components/comment/comment-editor" 5 | }, 6 | "rsc": false, 7 | "style": "default", 8 | "tailwind": { 9 | "baseColor": "slate", 10 | "config": "tailwind.config.js", 11 | "css": "src/styles/globals.css", 12 | "cssVariables": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/sdk/src/components/base-query/editors/QueryFilter/types.ts: -------------------------------------------------------------------------------- 1 | import type { IBaseQueryFilterItem } from '@teable/openapi'; 2 | 3 | export type IBaseFilterItem = { 4 | field: IBaseQueryFilterItem['column']; 5 | operator: IBaseQueryFilterItem['operator']; 6 | value: IBaseQueryFilterItem['value']; 7 | type: IBaseQueryFilterItem['type']; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/sdk/src/components/base-query/editors/types.ts: -------------------------------------------------------------------------------- 1 | export interface IQueryEditorProps { 2 | value?: T; 3 | onChange: (value?: T) => void; 4 | } 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/base-query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './QueryBuilder'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/billing/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './usage-limit-modal'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellEditor'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value-editor/type.ts: -------------------------------------------------------------------------------- 1 | import type { Field } from '../../model'; 2 | import type { ICellEditor } from '../editor/type'; 3 | 4 | export interface ICellValueEditor extends Omit, 'value'> { 5 | wrapClassName?: string; 6 | wrapStyle?: React.CSSProperties; 7 | cellValue?: T; 8 | field: Field; 9 | recordId?: string; 10 | } 11 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-attachment/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellAttachment'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-checkbox/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellCheckbox'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-date/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellDate'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellLink'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-number/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellNumber'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-rating/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellRating'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-select/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellSelect'; 2 | export * from './SelectTag'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-text/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellText'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/cell-user/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CellUser'; 2 | export * from './UserTag'; 3 | export * from './UserAvatar'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './OverflowTooltip'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useTagVisibility'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cell-text'; 2 | export * from './cell-user'; 3 | export * from './cell-date'; 4 | export * from './cell-number'; 5 | export * from './cell-select'; 6 | export * from './cell-rating'; 7 | export * from './cell-checkbox'; 8 | export * from './cell-attachment'; 9 | export * from './CellValue'; 10 | -------------------------------------------------------------------------------- /packages/sdk/src/components/cell-value/type.ts: -------------------------------------------------------------------------------- 1 | export interface ICellValue { 2 | value?: T; 3 | className?: string; 4 | style?: React.CSSProperties; 5 | ellipsis?: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /packages/sdk/src/components/collaborator/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CollaboratorWithHoverCard'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/color/Color.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from '../../context/app/i18n'; 2 | 3 | interface IColorProps { 4 | children: (text: string, isActive: boolean) => React.ReactNode; 5 | } 6 | 7 | export const Color = (props: IColorProps) => { 8 | const { children } = props; 9 | const { t } = useTranslation(); 10 | 11 | return children(t('color.label'), false); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/sdk/src/components/color/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Color'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CommentEditor'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-list/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | interface ICommentListProps { 3 | isMe: boolean; 4 | } 5 | 6 | export const CommentListContext = createContext({ 7 | isMe: false, 8 | }); 9 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CommentList'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-list/node/block-element/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Image'; 2 | export * from './Paragraph'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-list/node/index.ts: -------------------------------------------------------------------------------- 1 | export * from './inline-element'; 2 | export * from './block-element'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-list/node/inline-element/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Link'; 2 | export * from './MentionUser'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-list/node/type.ts: -------------------------------------------------------------------------------- 1 | export interface IBaseNodeProps { 2 | className?: string; 3 | } 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-list/reaction/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Reaction'; 2 | export * from './ReactionPicker'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/comment-list/useIsMe.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { CommentListContext } from './context'; 3 | 4 | export const useIsMe = () => { 5 | const { isMe = false } = useContext(CommentListContext); 6 | return isMe; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/context.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface ICommentContext { 4 | baseId: string; 5 | recordId?: string; 6 | } 7 | 8 | export const CommentContext = React.createContext({ baseId: '' }); 9 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useRecordId'; 2 | export * from './useRecordCommentCount'; 3 | export * from './useBaseId'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/hooks/useBaseId.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { CommentContext } from '../context'; 3 | 4 | export function useBaseId() { 5 | return useContext(CommentContext).baseId; 6 | } 7 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/hooks/useRecordId.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { CommentContext } from '../context'; 3 | 4 | export const useRecordId = () => { 5 | return useContext(CommentContext).recordId; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CommentPanel'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/comment/types.ts: -------------------------------------------------------------------------------- 1 | export interface IBaseQueryParams { 2 | tableId: string; 3 | recordId: string; 4 | } 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/create-record/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CreateRecordModal'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/attachment/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export { AttachmentEditor as AttachmentEditorMain } from './Editor'; 3 | export * from './utils'; 4 | export * from './upload-attachment/uploadManage'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export { CheckboxEditor as CheckboxEditorMain } from './Editor'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/date/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export * from './EditorMain'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/formula/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CodeEditor'; 2 | export * from './FunctionGuide'; 3 | export * from './FunctionHelper'; 4 | export * from './AiPromptContainer'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/formula/extensions/autocomplete.ts: -------------------------------------------------------------------------------- 1 | import { closeBrackets } from '@codemirror/autocomplete'; 2 | import { bracketMatching } from '@codemirror/language'; 3 | 4 | export const AUTOCOMPLETE_EXTENSIONS = [bracketMatching(), closeBrackets()]; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/formula/extensions/history.ts: -------------------------------------------------------------------------------- 1 | import { history } from '@codemirror/commands'; 2 | 3 | export const HISTORY_EXTENSIONS = [history()]; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/formula/extensions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './theme'; 2 | export * from './token'; 3 | export * from './variable'; 4 | export * from './history'; 5 | export * from './autocomplete'; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/formula/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export * from './components/CodeEditor'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './attachment'; 2 | export * from './date'; 3 | export * from './select'; 4 | export * from './checkbox'; 5 | export * from './text'; 6 | export * from './long-text'; 7 | export * from './number'; 8 | export * from './formula'; 9 | export * from './rating'; 10 | export * from './link'; 11 | export * from './user'; 12 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export * from './EditorMain'; 3 | export * from './LinkCard'; 4 | export * from './LinkList'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/link/interface.ts: -------------------------------------------------------------------------------- 1 | export enum LinkListType { 2 | Selected = 'selected', 3 | Unselected = 'unselected', 4 | } 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/long-text/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/number/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export { NumberEditor as NumberEditorMain } from './Editor'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/rating/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/select/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './OptionList'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/select/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export * from './EditorMain'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/text/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export * from './utils'; 3 | export { TextEditor as TextEditorMain } from './Editor'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/user/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './Editor'; 2 | export * from './EditorMain'; 3 | export * from './UserOption'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/editor/user/types.ts: -------------------------------------------------------------------------------- 1 | export interface ICollaborator { 2 | userId: string; 3 | userName: string; 4 | email: string; 5 | avatar?: string | null; 6 | } 7 | -------------------------------------------------------------------------------- /packages/sdk/src/components/expand-record/ModalContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | interface IModalContext { 4 | ref: React.RefObject; 5 | } 6 | 7 | export const ModalContext = createContext({ ref: { current: null } }); 8 | -------------------------------------------------------------------------------- /packages/sdk/src/components/expand-record/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CopyButton'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/expand-record/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ExpandRecord'; 2 | export * from './ExpandRecorder'; 3 | export * from './type'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/expand-record/type.ts: -------------------------------------------------------------------------------- 1 | export enum ExpandRecordModel { 2 | Modal = 'modal', 3 | Drawer = 'drawer', 4 | } 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/expand-record/useModalRefElement.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ModalContext } from './ModalContext'; 3 | 4 | export const useModalRefElement = () => { 5 | const { ref } = useContext(ModalContext); 6 | return ref; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/components/field/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldSelector'; 2 | export * from './FieldCommand'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/condition/condition-item/base-component/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldValue'; 2 | export * from './FieldSelect'; 3 | export * from './OperatorSelect'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/condition/condition-item/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ConditionItem'; 2 | export * from './ConditionGroup'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/condition/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Condition'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/filter-with-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FilterWithTable'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useCrud'; 2 | export * from './useDepth'; 3 | export * from './useComponent'; 4 | export * from './useCallbackRef'; 5 | export * from './useControllableState'; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/hooks/useComponent.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { BaseFilterContext } from '../context'; 3 | 4 | export const useComponent = () => { 5 | const { component } = useContext(BaseFilterContext); 6 | 7 | return { 8 | ...component, 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/hooks/useCrud.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { BaseFilterContext } from '../context'; 3 | 4 | export const useCrud = () => { 5 | const { createCondition, onDelete, onChange, getValue } = useContext(BaseFilterContext); 6 | return { createCondition, onDelete, onChange, getValue }; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/hooks/useDepth.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { BaseFilterContext } from '../context'; 3 | 4 | export const useDepth = () => { 5 | const { maxDepth = 2 } = useContext(BaseFilterContext); 6 | return maxDepth; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BaseFilter'; 2 | export * from './view-filter'; 3 | export * from './filter-with-table'; 4 | export * from './types'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/component/base/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BaseSingleSelect'; 2 | export * from './BaseMultipleSelect'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/component/filter-link/constant.ts: -------------------------------------------------------------------------------- 1 | export const INPUT_OPERATORS = ['contains', 'doesNotContain']; 2 | export const SINGLE_SELECT_OPERATORS = ['is', 'isNot']; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/component/filter-link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FilterLink'; 2 | export * from './FilterLinkSelect'; 3 | export * from './StandDefaultList'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/component/filter-link/storage.ts: -------------------------------------------------------------------------------- 1 | import { LRUCache } from 'lru-cache'; 2 | 3 | // key is tableId-recordId, value is record name 4 | export const StorageLinkSelected = new LRUCache({ 5 | max: 30, 6 | }); 7 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/component/filterDatePicker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FilterDatePicker'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/custom-component/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldSelect'; 2 | export * from './FieldValue'; 3 | export * from './OperatorSelect'; 4 | export * from './BaseFieldValue'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useOperators'; 2 | export * from './useFilterNode'; 3 | export * from './useViewFilterLinkContext'; 4 | export * from './useDateI18nMap'; 5 | export * from './useOperatorI18nMap'; 6 | export * from './useViewFilterContext'; 7 | export * from './useFieldFilterLinkContext'; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/hooks/useFields.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ViewFilterContext } from '../context'; 3 | 4 | export const useFields = () => { 5 | const { fields } = useContext(ViewFilterContext); 6 | 7 | return fields; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/hooks/useViewFilterContext.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ViewFilterContext } from '../context'; 3 | 4 | export const useViewFilterContext = () => { 5 | const { viewFilterLinkContext } = useContext(ViewFilterContext); 6 | 7 | return viewFilterLinkContext; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './constant'; 3 | export * from './ViewFilter'; 4 | export * from './BaseViewFilter'; 5 | export * from './custom-component'; 6 | export * from './types'; 7 | -------------------------------------------------------------------------------- /packages/sdk/src/components/filter/view-filter/type-guard.ts: -------------------------------------------------------------------------------- 1 | import type { IFilterItem, IFilterSet } from '@teable/core'; 2 | 3 | function isFilterItem(item: unknown): item is IFilterItem { 4 | return !Array.isArray((item as IFilterSet)?.filterSet); 5 | } 6 | 7 | export { isFilterItem }; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid-enhancements/components/grid-tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export * from './grid-tooltip'; 2 | export * from './GridTooltip'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid-enhancements/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './grid-tooltip'; 2 | export * from './row-counter'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid-enhancements/components/row-counter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RowCounter'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid-enhancements/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GridDateEditor'; 2 | export * from './GridSelectEditor'; 3 | export * from './GridLinkEditor'; 4 | export * from './GridNumberEditor'; 5 | export * from './GridAttachmentEditor'; 6 | export * from './GridFilePreviewer'; 7 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid-enhancements/index.ts: -------------------------------------------------------------------------------- 1 | export * from './editor'; 2 | export * from './hooks'; 3 | export * from './store'; 4 | export * from './utils'; 5 | export * from './components'; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid-enhancements/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useGridCollapsedGroupStore'; 2 | export * from './useGridViewStore'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid-enhancements/utils/generate-id.ts: -------------------------------------------------------------------------------- 1 | export const generateLocalId = (tableId?: string, viewId?: string) => `${tableId}-${viewId}`; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid-enhancements/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './generate-id'; 2 | export * from './image-handler'; 3 | export * from './group-value'; 4 | export * from './persist-editing'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/components/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './EditorContainer'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './editor'; 2 | export * from './LoadingIndicator'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/configs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './grid'; 2 | export * from './gridTheme'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Grid'; 2 | export * from './interface'; 3 | export * from './managers'; 4 | export * from './components'; 5 | export * from './utils'; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/managers/coordinate-manager/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CoordinateManager'; 2 | export * from './interface'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/managers/image-manager/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ImageManager'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/managers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './image-manager'; 2 | export * from './sprite-manager'; 3 | export * from './selection-manager'; 4 | export * from './coordinate-manager'; 5 | export * from './performance-tracker'; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/managers/performance-tracker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PerformanceTracker'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/managers/selection-manager/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CombinedSelection'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/managers/sprite-manager/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SpriteManager'; 2 | export * from './sprites'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/renderers/base-renderer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './interface'; 2 | export * from './baseRenderer'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/renderers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cell-renderer'; 2 | export * from './base-renderer'; 3 | export * from './layout-renderer'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/renderers/layout-renderer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './layoutRenderer'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/utils/element.ts: -------------------------------------------------------------------------------- 1 | export const isAncestorOfActiveElement = (id: string): boolean => { 2 | let activeElement = document.activeElement; 3 | 4 | while (activeElement) { 5 | if (activeElement.id === id) { 6 | return true; 7 | } 8 | activeElement = activeElement.parentElement; 9 | } 10 | 11 | return false; 12 | }; 13 | -------------------------------------------------------------------------------- /packages/sdk/src/components/grid/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils'; 2 | export * from './range'; 3 | export * from './group'; 4 | export * from './region'; 5 | export * from './hotkey'; 6 | export * from './measure'; 7 | export * from './element'; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/components/group/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Group'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/hide-fields/index.ts: -------------------------------------------------------------------------------- 1 | export * from './HideFields'; 2 | export * from './VisibleFields'; 3 | export * from './HideFieldsBase'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useAttachmentPreviewI18Map'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/markdown-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './MarkDownEditor'; 2 | export * from './MarkDownPreview'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/plate/ui/hooks/useMounted.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export function useMounted() { 4 | const [mounted, setMounted] = React.useState(false); 5 | 6 | React.useEffect(() => { 7 | setMounted(true); 8 | }, []); 9 | 10 | return mounted; 11 | } 12 | -------------------------------------------------------------------------------- /packages/sdk/src/components/plate/ui/paragraph-element.tsx: -------------------------------------------------------------------------------- 1 | import { withCn } from '@udecode/cn'; 2 | import { PlateElement } from '@udecode/plate/react'; 3 | 4 | export const ParagraphElement = withCn(PlateElement, 'm-0 px-0 py-0 leading-6'); 5 | -------------------------------------------------------------------------------- /packages/sdk/src/components/record-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RecordItem'; 2 | export * from './RecordList'; 3 | export * from './RecordSearch'; 4 | export * from './ApiRecordList'; 5 | export * from './SocketRecordList'; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/components/row-height/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RowHeight'; 2 | export * from './RowHeightBase'; 3 | export * from './useRowHeightNode'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/search/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SearchInput'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/select-field-dialog/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldCreateOrSelectModal'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/components/sort/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Sort'; 2 | export * from './SortBase'; 3 | export * from './useSortNode'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/components/table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InfiniteTable'; 2 | export * from './VirtualizedInfiniteTable'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/components/view/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ViewSelect'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './local-storage-keys'; 2 | export * from './react-query-keys'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/context/aggregation/AggregationContext.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import type { IAggregationVo } from '@teable/openapi'; 3 | import React from 'react'; 4 | 5 | export const AggregationContext = React.createContext(null); 6 | -------------------------------------------------------------------------------- /packages/sdk/src/context/aggregation/CalendarDailyCollectionContext.ts: -------------------------------------------------------------------------------- 1 | import type { ICalendarDailyCollectionVo } from '@teable/openapi'; 2 | import React from 'react'; 3 | 4 | export const CalendarDailyCollectionContext = 5 | React.createContext(null); 6 | -------------------------------------------------------------------------------- /packages/sdk/src/context/aggregation/GroupPointContext.ts: -------------------------------------------------------------------------------- 1 | import type { IGroupPointsVo } from '@teable/openapi'; 2 | import React from 'react'; 3 | 4 | export const GroupPointContext = React.createContext(null); 5 | -------------------------------------------------------------------------------- /packages/sdk/src/context/aggregation/RowCountContext.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import React from 'react'; 3 | 4 | export const RowCountContext = React.createContext(null); 5 | -------------------------------------------------------------------------------- /packages/sdk/src/context/aggregation/TaskStatusCollectionContext.ts: -------------------------------------------------------------------------------- 1 | import type { ITaskStatusCollectionVo } from '@teable/openapi'; 2 | import React from 'react'; 3 | 4 | export const TaskStatusCollectionContext = React.createContext( 5 | null 6 | ); 7 | -------------------------------------------------------------------------------- /packages/sdk/src/context/anchor/AnchorContext.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // eslint-disable-next-line @typescript-eslint/naming-convention 4 | export const AnchorContext = React.createContext<{ 5 | baseId?: string; 6 | tableId?: string; 7 | viewId?: string; 8 | }>({}); 9 | -------------------------------------------------------------------------------- /packages/sdk/src/context/anchor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AnchorContext'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/context/app/ConnectionContext.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* eslint-disable @typescript-eslint/no-non-null-assertion */ 3 | import React from 'react'; 4 | import type { Connection } from 'sharedb/lib/client'; 5 | 6 | export const ConnectionContext = React.createContext<{ 7 | connection?: Connection; 8 | connected: boolean; 9 | }>(null!); 10 | -------------------------------------------------------------------------------- /packages/sdk/src/context/app/i18n/const.ts: -------------------------------------------------------------------------------- 1 | import defaultLocale from '@teable/common-i18n/src/locales/en/sdk.json'; 2 | export { defaultLocale }; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/context/app/i18n/index.ts: -------------------------------------------------------------------------------- 1 | export * from './const'; 2 | export * from './useTranslation'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/context/app/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AppContext'; 2 | export * from './AppProvider'; 3 | export * from './queryClient'; 4 | export * from './ConnectionProvider'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/context/base/BaseContext.ts: -------------------------------------------------------------------------------- 1 | import type { IGetBasePermissionVo } from '@teable/openapi'; 2 | import { createContext } from 'react'; 3 | import type { Base } from '../../model'; 4 | 5 | export const BaseContext = createContext<{ 6 | base?: Base; 7 | permission?: IGetBasePermissionVo; 8 | }>({}); 9 | -------------------------------------------------------------------------------- /packages/sdk/src/context/base/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BaseContext'; 2 | export * from './BaseProvider'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/context/field/FieldContext.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { IFieldInstance } from '../../model'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const FieldContext = React.createContext<{ 6 | fields: IFieldInstance[]; 7 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 8 | }>(null!); 9 | -------------------------------------------------------------------------------- /packages/sdk/src/context/field/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FieldContext'; 2 | export * from './FieldProvider'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/context/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app'; 2 | export * from './anchor'; 3 | export * from './field'; 4 | export * from './record'; 5 | export * from './table'; 6 | export * from './view'; 7 | export * from './aggregation'; 8 | export * from './session'; 9 | export * from './base'; 10 | export * from './notification'; 11 | export * from './table-permission'; 12 | -------------------------------------------------------------------------------- /packages/sdk/src/context/notification/NotificationContext.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import type { INotificationBuffer } from '@teable/core'; 3 | import React from 'react'; 4 | 5 | export const NotificationContext = React.createContext(null); 6 | -------------------------------------------------------------------------------- /packages/sdk/src/context/notification/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NotificationContext'; 2 | export * from './NotificationProvider'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/context/query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SearchContext'; 2 | export * from './SearchProvider'; 3 | export * from './LinkFilterContext'; 4 | -------------------------------------------------------------------------------- /packages/sdk/src/context/record/RecordContext.ts: -------------------------------------------------------------------------------- 1 | import type { IRecord } from '@teable/core'; 2 | import React from 'react'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const RecordContext = React.createContext<{ 6 | serverRecords?: IRecord[]; 7 | serverRecord?: IRecord; 8 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 9 | }>(null!); 10 | -------------------------------------------------------------------------------- /packages/sdk/src/context/record/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RecordContext'; 2 | export * from './RecordProvider'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/context/session/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SessionContext'; 2 | export * from './SessionProvider'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/context/table-permission/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TablePermissionContext'; 2 | export * from './TablePermissionProvider'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/context/table/ShareViewContext.tsx: -------------------------------------------------------------------------------- 1 | import type { ShareViewGetVo } from '@teable/openapi'; 2 | import React from 'react'; 3 | 4 | export const ShareViewContext = React.createContext({} as ShareViewGetVo); 5 | -------------------------------------------------------------------------------- /packages/sdk/src/context/table/TableContext.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { Table } from '../../model'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const TableContext = React.createContext<{ 6 | tables: Table[]; 7 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 8 | }>(null!); 9 | -------------------------------------------------------------------------------- /packages/sdk/src/context/table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableContext'; 2 | export * from './TableProvider'; 3 | export * from './StandaloneViewProvider'; 4 | export * from './ShareViewProxy'; 5 | export * from './LinkViewProvider'; 6 | export * from './ShareViewContext'; 7 | -------------------------------------------------------------------------------- /packages/sdk/src/context/use-instances/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useInstances'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/context/view/ViewContext.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* eslint-disable @typescript-eslint/no-non-null-assertion */ 3 | import React from 'react'; 4 | import type { IViewInstance } from '../../model'; 5 | 6 | export const ViewContext = React.createContext<{ 7 | views: IViewInstance[]; 8 | }>(null!); 9 | -------------------------------------------------------------------------------- /packages/sdk/src/context/view/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ViewContext'; 2 | export * from './ViewProvider'; 3 | export * from './PersonalViewProxy'; 4 | export * from './PersonalViewProvider'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/context/view/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './usePersonalViewStore'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-aggregation.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { AggregationContext } from '../context'; 3 | 4 | export const useAggregation = () => { 5 | return useContext(AggregationContext); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-base-id.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { AnchorContext } from '../context'; 3 | 4 | export function useBaseId() { 5 | const { baseId } = useContext(AnchorContext); 6 | return baseId; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-base-permission.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { BaseContext } from '../context'; 3 | 4 | export const useBasePermission = () => { 5 | const { permission } = useContext(BaseContext); 6 | 7 | return permission; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-base.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { BaseContext } from '../context/base/BaseContext'; 3 | 4 | export function useBase() { 5 | const { base } = useContext(BaseContext); 6 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 7 | return base!; 8 | } 9 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-connection.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ConnectionContext } from '../context/app/ConnectionContext'; 3 | 4 | export function useConnection() { 5 | const { connection, connected } = useContext(ConnectionContext); 6 | return { connection, connected }; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-field-permission.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { TablePermissionContext } from '../context/table-permission'; 3 | 4 | export type IUseFieldPermissionAction = keyof ReturnType; 5 | 6 | export const useFieldPermission = () => { 7 | const { field } = useContext(TablePermissionContext) ?? {}; 8 | return field; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-field.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { FieldContext } from '../context'; 3 | 4 | export function useField(fieldId?: string) { 5 | const { fields } = useContext(FieldContext); 6 | return fields.find((field) => field.id === fieldId); 7 | } 8 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-group-point.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { GroupPointContext } from '../context'; 3 | 4 | export const useGroupPoint = () => { 5 | return useContext(GroupPointContext); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-is-hydrated.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | // Wait till NextJS rehydration completes, then show the app 4 | // otherwise there my be throw an error 5 | export function useIsHydrated() { 6 | const [isHydrated, setIsHydrated] = useState(false); 7 | useEffect(() => { 8 | setIsHydrated(true); 9 | }, []); 10 | return isHydrated; 11 | } 12 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-is-mobile.ts: -------------------------------------------------------------------------------- 1 | import { useMedia } from 'react-use'; 2 | 3 | export const useIsMobile = () => { 4 | return useMedia('(max-width: 640px)'); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-notification.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { NotificationContext } from '../context'; 3 | 4 | export const useNotification = () => { 5 | return useContext(NotificationContext); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-row-count.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { RowCountContext } from '../context'; 3 | 4 | export function useRowCount() { 5 | return useContext(RowCountContext); 6 | } 7 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-ssr-record.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { RecordContext } from '../context'; 3 | 4 | export function useSSRRecord() { 5 | const { serverRecord } = useContext(RecordContext); 6 | return serverRecord; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-ssr-records.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { RecordContext } from '../context'; 3 | 4 | export function useSSRRecords() { 5 | const { serverRecords } = useContext(RecordContext); 6 | return serverRecords; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-table-id.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { AnchorContext } from '../context'; 3 | 4 | export function useTableId() { 5 | const { tableId } = useContext(AnchorContext); 6 | return tableId; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-table.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { AnchorContext, TableContext } from '../context'; 3 | 4 | export function useTable() { 5 | const { tableId } = useContext(AnchorContext); 6 | const { tables } = useContext(TableContext); 7 | 8 | return tables.find((table) => table.id === tableId); 9 | } 10 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-tables.ts: -------------------------------------------------------------------------------- 1 | import { orderBy } from 'lodash'; 2 | import { useContext, useMemo } from 'react'; 3 | import { TableContext } from '../context/table'; 4 | 5 | export function useTables() { 6 | const tableContext = useContext(TableContext); 7 | return useMemo(() => orderBy(tableContext?.tables, ['order']), [tableContext?.tables]); 8 | } 9 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-view-id.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { AnchorContext } from '../context'; 3 | 4 | // use current active view id 5 | export function useViewId() { 6 | const { viewId } = useContext(AnchorContext); 7 | return viewId; 8 | } 9 | -------------------------------------------------------------------------------- /packages/sdk/src/hooks/use-views.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { ViewContext } from '../context/view'; 3 | 4 | export function useViews() { 5 | const viewCtx = useContext(ViewContext); 6 | return viewCtx?.views; 7 | } 8 | -------------------------------------------------------------------------------- /packages/sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | export * from './config'; 3 | export * from './context'; 4 | export * from './hooks'; 5 | export * from './model'; 6 | export * from './utils'; 7 | export * from './store'; 8 | export * from './plugin-bridge'; 9 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/attachment.field.ts: -------------------------------------------------------------------------------- 1 | import { AttachmentFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class AttachmentField extends Mixin(AttachmentFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/auto-number.field.ts: -------------------------------------------------------------------------------- 1 | import { AutoNumberFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class AutoNumberField extends Mixin(AutoNumberFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/checkbox.field.ts: -------------------------------------------------------------------------------- 1 | import { CheckboxFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class CheckboxField extends Mixin(CheckboxFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/created-by.field.ts: -------------------------------------------------------------------------------- 1 | import { CreatedByFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class CreatedByField extends Mixin(CreatedByFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/created-time.field.ts: -------------------------------------------------------------------------------- 1 | import { CreatedTimeFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class CreatedTimeField extends Mixin(CreatedTimeFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/date.field.ts: -------------------------------------------------------------------------------- 1 | import { DateFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class DateField extends Mixin(DateFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/formula.field.ts: -------------------------------------------------------------------------------- 1 | import { FormulaFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class FormulaField extends Mixin(FormulaFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/last-modified-by.field.ts: -------------------------------------------------------------------------------- 1 | import { LastModifiedByFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class LastModifiedByField extends Mixin(LastModifiedByFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/last-modified-time.field.ts: -------------------------------------------------------------------------------- 1 | import { LastModifiedTimeFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class LastModifiedTimeField extends Mixin(LastModifiedTimeFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/link.field.ts: -------------------------------------------------------------------------------- 1 | import { LinkFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class LinkField extends Mixin(LinkFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/long-text.field.ts: -------------------------------------------------------------------------------- 1 | import { LongTextFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class LongTextField extends Mixin(LongTextFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/multiple-select.field.ts: -------------------------------------------------------------------------------- 1 | import { MultipleSelectFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | import { SelectFieldSdk } from './mixin/select.field'; 5 | 6 | export class MultipleSelectField extends Mixin(SelectFieldSdk, MultipleSelectFieldCore, Field) {} 7 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/number.field.ts: -------------------------------------------------------------------------------- 1 | import { NumberFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class NumberField extends Mixin(NumberFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/rating.field.ts: -------------------------------------------------------------------------------- 1 | import { RatingFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class RatingField extends Mixin(RatingFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/rollup.field.ts: -------------------------------------------------------------------------------- 1 | import { RollupFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class RollupField extends Mixin(RollupFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/single-line-text.field.ts: -------------------------------------------------------------------------------- 1 | import { SingleLineTextFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class SingleLineTextField extends Mixin(SingleLineTextFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/single-select.field.ts: -------------------------------------------------------------------------------- 1 | import { SingleSelectFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | import { SelectFieldSdk } from './mixin/select.field'; 5 | 6 | export class SingleSelectField extends Mixin(SelectFieldSdk, SingleSelectFieldCore, Field) {} 7 | -------------------------------------------------------------------------------- /packages/sdk/src/model/field/user.field.ts: -------------------------------------------------------------------------------- 1 | import { UserFieldCore } from '@teable/core'; 2 | import { Mixin } from 'ts-mixer'; 3 | import { Field } from './field'; 4 | 5 | export class UserField extends Mixin(UserFieldCore, Field) {} 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './table'; 2 | export * from './record'; 3 | export * from './field'; 4 | export * from './view'; 5 | export * from './base'; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/model/record/index.ts: -------------------------------------------------------------------------------- 1 | export * from './record'; 2 | export * from './factory'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/model/table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './factory'; 2 | export * from './table'; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/model/view/index.ts: -------------------------------------------------------------------------------- 1 | export * from './factory'; 2 | export * from './grid.view'; 3 | export * from './kanban.view'; 4 | export * from './gallery.view'; 5 | export * from './calendar.view'; 6 | export * from './form.view'; 7 | export * from './view'; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/plugin-bridge/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-bridge'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/plugin-bridge/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './bridge'; 3 | export * from './utils'; 4 | export * from './hooks'; 5 | -------------------------------------------------------------------------------- /packages/sdk/src/plugin-bridge/utils.ts: -------------------------------------------------------------------------------- 1 | export const isIframe = () => window !== window.parent; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-interaction-mode-store'; 2 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/copy.ts: -------------------------------------------------------------------------------- 1 | import copy from 'copy-to-clipboard'; 2 | 3 | // you can only use this in sync keyboard or mouse click event 4 | export const syncCopy = async (text: string) => { 5 | copy(text); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './statistic'; 2 | export * from './order'; 3 | export * from './sprite'; 4 | export * from './fieldType'; 5 | export * from './urlParams'; 6 | export * from './copy'; 7 | export * from './filterWithDefaultValue'; 8 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/urlParams.ts: -------------------------------------------------------------------------------- 1 | export function addQueryParamsToWebSocketUrl(url: string, params: Record) { 2 | const urlObj = new URL(url); 3 | 4 | Object.keys(params).forEach((key) => { 5 | urlObj.searchParams.set(key, params[key]); 6 | }); 7 | 8 | return urlObj.toString(); 9 | } 10 | -------------------------------------------------------------------------------- /packages/sdk/ui.config.d.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss'; 2 | 3 | declare const configure: (config: Config) => Config; 4 | 5 | export default configure; 6 | -------------------------------------------------------------------------------- /packages/sdk/ui.config.js: -------------------------------------------------------------------------------- 1 | const deepMerge = require('deepmerge'); 2 | 3 | const uiConfig = require('./tailwind.config'); 4 | 5 | function wrapper(tailwindConfig) { 6 | return deepMerge({ ...tailwindConfig }, uiConfig); 7 | } 8 | 9 | module.exports = wrapper; 10 | -------------------------------------------------------------------------------- /packages/ui-lib/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # build 4 | /dist 5 | /build 6 | /storybook-static 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # testing 12 | /coverage 13 | 14 | # misc 15 | .DS_Store 16 | *.pem 17 | -------------------------------------------------------------------------------- /packages/ui-lib/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/ui-lib/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import '../src/_stories/tailwind.css'; 2 | export const parameters = { 3 | actions: { argTypesRegex: '^on[A-Z].*' }, 4 | controls: { 5 | matchers: { 6 | color: /(background|color)$/i, 7 | date: /Date$/, 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /packages/ui-lib/postcss.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Notably for storybook & independent releases 3 | * @link https://storybook.js.org/addons/@storybook/addon-postcss 4 | */ 5 | module.exports = { 6 | plugins: { 7 | tailwindcss: {}, 8 | autoprefixer: {}, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /packages/ui-lib/src/_stories/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /packages/ui-lib/src/base/dialog/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ConfirmDialog'; 2 | -------------------------------------------------------------------------------- /packages/ui-lib/src/base/file/index.ts: -------------------------------------------------------------------------------- 1 | export * from './preview'; 2 | -------------------------------------------------------------------------------- /packages/ui-lib/src/base/file/preview/genFileId.ts: -------------------------------------------------------------------------------- 1 | let uuid = 0; 2 | 3 | export const genFileId = () => { 4 | uuid += 1; 5 | return uuid; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/ui-lib/src/base/file/preview/image/ImagePreview.tsx: -------------------------------------------------------------------------------- 1 | import type { IFileItemInner } from '../FilePreviewContext'; 2 | 3 | interface IImagePreviewProps extends IFileItemInner {} 4 | 5 | export const ImagePreview = (props: IImagePreviewProps) => { 6 | const { src, name } = props; 7 | return {name}; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/ui-lib/src/base/file/preview/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './FilePreviewProvider'; 2 | export * from './FilePreviewItem'; 3 | export * from './FilePreviewDialog'; 4 | export * from './getFileIcon'; 5 | export * from './utils'; 6 | -------------------------------------------------------------------------------- /packages/ui-lib/src/base/file/preview/pdf/utils.ts: -------------------------------------------------------------------------------- 1 | import { getBlobFromUrl } from '../office/utils'; 2 | 3 | export const getBlobUrlFromUrl = async (url: string) => { 4 | const blob = await getBlobFromUrl(url); 5 | return URL.createObjectURL(blob); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/ui-lib/src/base/index.ts: -------------------------------------------------------------------------------- 1 | export * from './card/BasicCard'; 2 | export * from './spin/Spin'; 3 | export * from './selector/Selector'; 4 | export * from './file'; 5 | export * from './dialog'; 6 | export * from './dnd-kit'; 7 | export * from './Error'; 8 | -------------------------------------------------------------------------------- /packages/ui-lib/src/icons/social/README.md: -------------------------------------------------------------------------------- 1 | ## Credits 2 | 3 | - **github.svg** by https://www.iconfinder.com/Adi_Sinchetru from https://www.iconfinder.com/icons/1390302/github_icon 4 | -------------------------------------------------------------------------------- /packages/ui-lib/src/index.ts: -------------------------------------------------------------------------------- 1 | export { Message } from './message'; 2 | export { AsyncMessage } from './async-message'; 3 | export * from './shadcn'; 4 | export * from './base'; 5 | -------------------------------------------------------------------------------- /packages/ui-lib/src/message.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react'; 2 | 3 | type Props = { 4 | message: string; 5 | children?: never; 6 | }; 7 | 8 | export const Message: FC = ({ message }) => {message}; 9 | -------------------------------------------------------------------------------- /packages/ui-lib/src/shadcn/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '../utils'; 2 | 3 | function Skeleton({ className, ...props }: React.HTMLAttributes) { 4 | return

; 5 | } 6 | 7 | export { Skeleton }; 8 | -------------------------------------------------------------------------------- /packages/ui-lib/src/shadcn/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/ui-lib/ui.config.d.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss'; 2 | 3 | declare const configure: (config: Config) => Config; 4 | 5 | export default configure; 6 | -------------------------------------------------------------------------------- /packages/ui-lib/ui.config.js: -------------------------------------------------------------------------------- 1 | const deepMerge = require('deepmerge'); 2 | 3 | const uiConfig = require('./tailwind.config'); 4 | 5 | function wrapper(tailwindConfig) { 6 | return deepMerge({ ...tailwindConfig }, uiConfig); 7 | } 8 | 9 | module.exports = wrapper; 10 | -------------------------------------------------------------------------------- /plugins/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /plugins/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. 6 | -------------------------------------------------------------------------------- /plugins/postcss.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | plugins: { 5 | tailwindcss: { 6 | config: path.join(__dirname, 'tailwind.config.ts'), 7 | }, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /plugins/src/app/chart/components/chart/chart-show/types.ts: -------------------------------------------------------------------------------- 1 | export interface IChartBase { 2 | rows: Record[]; 3 | } 4 | -------------------------------------------------------------------------------- /plugins/src/app/chart/components/chart/chart-show/utils.ts: -------------------------------------------------------------------------------- 1 | import { COLOR_MAXIMUM } from '../../../constant'; 2 | 3 | export const getColor = (index: number) => { 4 | return `hsl(var(--chart-${(index % COLOR_MAXIMUM) + 1}))`; 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/src/app/chart/constant.ts: -------------------------------------------------------------------------------- 1 | export const COLOR_MAXIMUM = 30; 2 | -------------------------------------------------------------------------------- /plugins/src/app/chart/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/plugins/src/app/chart/favicon.ico -------------------------------------------------------------------------------- /plugins/src/app/chart/hooks/useUIConfig.ts: -------------------------------------------------------------------------------- 1 | import { useContext, useMemo } from 'react'; 2 | import { ChartContext } from '../components/ChartProvider'; 3 | 4 | export const useUIConfig = () => { 5 | const { uiConfig } = useContext(ChartContext); 6 | return useMemo(() => uiConfig ?? {}, [uiConfig]); 7 | }; 8 | -------------------------------------------------------------------------------- /plugins/src/app/sheet-form-view/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/plugins/src/app/sheet-form-view/favicon.ico -------------------------------------------------------------------------------- /plugins/src/components/types.ts: -------------------------------------------------------------------------------- 1 | export enum PageType { 2 | Chart = 'chart', 3 | View = 'view', 4 | } 5 | -------------------------------------------------------------------------------- /plugins/src/hooks/useEnv.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { EvnContext } from '../components/EnvProvider'; 3 | 4 | export const useEnv = () => { 5 | return useContext(EvnContext); 6 | }; 7 | -------------------------------------------------------------------------------- /plugins/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { PluginPosition } from '@teable/openapi'; 2 | 3 | export interface IPageParams { 4 | lang: string; 5 | baseId: string; 6 | pluginInstallId: string; 7 | positionId: string; 8 | positionType: PluginPosition; 9 | pluginId: string; 10 | theme: string; 11 | tableId?: string; 12 | shareId?: string; 13 | } 14 | -------------------------------------------------------------------------------- /plugins/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import uiConfig from '@teable/sdk/ui.config'; 2 | import type { Config } from 'tailwindcss'; 3 | 4 | const config: Config = uiConfig({ 5 | content: [ 6 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 7 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 8 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 9 | ], 10 | plugins: [], 11 | }); 12 | export default config; 13 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'apps/*' 3 | - 'packages/*' 4 | - 'plugins' 5 | - '!apps/electron' 6 | -------------------------------------------------------------------------------- /static/assets/example/Boy1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/example/Boy1.png -------------------------------------------------------------------------------- /static/assets/example/Boy3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/example/Boy3.png -------------------------------------------------------------------------------- /static/assets/example/Girl1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/example/Girl1.png -------------------------------------------------------------------------------- /static/assets/example/Girl2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/example/Girl2.png -------------------------------------------------------------------------------- /static/assets/example/Girl3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/example/Girl3.png -------------------------------------------------------------------------------- /static/assets/images/comments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/comments.png -------------------------------------------------------------------------------- /static/assets/images/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/dashboard.png -------------------------------------------------------------------------------- /static/assets/images/record-history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/record-history.png -------------------------------------------------------------------------------- /static/assets/images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/search.png -------------------------------------------------------------------------------- /static/assets/images/teable-interface-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/teable-interface-dark.png -------------------------------------------------------------------------------- /static/assets/images/teable-interface-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/teable-interface-light.png -------------------------------------------------------------------------------- /static/assets/images/teable-vertical-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/teable-vertical-dark.png -------------------------------------------------------------------------------- /static/assets/images/teable-vertical-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/teable-vertical-light.png -------------------------------------------------------------------------------- /static/assets/images/view-calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/view-calendar.png -------------------------------------------------------------------------------- /static/assets/images/view-form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/view-form.png -------------------------------------------------------------------------------- /static/assets/images/view-gallery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/view-gallery.png -------------------------------------------------------------------------------- /static/assets/images/view-grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/view-grid.png -------------------------------------------------------------------------------- /static/assets/images/view-kanban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teableio/teable/6ec693d33a61cc6ec51400b0e6f2cb10e47e3bce/static/assets/images/view-kanban.png --------------------------------------------------------------------------------