Merge branch 'main' into feat/last-publish-name
This commit is contained in:
commit
c705d500ce
|
|
@ -44,20 +44,23 @@ jobs:
|
|||
- name: Build Docker Images
|
||||
run: |
|
||||
export DOCKER_DEFAULT_PLATFORM=linux/amd64
|
||||
docker compose build appflowy_cloud appflowy_history appflowy_worker
|
||||
docker compose build appflowy_cloud appflowy_history appflowy_worker admin_frontend
|
||||
|
||||
- name: Push docker images to docker hub
|
||||
run: |
|
||||
docker tag appflowyinc/appflowy_cloud appflowyinc/appflowy_cloud:${GITHUB_SHA}
|
||||
docker tag appflowyinc/appflowy_history appflowyinc/appflowy_history:${GITHUB_SHA}
|
||||
docker tag appflowyinc/appflowy_worker appflowyinc/appflowy_worker:${GITHUB_SHA}
|
||||
docker tag appflowyinc/admin_frontend appflowyinc/admin_frontend:${GITHUB_SHA}
|
||||
echo ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | docker login --username appflowyinc --password-stdin
|
||||
docker push appflowyinc/appflowy_cloud:${GITHUB_SHA}
|
||||
docker push appflowyinc/appflowy_history:${GITHUB_SHA}
|
||||
docker push appflowyinc/appflowy_worker:${GITHUB_SHA}
|
||||
docker push appflowyinc/admin_frontend:${GITHUB_SHA}
|
||||
APPFLOWY_HISTORY_VERSION=${GITHUB_SHA}
|
||||
APPFLOWY_WORKER_VERSION=${GITHUB_SHA}
|
||||
APPFLOWY_CLOUD_VERSION=${GITHUB_SHA}
|
||||
APPFLOWY_ADMIN_FRONTEND_VERSION=${GITHUB_SHA}
|
||||
|
||||
test:
|
||||
name: Integration Tests
|
||||
|
|
@ -72,6 +75,8 @@ jobs:
|
|||
test_cmd: "-p appflowy-history"
|
||||
- test_service: "appflowy_worker"
|
||||
test_cmd: "-p appflowy-worker"
|
||||
- test_service: "admin_frontend"
|
||||
test_cmd: "-p admin_frontend"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
|
|
@ -122,7 +127,7 @@ jobs:
|
|||
echo "No running container found to display logs."
|
||||
fi
|
||||
|
||||
- name: install prerequisites
|
||||
- name: Install prerequisites
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install protobuf-compiler
|
||||
|
|
@ -131,7 +136,6 @@ jobs:
|
|||
run: |
|
||||
echo "Running tests for ${{ matrix.test_service }} with flags: ${{ matrix.test_cmd }}"
|
||||
RUST_LOG="info" DISABLE_CI_TEST_LOG="true" cargo test ${{ matrix.test_cmd }}
|
||||
RUST_LOG="info" DISABLE_CI_TEST_LOG="true" cargo test -p admin_frontend ${{ matrix.test_cmd }}
|
||||
|
||||
- name: Run Tests from main branch
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::http::log_request_id;
|
||||
use crate::{blocking_brotli_compress, Client};
|
||||
use app_error::AppError;
|
||||
use client_api_entity::workspace_dto::AFDatabase;
|
||||
use client_api_entity::{
|
||||
BatchQueryCollabParams, BatchQueryCollabResult, CreateCollabParams, DeleteCollabParams,
|
||||
QueryCollab, UpdateCollabWebParams,
|
||||
|
|
@ -123,6 +124,7 @@ impl Client {
|
|||
.await?
|
||||
.into_data()
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip_all, err)]
|
||||
pub async fn delete_collab(&self, params: DeleteCollabParams) -> Result<(), AppResponseError> {
|
||||
let url = format!(
|
||||
|
|
@ -138,4 +140,19 @@ impl Client {
|
|||
log_request_id(&resp);
|
||||
AppResponse::<()>::from_response(resp).await?.into_error()
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip_all, err)]
|
||||
pub async fn list_databases(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<AFDatabase>, AppResponseError> {
|
||||
let url = format!("{}/api/workspace/{}/database", self.base_url, workspace_id);
|
||||
let resp = self
|
||||
.http_client_with_auth(Method::GET, &url)
|
||||
.await?
|
||||
.send()
|
||||
.await?;
|
||||
log_request_id(&resp);
|
||||
AppResponse::from_response(resp).await?.into_data()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,23 @@ impl Client {
|
|||
AppResponse::<()>::from_response(resp).await?.into_error()
|
||||
}
|
||||
|
||||
pub async fn restore_all_workspace_page_views_from_trash(
|
||||
&self,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<(), AppResponseError> {
|
||||
let url = format!(
|
||||
"{}/api/workspace/{}/restore-all-pages-from-trash",
|
||||
self.base_url, workspace_id
|
||||
);
|
||||
let resp = self
|
||||
.http_client_with_auth(Method::POST, &url)
|
||||
.await?
|
||||
.json(&json!({}))
|
||||
.send()
|
||||
.await?;
|
||||
AppResponse::<()>::from_response(resp).await?.into_error()
|
||||
}
|
||||
|
||||
pub async fn update_workspace_page_view(
|
||||
&self,
|
||||
workspace_id: Uuid,
|
||||
|
|
|
|||
|
|
@ -280,3 +280,16 @@ pub struct PublishedView {
|
|||
pub extra: Option<serde_json::Value>,
|
||||
pub children: Vec<PublishedView>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AFDatabase {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub fields: Vec<AFDatabaseField>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct AFDatabaseField {
|
||||
pub name: String,
|
||||
pub field_type: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ use crate::biz::workspace::ops::{
|
|||
get_reactions_on_published_view, remove_comment_on_published_view, remove_reaction_on_comment,
|
||||
};
|
||||
use crate::biz::workspace::page_view::{
|
||||
create_page, get_page_view_collab, move_page_to_trash, restore_page_from_trash, update_page,
|
||||
update_page_collab_data,
|
||||
create_page, get_page_view_collab, move_page_to_trash, restore_all_pages_from_trash,
|
||||
restore_page_from_trash, update_page, update_page_collab_data,
|
||||
};
|
||||
use crate::biz::workspace::publish::get_workspace_default_publish_view_info_meta;
|
||||
use crate::domain::compression::{
|
||||
|
|
@ -143,6 +143,10 @@ pub fn workspace_scope() -> Scope {
|
|||
web::resource("/{workspace_id}/page-view/{view_id}/restore-from-trash")
|
||||
.route(web::post().to(restore_page_from_trash_handler)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/{workspace_id}/restore-all-pages-from-trash")
|
||||
.route(web::post().to(restore_all_pages_from_trash_handler)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/{workspace_id}/batch/collab")
|
||||
.route(web::post().to(batch_create_collab_handler)),
|
||||
|
|
@ -246,6 +250,7 @@ pub fn workspace_scope() -> Scope {
|
|||
// Web browser can't carry payload when using GET method, so for browser compatibility, we use POST method
|
||||
.route(web::post().to(batch_get_collab_handler)),
|
||||
)
|
||||
.service(web::resource("/{workspace_id}/database").route(web::get().to(list_database_handler)))
|
||||
}
|
||||
|
||||
pub fn collab_scope() -> Scope {
|
||||
|
|
@ -946,6 +951,23 @@ async fn restore_page_from_trash_handler(
|
|||
Ok(Json(AppResponse::Ok()))
|
||||
}
|
||||
|
||||
async fn restore_all_pages_from_trash_handler(
|
||||
user_uuid: UserUuid,
|
||||
path: web::Path<Uuid>,
|
||||
state: Data<AppState>,
|
||||
) -> Result<Json<AppResponse<()>>> {
|
||||
let uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
||||
let workspace_uuid = path.into_inner();
|
||||
restore_all_pages_from_trash(
|
||||
&state.pg_pool,
|
||||
&state.collab_access_control_storage,
|
||||
uid,
|
||||
workspace_uuid,
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(AppResponse::Ok()))
|
||||
}
|
||||
|
||||
async fn update_page_view_handler(
|
||||
user_uuid: UserUuid,
|
||||
path: web::Path<(Uuid, String)>,
|
||||
|
|
@ -1375,6 +1397,7 @@ async fn post_published_duplicate_handler(
|
|||
params.dest_view_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(AppResponse::Ok()))
|
||||
}
|
||||
|
||||
|
|
@ -1774,6 +1797,23 @@ async fn get_workspace_publish_outline_handler(
|
|||
Ok(Json(AppResponse::Ok().with_data(published_view)))
|
||||
}
|
||||
|
||||
async fn list_database_handler(
|
||||
user_uuid: UserUuid,
|
||||
workspace_id: web::Path<String>,
|
||||
state: Data<AppState>,
|
||||
) -> Result<Json<AppResponse<Vec<AFDatabase>>>> {
|
||||
let uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
||||
let workspace_id = workspace_id.into_inner();
|
||||
let dbs = biz::collab::ops::list_database(
|
||||
&state.pg_pool,
|
||||
&state.collab_access_control_storage,
|
||||
uid,
|
||||
workspace_id,
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(AppResponse::Ok().with_data(dbs)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn parser_realtime_msg(
|
||||
payload: Bytes,
|
||||
|
|
|
|||
|
|
@ -2,14 +2,23 @@ use std::sync::Arc;
|
|||
|
||||
use app_error::AppError;
|
||||
use appflowy_collaborate::collab::storage::CollabAccessControlStorage;
|
||||
use collab::preclude::Collab;
|
||||
use collab_database::database::DatabaseBody;
|
||||
use collab_database::entity::FieldType;
|
||||
use collab_database::workspace_database::NoPersistenceDatabaseCollabService;
|
||||
use collab_database::workspace_database::WorkspaceDatabaseBody;
|
||||
use collab_entity::CollabType;
|
||||
use collab_entity::EncodedCollab;
|
||||
use collab_folder::SectionItem;
|
||||
use collab_folder::{CollabOrigin, Folder};
|
||||
use database::collab::select_workspace_database_oid;
|
||||
use database::collab::{CollabStorage, GetCollabOrigin};
|
||||
use database::publish::select_published_view_ids_for_workspace;
|
||||
use database::publish::select_workspace_id_for_publish_namespace;
|
||||
use database_entity::dto::QueryCollabResult;
|
||||
use database_entity::dto::{QueryCollab, QueryCollabParams};
|
||||
use shared_entity::dto::workspace_dto::AFDatabase;
|
||||
use shared_entity::dto::workspace_dto::AFDatabaseField;
|
||||
use shared_entity::dto::workspace_dto::FavoriteFolderView;
|
||||
use shared_entity::dto::workspace_dto::RecentFolderView;
|
||||
use shared_entity::dto::workspace_dto::TrashFolderView;
|
||||
|
|
@ -348,3 +357,101 @@ pub async fn get_published_view(
|
|||
collab_folder_to_published_outline(&workspace_id.to_string(), &folder, &publish_view_ids)?;
|
||||
Ok(published_view)
|
||||
}
|
||||
|
||||
pub async fn list_database(
|
||||
pg_pool: &PgPool,
|
||||
collab_storage: &CollabAccessControlStorage,
|
||||
uid: i64,
|
||||
workspace_uuid_str: String,
|
||||
) -> Result<Vec<AFDatabase>, AppError> {
|
||||
let workspace_uuid: Uuid = workspace_uuid_str.as_str().parse()?;
|
||||
let ws_db_oid = select_workspace_database_oid(pg_pool, &workspace_uuid).await?;
|
||||
|
||||
let ec = get_latest_collab_encoded(
|
||||
collab_storage,
|
||||
GetCollabOrigin::Server,
|
||||
&workspace_uuid_str,
|
||||
&ws_db_oid,
|
||||
CollabType::WorkspaceDatabase,
|
||||
)
|
||||
.await?;
|
||||
let mut collab: Collab =
|
||||
Collab::new_with_source(CollabOrigin::Server, &ws_db_oid, ec.into(), vec![], false).map_err(
|
||||
|e| {
|
||||
AppError::Internal(anyhow::anyhow!(
|
||||
"Failed to create collab from encoded collab: {:?}",
|
||||
e
|
||||
))
|
||||
},
|
||||
)?;
|
||||
|
||||
let ws_body = WorkspaceDatabaseBody::open(&mut collab).map_err(|e| {
|
||||
AppError::Internal(anyhow::anyhow!(
|
||||
"Failed to open workspace database body: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
let db_metas = ws_body.get_all_meta(&collab.transact());
|
||||
let query_collabs: Vec<QueryCollab> = db_metas
|
||||
.into_iter()
|
||||
.map(|meta| QueryCollab {
|
||||
object_id: meta.database_id.clone(),
|
||||
collab_type: CollabType::Database,
|
||||
})
|
||||
.collect();
|
||||
let results = collab_storage
|
||||
.batch_get_collab(&uid, query_collabs, true)
|
||||
.await;
|
||||
|
||||
let txn = collab.transact();
|
||||
let mut af_databases: Vec<AFDatabase> = Vec::with_capacity(results.len());
|
||||
for (oid, result) in results {
|
||||
match result {
|
||||
QueryCollabResult::Success { encode_collab_v1 } => {
|
||||
match EncodedCollab::decode_from_bytes(&encode_collab_v1) {
|
||||
Ok(ec) => {
|
||||
match Collab::new_with_source(CollabOrigin::Server, &oid, ec.into(), vec![], false) {
|
||||
Ok(db_collab) => match DatabaseBody::from_collab(
|
||||
&db_collab,
|
||||
Arc::new(NoPersistenceDatabaseCollabService),
|
||||
None,
|
||||
) {
|
||||
Some(db_body) => match db_body.metas.get_inline_view_id(&txn) {
|
||||
Some(iid) => match db_body.views.get_view(&txn, &iid) {
|
||||
Some(iview) => {
|
||||
let name = iview.name;
|
||||
|
||||
let db_fields = db_body.fields.get_all_fields(&txn);
|
||||
let mut af_fields: Vec<AFDatabaseField> = Vec::with_capacity(db_fields.len());
|
||||
for db_field in db_fields {
|
||||
af_fields.push(AFDatabaseField {
|
||||
name: db_field.name,
|
||||
field_type: format!("{:?}", FieldType::from(db_field.field_type)),
|
||||
});
|
||||
}
|
||||
af_databases.push(AFDatabase {
|
||||
id: db_body.get_database_id(&txn),
|
||||
name,
|
||||
fields: af_fields,
|
||||
});
|
||||
},
|
||||
None => tracing::warn!("Failed to get inline view: {}", iid),
|
||||
},
|
||||
None => tracing::error!("Failed to get inline view id for database: {}", oid),
|
||||
},
|
||||
None => tracing::error!("Failed to create db_body from db_collab, oid: {}", oid),
|
||||
},
|
||||
Err(err) => tracing::error!("Failed to create db_collab: {:?}", err),
|
||||
}
|
||||
},
|
||||
Err(err) => tracing::error!("Failed to decode collab: {:?}", err),
|
||||
}
|
||||
},
|
||||
QueryCollabResult::Failed { error } => {
|
||||
tracing::warn!("Failed to get collab: {:?}", error)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(af_databases)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,6 +164,25 @@ async fn move_view_out_from_trash(
|
|||
})
|
||||
}
|
||||
|
||||
async fn move_all_views_out_from_trash(folder: &mut Folder) -> Result<FolderUpdate, AppError> {
|
||||
let encoded_update = {
|
||||
let mut txn = folder.collab.transact_mut();
|
||||
if let Some(op) = folder
|
||||
.body
|
||||
.section
|
||||
.section_op(&txn, collab_folder::Section::Trash)
|
||||
{
|
||||
op.clear(&mut txn);
|
||||
};
|
||||
txn.encode_update_v1()
|
||||
};
|
||||
|
||||
Ok(FolderUpdate {
|
||||
updated_encoded_collab: folder_to_encoded_collab(folder)?,
|
||||
encoded_updates: encoded_update,
|
||||
})
|
||||
}
|
||||
|
||||
fn folder_to_encoded_collab(folder: &Folder) -> Result<Vec<u8>, AppError> {
|
||||
let collab_type = CollabType::Folder;
|
||||
let encoded_folder_collab = folder
|
||||
|
|
@ -297,6 +316,29 @@ pub async fn restore_page_from_trash(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn restore_all_pages_from_trash(
|
||||
pg_pool: &PgPool,
|
||||
collab_storage: &CollabAccessControlStorage,
|
||||
uid: i64,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<(), AppError> {
|
||||
let collab_origin = GetCollabOrigin::User { uid };
|
||||
let mut folder =
|
||||
get_latest_collab_folder(collab_storage, collab_origin, &workspace_id.to_string()).await?;
|
||||
let folder_update = move_all_views_out_from_trash(&mut folder).await?;
|
||||
let mut transaction = pg_pool.begin().await?;
|
||||
insert_and_broadcast_workspace_folder_update(
|
||||
uid,
|
||||
workspace_id,
|
||||
folder_update,
|
||||
collab_storage,
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
transaction.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn update_page(
|
||||
pg_pool: &PgPool,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::time::Duration;
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
|
||||
use client_api::entity::{QueryCollab, QueryCollabParams};
|
||||
use client_api_test::{
|
||||
|
|
@ -146,40 +146,49 @@ async fn move_page_to_trash() {
|
|||
.into_iter()
|
||||
.find(|v| v.name == "General")
|
||||
.unwrap();
|
||||
let view_id_to_be_deleted = general_space.children[0].view_id.clone();
|
||||
let view_ids_to_be_deleted = [
|
||||
general_space.children[0].view_id.clone(),
|
||||
general_space.children[1].view_id.clone(),
|
||||
];
|
||||
app_client.open_workspace_collab(&workspace_id).await;
|
||||
app_client
|
||||
.wait_object_sync_complete(&workspace_id)
|
||||
.await
|
||||
.unwrap();
|
||||
web_client
|
||||
.api_client
|
||||
.move_workspace_page_view_to_trash(
|
||||
Uuid::parse_str(&workspace_id).unwrap(),
|
||||
view_id_to_be_deleted.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
for view_id in view_ids_to_be_deleted.iter() {
|
||||
app_client
|
||||
.api_client
|
||||
.move_workspace_page_view_to_trash(Uuid::parse_str(&workspace_id).unwrap(), view_id.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
let folder = get_latest_folder(&app_client, &workspace_id).await;
|
||||
assert!(folder
|
||||
let views_in_trash_for_app = folder
|
||||
.get_my_trash_sections()
|
||||
.iter()
|
||||
.any(|v| v.id == view_id_to_be_deleted.clone()));
|
||||
let view_found = web_client
|
||||
.map(|v| v.id.clone())
|
||||
.collect::<HashSet<String>>();
|
||||
for view_id in view_ids_to_be_deleted.iter() {
|
||||
assert!(views_in_trash_for_app.contains(view_id));
|
||||
}
|
||||
let views_in_trash_for_web = web_client
|
||||
.api_client
|
||||
.get_workspace_trash(&workspace_id)
|
||||
.await
|
||||
.unwrap()
|
||||
.views
|
||||
.iter()
|
||||
.any(|v| v.view.view_id == view_id_to_be_deleted.clone());
|
||||
assert!(view_found);
|
||||
.map(|v| v.view.view_id.clone())
|
||||
.collect::<HashSet<String>>();
|
||||
for view_id in view_ids_to_be_deleted.iter() {
|
||||
assert!(views_in_trash_for_web.contains(view_id));
|
||||
}
|
||||
|
||||
web_client
|
||||
.api_client
|
||||
.restore_workspace_page_view_from_trash(
|
||||
Uuid::parse_str(&workspace_id).unwrap(),
|
||||
&view_id_to_be_deleted,
|
||||
&view_ids_to_be_deleted[0],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -187,7 +196,7 @@ async fn move_page_to_trash() {
|
|||
assert!(!folder
|
||||
.get_my_trash_sections()
|
||||
.iter()
|
||||
.any(|v| v.id == view_id_to_be_deleted.clone()));
|
||||
.any(|v| v.id == view_ids_to_be_deleted[0]));
|
||||
let view_found = web_client
|
||||
.api_client
|
||||
.get_workspace_trash(&workspace_id)
|
||||
|
|
@ -195,7 +204,26 @@ async fn move_page_to_trash() {
|
|||
.unwrap()
|
||||
.views
|
||||
.iter()
|
||||
.any(|v| v.view.view_id == view_id_to_be_deleted.clone());
|
||||
.any(|v| v.view.view_id == view_ids_to_be_deleted[0]);
|
||||
assert!(!view_found);
|
||||
web_client
|
||||
.api_client
|
||||
.restore_all_workspace_page_views_from_trash(Uuid::parse_str(&workspace_id).unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
let folder = get_latest_folder(&app_client, &workspace_id).await;
|
||||
assert!(!folder
|
||||
.get_my_trash_sections()
|
||||
.iter()
|
||||
.any(|v| v.id == view_ids_to_be_deleted[1]));
|
||||
let view_found = web_client
|
||||
.api_client
|
||||
.get_workspace_trash(&workspace_id)
|
||||
.await
|
||||
.unwrap()
|
||||
.views
|
||||
.iter()
|
||||
.any(|v| v.view.view_id == view_ids_to_be_deleted[1]);
|
||||
assert!(!view_found);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,42 @@
|
|||
use client_api_test::generate_unique_registered_user_client;
|
||||
use collab_entity::CollabType;
|
||||
use database_entity::dto::QueryCollabParams;
|
||||
use shared_entity::dto::workspace_dto::AFDatabaseField;
|
||||
use shared_entity::dto::workspace_dto::CreateWorkspaceParam;
|
||||
use shared_entity::dto::workspace_dto::PatchWorkspaceParam;
|
||||
|
||||
#[tokio::test]
|
||||
async fn workspace_list_database() {
|
||||
let (c, _user) = generate_unique_registered_user_client().await;
|
||||
let workspace_id = c.get_workspaces().await.unwrap()[0].workspace_id;
|
||||
let dbs = c.list_databases(&workspace_id.to_string()).await.unwrap();
|
||||
assert_eq!(dbs.len(), 1);
|
||||
|
||||
let db = &dbs[0];
|
||||
|
||||
assert_eq!(db.name, "");
|
||||
assert!(db.fields.contains(&AFDatabaseField {
|
||||
name: "Last modified".to_string(),
|
||||
field_type: "LastEditedTime".to_string(),
|
||||
}));
|
||||
assert!(db.fields.contains(&AFDatabaseField {
|
||||
name: "Multiselect".to_string(),
|
||||
field_type: "MultiSelect".to_string(),
|
||||
}));
|
||||
assert!(db.fields.contains(&AFDatabaseField {
|
||||
name: "Tasks".to_string(),
|
||||
field_type: "Checklist".to_string(),
|
||||
}));
|
||||
assert!(db.fields.contains(&AFDatabaseField {
|
||||
name: "Status".to_string(),
|
||||
field_type: "SingleSelect".to_string(),
|
||||
}));
|
||||
assert!(db.fields.contains(&AFDatabaseField {
|
||||
name: "Description".to_string(),
|
||||
field_type: "RichText".to_string(),
|
||||
}));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn add_and_delete_workspace_for_user() {
|
||||
let (c, _user) = generate_unique_registered_user_client().await;
|
||||
|
|
|
|||
Loading…
Reference in New Issue