Merge branch 'AppFlowy-IO:main' into dev

This commit is contained in:
Zaki Mubarok 2022-07-25 13:38:26 +07:00 committed by GitHub
commit 7c5c6f2faa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 645 additions and 371 deletions

View File

@ -96,6 +96,12 @@
"lightMode": "Cambiar a modo Claro",
"darkMode": "Cambiar a modo Oscuro"
},
"notifications": {
"export": {
"markdown": "Nota exportada a Markdown",
"path": "Documentos/flowy"
}
},
"contactsPage": {
"title": "Contactos",
"whatsHappening": "¿Qué está pasando esta semana?",
@ -120,13 +126,13 @@
"oAuth": {
"err": {
"failedTitle": "Imposible conectarse con sus credenciales.",
"failedMsg": "Por favor asegurese haber completado el proceso de ingreso en su buscador."
"failedMsg": "Por favor asegurese haber completado el proceso de ingreso en su navegador."
},
"google": {
"title": "Ingresar con Google",
"instruction1": "Para importar sus contactos de Google, debe autorizar esta aplicación usando su buscador web.",
"instruction1": "Para importar sus contactos de Google, debe autorizar esta aplicación usando su navegador web.",
"instruction2": "Copie este código al presionar el icono o al seleccionar el texto:",
"instruction3": "Navege al siguiente enlace en su buscador web, e ingrese el código anterior:",
"instruction3": "Navege al siguiente enlace en su navegador web, e ingrese el código anterior:",
"instruction4": "Presione el botón de abajo cuando haya completado su registro:"
}
},
@ -141,5 +147,71 @@
"lightLabel": "Modo Claro",
"darkLabel": "Modo Oscuro"
}
},
"grid": {
"settings": {
"filter": "Filtrar",
"sortBy": "Ordenar por",
"Properties": "Propiedades"
},
"field": {
"hide": "Ocultar",
"insertLeft": "Insertar a la Izquierda",
"insertRight": "Insertar a la Derecha",
"duplicate": "Duplicar",
"delete": "Eliminar",
"textFieldName": "Texto",
"checkboxFieldName": "Casilla de verificación",
"dateFieldName": "Fecha",
"numberFieldName": "Números",
"singleSelectFieldName": "Seleccionar",
"multiSelectFieldName": "Selección múltiple",
"urlFieldName": "URL",
"numberFormat": " Formato numérico",
"dateFormat": " Formato de fecha",
"includeTime": " Incluir tiempo",
"dateFormatFriendly": "Mes Día, Año",
"dateFormatISO": "Año-Mes-Día",
"dateFormatLocal": "Año/Mes/Día",
"dateFormatUS": "Año/Mes/Día",
"timeFormat": " Time format",
"invalidTimeFormat": "Formato de tiempo",
"timeFormatTwelveHour": "12 horas",
"timeFormatTwentyFourHour": "24 horas",
"addSelectOption": "Añadir una opción",
"optionTitle": "Opciones",
"addOption": "Añadir opción",
"editProperty": "Editar propiedad"
},
"row": {
"duplicate": "Duplicar",
"delete": "Eliminar",
"textPlaceholder": "Vacío",
"copyProperty": "Propiedad copiada al portapapeles"
},
"selectOption": {
"create": "Crear",
"purpleColor": "Morado",
"pinkColor": "Rosa",
"lightPinkColor": "Rosa Claro",
"orangeColor": "Naranja",
"yellowColor": "Amarillo",
"limeColor": "Lima",
"greenColor": "Verde",
"aquaColor": "Agua",
"blueColor": "Azul",
"deleteTag": "Borrar etiqueta",
"colorPannelTitle": "Colores",
"pannelTitle": "Selecciona una opción o crea una",
"searchOption": "Buscar una opción"
},
"menuName": "Grid"
},
"document": {
"menuName": "Doc",
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
}
}
}

View File

@ -68,7 +68,7 @@
"help": "Aide et Support",
"debug": {
"name": "Informations de Débogage",
"success": "Informations de Débogage copiées dans le presse-papiers!",
"success": "Informations de Débogage copiées dans le presse-papiers !",
"fail": "Impossible de copier les informations de Débogage dans le presse-papiers"
}
},

View File

@ -0,0 +1,218 @@
{
"appName": "AppFlowy",
"defaultUsername": "我",
"welcomeText": "歡迎使用 @:appName",
"githubStarText": "在 GitHub 點星",
"subscribeNewsletterText": "訂閱電子報",
"letsGoButtonText": "出發吧",
"title": "標題",
"signUp": {
"buttonText": "註冊",
"title": "註冊 @:appName",
"getStartedText": "開始使用",
"emptyPasswordError": "密碼不能為空",
"repeatPasswordEmptyError": "確認密碼不能為空",
"unmatchedPasswordError": "確認密碼與密碼不符",
"alreadyHaveAnAccount": "已經有帳號了嗎?",
"emailHint": "電子郵件地址",
"passwordHint": "密碼",
"repeatPasswordHint": "確認密碼"
},
"signIn": {
"loginTitle": "登入 @:appName",
"loginButtonText": "登入",
"buttonText": "登入",
"forgotPassword": "忘記密碼?",
"emailHint": "電子郵件地址",
"passwordHint": "密碼",
"dontHaveAnAccount": "沒有帳號?",
"repeatPasswordEmptyError": "確認密碼不能為空",
"unmatchedPasswordError": "確認密碼與密碼不符"
},
"workspace": {
"create": "建立工作區",
"hint": "工作區",
"notFoundError": "找不到工作區"
},
"shareAction": {
"buttonText": "分享",
"workInProgress": "即將推出",
"markdown": "Markdown",
"copyLink": "複製連結"
},
"disclosureAction": {
"rename": "重新命名",
"delete": "刪除",
"duplicate": "複製"
},
"blankPageTitle": "空白頁面",
"newPageText": "新頁面",
"trash": {
"text": "垃圾筒",
"restoreAll": "全部復原",
"deleteAll": "全部刪除",
"pageHeader": {
"fileName": "檔案名稱",
"lastModified": "最後修改時間",
"created": "建立時間"
}
},
"deletePagePrompt": {
"text": "此頁面在垃圾筒中",
"restore": "復原頁面",
"deletePermanent": "永久刪除"
},
"dialogCreatePageNameHint": "頁面名稱",
"questionBubble": {
"whatsNew": "新功能",
"help": "幫助 & 支援",
"debug": {
"name": "除錯資訊",
"success": "已將除錯資訊複製至剪貼簿!",
"fail": "無法將除錯資訊複製至剪貼簿"
}
},
"menuAppHeader": {
"addPageTooltip": "快速新增頁面",
"defaultNewPageName": "未命名",
"renameDialog": "重新命名"
},
"toolbar": {
"undo": "復原",
"redo": "取消復原",
"bold": "粗體",
"italic": "斜體",
"underline": "底線",
"strike": "刪除線",
"numList": "有序清單",
"bulletList": "無序清單",
"checkList": "核取清單",
"inlineCode": "程式碼",
"quote": "區塊引言",
"header": "標題",
"highlight": "反白"
},
"tooltip": {
"lightMode": "切換至亮色模式",
"darkMode": "切換至暗色模式"
},
"notifications": {
"export": {
"markdown": "已將筆記匯出成 Markdown",
"path": "Documents/flowy"
}
},
"contactsPage": {
"title": "聯絡人",
"whatsHappening": "這周有甚麼新鮮事?",
"addContact": "新增聯絡人",
"editContact": "編輯聯絡人"
},
"button": {
"OK": "OK",
"Cancel": "取消",
"signIn": "登入",
"signOut": "登出",
"complete": "完成",
"save": "儲存"
},
"label": {
"welcome": "歡迎!",
"firstName": "名",
"middleName": "中間名",
"lastName": "姓",
"stepX": "步驟 {X}"
},
"oAuth": {
"err": {
"failedTitle": "無法連接至您的帳號。",
"failedMsg": "請確認您已在瀏覽器中完成登入程序:"
},
"google": {
"title": "GOOGLE 登入",
"instruction1": "若要匯入您的 Google 聯絡人,您必須透過瀏覽器授權此應用程式:",
"instruction2": "點擊圖示或選取文字以複製代碼:",
"instruction3": "前往下列網址,並輸入上述代碼:",
"instruction4": "完成註冊後,請點擊下方按鈕:"
}
},
"settings": {
"title": "設定",
"menu": {
"appearance": "外觀",
"language": "語言",
"user": "使用者",
"open": "開啟設定"
},
"appearance": {
"lightLabel": "亮色模式",
"darkLabel": "暗色模式"
}
},
"grid": {
"settings": {
"filter": "篩選",
"sortBy": "排序方式",
"Properties": "內容"
},
"field": {
"hide": "隱藏",
"insertLeft": "插入左方欄",
"insertRight": "插入右方欄",
"duplicate": "複製",
"delete": "刪除",
"textFieldName": "文字",
"checkboxFieldName": "核取方塊",
"dateFieldName": "日期",
"numberFieldName": "數字",
"singleSelectFieldName": "單選",
"multiSelectFieldName": "多選",
"urlFieldName": "網址",
"numberFormat": " 數字格式",
"dateFormat": " 日期格式",
"includeTime": " 包含時間",
"dateFormatFriendly": "月 日,年",
"dateFormatISO": "年-月-日",
"dateFormatLocal": "年/月/日",
"dateFormatUS": "年/月/日",
"timeFormat": " 時間格式",
"invalidTimeFormat": "格式無效",
"timeFormatTwelveHour": "12 小時",
"timeFormatTwentyFourHour": "24 小時",
"addSelectOption": "新增選項",
"optionTitle": "選項",
"addOption": "新增選項",
"editProperty": "編輯內容"
},
"row": {
"duplicate": "複製",
"delete": "刪除",
"textPlaceholder": "空",
"copyProperty": "已將內容複製至剪貼簿"
},
"selectOption": {
"create": "建立",
"purpleColor": "紫色",
"pinkColor": "粉色",
"lightPinkColor": "淡粉色",
"orangeColor": "橘色",
"yellowColor": "黃色",
"limeColor": "萊姆色",
"greenColor": "綠色",
"aquaColor": "水藍色",
"blueColor": "藍色",
"deleteTag": "刪除標籤",
"colorPannelTitle": "顏色",
"pannelTitle": "搜尋或建立選項",
"searchOption": "搜尋選項"
},
"menuName": "網格"
},
"document": {
"menuName": "檔案",
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
}
}
}

View File

@ -58,8 +58,8 @@ class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData>
}
}
GridCellIdentifierPayloadPB _makeCellIdPayload(GridCellIdentifier cellId) {
return GridCellIdentifierPayloadPB.create()
GridCellIdPB _makeCellIdPayload(GridCellIdentifier cellId) {
return GridCellIdPB.create()
..gridId = cellId.gridId
..fieldId = cellId.fieldId
..rowId = cellId.rowId;

View File

@ -46,7 +46,7 @@ class CellService {
Future<Either<GridCellPB, FlowyError>> getCell({
required GridCellIdentifier cellId,
}) {
final payload = GridCellIdentifierPayloadPB.create()
final payload = GridCellIdPB.create()
..gridId = cellId.gridId
..fieldId = cellId.fieldId
..rowId = cellId.rowId;

View File

@ -19,7 +19,7 @@ class SelectOptionService {
(result) {
return result.fold(
(option) {
final cellIdentifier = GridCellIdentifierPayloadPB.create()
final cellIdentifier = GridCellIdPB.create()
..gridId = gridId
..fieldId = fieldId
..rowId = rowId;
@ -54,7 +54,7 @@ class SelectOptionService {
}
Future<Either<SelectOptionCellDataPB, FlowyError>> getOpitonContext() {
final payload = GridCellIdentifierPayloadPB.create()
final payload = GridCellIdPB.create()
..gridId = gridId
..fieldId = fieldId
..rowId = rowId;
@ -76,8 +76,8 @@ class SelectOptionService {
return GridEventUpdateSelectOptionCell(payload).send();
}
GridCellIdentifierPayloadPB _cellIdentifier() {
return GridCellIdentifierPayloadPB.create()
GridCellIdPB _cellIdentifier() {
return GridCellIdPB.create()
..gridId = gridId
..fieldId = fieldId
..rowId = rowId;

View File

@ -103,7 +103,7 @@ class FieldService {
}
Future<Either<Unit, FlowyError>> deleteField() {
final payload = GridFieldIdentifierPayloadPB.create()
final payload = DeleteFieldPayloadPB.create()
..gridId = gridId
..fieldId = fieldId;
@ -111,7 +111,7 @@ class FieldService {
}
Future<Either<Unit, FlowyError>> duplicateField() {
final payload = GridFieldIdentifierPayloadPB.create()
final payload = DuplicateFieldPayloadPB.create()
..gridId = gridId
..fieldId = fieldId;
@ -121,7 +121,7 @@ class FieldService {
Future<Either<FieldTypeOptionDataPB, FlowyError>> getFieldTypeOptionData({
required FieldType fieldType,
}) {
final payload = EditFieldPayloadPB.create()
final payload = GridFieldTypeOptionIdPB.create()
..gridId = gridId
..fieldId = fieldId
..fieldType = fieldType;
@ -165,7 +165,7 @@ class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {
@override
Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
final payload = EditFieldPayloadPB.create()
final payload = CreateFieldPayloadPB.create()
..gridId = gridId
..fieldType = FieldType.RichText;
@ -185,7 +185,7 @@ class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
@override
Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
final payload = EditFieldPayloadPB.create()
final payload = GridFieldTypeOptionIdPB.create()
..gridId = gridId
..fieldId = field.id
..fieldType = field.fieldType;

View File

@ -21,13 +21,10 @@ class TypeOptionService {
Future<Either<SelectOptionPB, FlowyError>> newOption({
required String name,
}) {
final fieldIdentifier = GridFieldIdentifierPayloadPB.create()
..gridId = gridId
..fieldId = fieldId;
final payload = CreateSelectOptionPayloadPB.create()
..optionName = name
..fieldIdentifier = fieldIdentifier;
..gridId = gridId
..fieldId = fieldId;
return GridEventNewSelectOption(payload).send();
}

View File

@ -191,7 +191,7 @@ class GridRowCache {
}
Future<void> _loadRow(String rowId) async {
final payload = GridRowIdPayloadPB.create()
final payload = GridRowIdPB.create()
..gridId = gridId
..blockId = block.id
..rowId = rowId;
@ -297,7 +297,7 @@ class RowService {
}
Future<Either<OptionalRowPB, FlowyError>> getRow() {
final payload = GridRowIdPayloadPB.create()
final payload = GridRowIdPB.create()
..gridId = gridId
..blockId = blockId
..rowId = rowId;
@ -306,7 +306,7 @@ class RowService {
}
Future<Either<Unit, FlowyError>> deleteRow() {
final payload = GridRowIdPayloadPB.create()
final payload = GridRowIdPB.create()
..gridId = gridId
..blockId = blockId
..rowId = rowId;
@ -315,7 +315,7 @@ class RowService {
}
Future<Either<Unit, FlowyError>> duplicateRow() {
final payload = GridRowIdPayloadPB.create()
final payload = GridRowIdPB.create()
..gridId = gridId
..blockId = blockId
..rowId = rowId;

View File

@ -7,14 +7,14 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "38.0.0"
version: "42.0.0"
analyzer:
dependency: transitive
dependency: "direct overridden"
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "3.4.1"
version: "4.3.0"
animations:
dependency: transitive
description:

View File

@ -85,6 +85,9 @@ dev_dependencies:
freezed:
bloc_test: ^9.0.2
dependency_overrides:
analyzer: ">=4.2.0 <5.0.0"
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your

View File

@ -1,4 +1,4 @@
use crate::entities::{FieldIdentifierParams, GridFieldIdentifierPayloadPB};
use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
@ -8,23 +8,20 @@ use std::collections::HashMap;
#[derive(ProtoBuf, Default)]
pub struct CreateSelectOptionPayloadPB {
#[pb(index = 1)]
pub field_identifier: GridFieldIdentifierPayloadPB,
pub field_id: String,
#[pb(index = 2)]
pub grid_id: String,
#[pb(index = 3)]
pub option_name: String,
}
pub struct CreateSelectOptionParams {
pub field_identifier: FieldIdentifierParams,
pub field_id: String,
pub grid_id: String,
pub option_name: String,
}
impl std::ops::Deref for CreateSelectOptionParams {
type Target = FieldIdentifierParams;
fn deref(&self) -> &Self::Target {
&self.field_identifier
}
}
impl TryInto<CreateSelectOptionParams> for CreateSelectOptionPayloadPB {
@ -32,16 +29,18 @@ impl TryInto<CreateSelectOptionParams> for CreateSelectOptionPayloadPB {
fn try_into(self) -> Result<CreateSelectOptionParams, Self::Error> {
let option_name = NotEmptyStr::parse(self.option_name).map_err(|_| ErrorCode::SelectOptionNameIsEmpty)?;
let field_identifier = self.field_identifier.try_into()?;
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
Ok(CreateSelectOptionParams {
field_identifier,
field_id: field_id.0,
option_name: option_name.0,
grid_id: grid_id.0,
})
}
}
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct GridCellIdentifierPayloadPB {
pub struct GridCellIdPB {
#[pb(index = 1)]
pub grid_id: String,
@ -52,20 +51,20 @@ pub struct GridCellIdentifierPayloadPB {
pub row_id: String,
}
pub struct CellIdentifierParams {
pub struct GridCellIdParams {
pub grid_id: String,
pub field_id: String,
pub row_id: String,
}
impl TryInto<CellIdentifierParams> for GridCellIdentifierPayloadPB {
impl TryInto<GridCellIdParams> for GridCellIdPB {
type Error = ErrorCode;
fn try_into(self) -> Result<CellIdentifierParams, Self::Error> {
fn try_into(self) -> Result<GridCellIdParams, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
Ok(CellIdentifierParams {
Ok(GridCellIdParams {
grid_id: grid_id.0,
field_id: field_id.0,
row_id: row_id.0,

View File

@ -155,6 +155,45 @@ pub struct GetEditFieldContextPayloadPB {
pub field_type: FieldType,
}
#[derive(Debug, Default, ProtoBuf)]
pub struct CreateFieldPayloadPB {
#[pb(index = 1)]
pub grid_id: String,
#[pb(index = 2)]
pub field_id: String,
#[pb(index = 3)]
pub field_type: FieldType,
#[pb(index = 4)]
pub create_if_not_exist: bool,
}
pub struct CreateFieldParams {
pub grid_id: String,
pub field_id: String,
pub field_type: FieldType,
}
impl TryInto<CreateFieldParams> for CreateFieldPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<CreateFieldParams, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
Ok(CreateFieldParams {
grid_id: grid_id.0,
field_id: field_id.0,
field_type: self.field_type,
})
}
}
#[derive(Debug, Default, ProtoBuf)]
pub struct EditFieldPayloadPB {
#[pb(index = 1)]
@ -190,19 +229,34 @@ impl TryInto<EditFieldParams> for EditFieldPayloadPB {
}
}
pub struct CreateFieldParams {
#[derive(Debug, Default, ProtoBuf)]
pub struct GridFieldTypeOptionIdPB {
#[pb(index = 1)]
pub grid_id: String,
#[pb(index = 2)]
pub field_id: String,
#[pb(index = 3)]
pub field_type: FieldType,
}
impl TryInto<CreateFieldParams> for EditFieldPayloadPB {
pub struct GridFieldTypeOptionIdParams {
pub grid_id: String,
pub field_id: String,
pub field_type: FieldType,
}
impl TryInto<GridFieldTypeOptionIdParams> for GridFieldTypeOptionIdPB {
type Error = ErrorCode;
fn try_into(self) -> Result<CreateFieldParams, Self::Error> {
fn try_into(self) -> Result<GridFieldTypeOptionIdParams, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
Ok(CreateFieldParams {
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
Ok(GridFieldTypeOptionIdParams {
grid_id: grid_id.0,
field_id: field_id.0,
field_type: self.field_type,
})
}
@ -556,6 +610,16 @@ impl std::convert::From<FieldTypeRevision> for FieldType {
}
}
}
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct DuplicateFieldPayloadPB {
#[pb(index = 1)]
pub field_id: String,
#[pb(index = 2)]
pub grid_id: String,
}
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct GridFieldIdentifierPayloadPB {
#[pb(index = 1)]
@ -565,20 +629,44 @@ pub struct GridFieldIdentifierPayloadPB {
pub grid_id: String,
}
pub struct FieldIdentifierParams {
pub field_id: String,
pub grid_id: String,
}
impl TryInto<FieldIdentifierParams> for GridFieldIdentifierPayloadPB {
impl TryInto<GridFieldIdParams> for DuplicateFieldPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<FieldIdentifierParams, Self::Error> {
fn try_into(self) -> Result<GridFieldIdParams, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
Ok(FieldIdentifierParams {
Ok(GridFieldIdParams {
grid_id: grid_id.0,
field_id: field_id.0,
})
}
}
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct DeleteFieldPayloadPB {
#[pb(index = 1)]
pub field_id: String,
#[pb(index = 2)]
pub grid_id: String,
}
impl TryInto<GridFieldIdParams> for DeleteFieldPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<GridFieldIdParams, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
Ok(GridFieldIdParams {
grid_id: grid_id.0,
field_id: field_id.0,
})
}
}
pub struct GridFieldIdParams {
pub field_id: String,
pub grid_id: String,
}

View File

@ -2,17 +2,6 @@ use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
#[derive(ProtoBuf, Default)]
pub struct GridRowIdPayloadPB {
#[pb(index = 1)]
pub grid_id: String,
#[pb(index = 2)]
pub block_id: String,
#[pb(index = 3)]
pub row_id: String,
}
#[derive(Debug, Default, Clone, ProtoBuf)]
pub struct GridRowIdPB {
@ -26,15 +15,21 @@ pub struct GridRowIdPB {
pub row_id: String,
}
impl TryInto<GridRowIdPB> for GridRowIdPayloadPB {
pub struct GridRowIdParams {
pub grid_id: String,
pub block_id: String,
pub row_id: String,
}
impl TryInto<GridRowIdParams> for GridRowIdPB {
type Error = ErrorCode;
fn try_into(self) -> Result<GridRowIdPB, Self::Error> {
fn try_into(self) -> Result<GridRowIdParams, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let block_id = NotEmptyStr::parse(self.block_id).map_err(|_| ErrorCode::BlockIdIsEmpty)?;
let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
Ok(GridRowIdPB {
Ok(GridRowIdParams {
grid_id: grid_id.0,
block_id: block_id.0,
row_id: row_id.0,

View File

@ -113,10 +113,10 @@ pub(crate) async fn update_field_type_option_handler(
#[tracing::instrument(level = "trace", skip(data, manager), err)]
pub(crate) async fn delete_field_handler(
data: Data<GridFieldIdentifierPayloadPB>,
data: Data<DeleteFieldPayloadPB>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: FieldIdentifierParams = data.into_inner().try_into()?;
let params: GridFieldIdParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.delete_field(&params.field_id).await?;
Ok(())
@ -151,10 +151,10 @@ pub(crate) async fn switch_to_field_handler(
#[tracing::instrument(level = "trace", skip(data, manager), err)]
pub(crate) async fn duplicate_field_handler(
data: Data<GridFieldIdentifierPayloadPB>,
data: Data<DuplicateFieldPayloadPB>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: FieldIdentifierParams = data.into_inner().try_into()?;
let params: GridFieldIdParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.duplicate_field(&params.field_id).await?;
Ok(())
@ -163,10 +163,10 @@ pub(crate) async fn duplicate_field_handler(
/// Return the FieldTypeOptionData if the Field exists otherwise return record not found error.
#[tracing::instrument(level = "trace", skip(data, manager), err)]
pub(crate) async fn get_field_type_option_data_handler(
data: Data<EditFieldPayloadPB>,
data: Data<GridFieldTypeOptionIdPB>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<FieldTypeOptionDataPB, FlowyError> {
let params: EditFieldParams = data.into_inner().try_into()?;
let params: GridFieldTypeOptionIdParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
match editor.get_field_rev(&params.field_id).await {
None => Err(FlowyError::record_not_found()),
@ -186,7 +186,7 @@ pub(crate) async fn get_field_type_option_data_handler(
/// Create FieldMeta and save it. Return the FieldTypeOptionData.
#[tracing::instrument(level = "trace", skip(data, manager), err)]
pub(crate) async fn create_field_type_option_data_handler(
data: Data<EditFieldPayloadPB>,
data: Data<CreateFieldPayloadPB>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<FieldTypeOptionDataPB, FlowyError> {
let params: CreateFieldParams = data.into_inner().try_into()?;
@ -227,10 +227,10 @@ async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType)
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn get_row_handler(
data: Data<GridRowIdPayloadPB>,
data: Data<GridRowIdPB>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<OptionalRowPB, FlowyError> {
let params: GridRowIdPB = data.into_inner().try_into()?;
let params: GridRowIdParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let row = editor
.get_row_rev(&params.row_id)
@ -242,10 +242,10 @@ pub(crate) async fn get_row_handler(
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn delete_row_handler(
data: Data<GridRowIdPayloadPB>,
data: Data<GridRowIdPB>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: GridRowIdPB = data.into_inner().try_into()?;
let params: GridRowIdParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.delete_row(&params.row_id).await?;
Ok(())
@ -253,10 +253,10 @@ pub(crate) async fn delete_row_handler(
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn duplicate_row_handler(
data: Data<GridRowIdPayloadPB>,
data: Data<GridRowIdPB>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: GridRowIdPB = data.into_inner().try_into()?;
let params: GridRowIdParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.duplicate_row(&params.row_id).await?;
Ok(())
@ -275,10 +275,10 @@ pub(crate) async fn create_row_handler(
// #[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_cell_handler(
data: Data<GridCellIdentifierPayloadPB>,
data: Data<GridCellIdPB>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<GridCellPB, FlowyError> {
let params: CellIdentifierParams = data.into_inner().try_into()?;
let params: GridCellIdParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
match editor.get_cell(&params).await {
None => data_result(GridCellPB::empty(&params.field_id)),
@ -357,10 +357,10 @@ pub(crate) async fn update_select_option_handler(
#[tracing::instrument(level = "trace", skip(data, manager), err)]
pub(crate) async fn get_select_option_handler(
data: Data<GridCellIdentifierPayloadPB>,
data: Data<GridCellIdPB>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<SelectOptionCellDataPB, FlowyError> {
let params: CellIdentifierParams = data.into_inner().try_into()?;
let params: GridCellIdParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
match editor.get_field_rev(&params.field_id).await {
None => {

View File

@ -69,28 +69,28 @@ pub enum GridEvent {
#[event(input = "InsertFieldPayloadPB")]
InsertField = 13,
#[event(input = "GridFieldIdentifierPayloadPB")]
#[event(input = "DeleteFieldPayloadPB")]
DeleteField = 14,
#[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")]
SwitchToField = 20,
#[event(input = "GridFieldIdentifierPayloadPB")]
#[event(input = "DuplicateFieldPayloadPB")]
DuplicateField = 21,
#[event(input = "MoveItemPayloadPB")]
MoveItem = 22,
#[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")]
#[event(input = "GridFieldTypeOptionIdPB", output = "FieldTypeOptionDataPB")]
GetFieldTypeOption = 23,
#[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")]
#[event(input = "CreateFieldPayloadPB", output = "FieldTypeOptionDataPB")]
CreateFieldTypeOption = 24,
#[event(input = "CreateSelectOptionPayloadPB", output = "SelectOptionPB")]
NewSelectOption = 30,
#[event(input = "GridCellIdentifierPayloadPB", output = "SelectOptionCellDataPB")]
#[event(input = "GridCellIdPB", output = "SelectOptionCellDataPB")]
GetSelectOptionCellData = 31,
#[event(input = "SelectOptionChangesetPayloadPB")]
@ -99,16 +99,16 @@ pub enum GridEvent {
#[event(input = "CreateRowPayloadPB", output = "GridRowPB")]
CreateRow = 50,
#[event(input = "GridRowIdPayloadPB", output = "OptionalRowPB")]
#[event(input = "GridRowIdPB", output = "OptionalRowPB")]
GetRow = 51,
#[event(input = "GridRowIdPayloadPB")]
#[event(input = "GridRowIdPB")]
DeleteRow = 52,
#[event(input = "GridRowIdPayloadPB")]
#[event(input = "GridRowIdPB")]
DuplicateRow = 53,
#[event(input = "GridCellIdentifierPayloadPB", output = "GridCellPB")]
#[event(input = "GridCellIdPB", output = "GridCellPB")]
GetCell = 70,
#[event(input = "CellChangesetPB")]

View File

@ -1,30 +1,44 @@
#[cfg(test)]
mod tests {
use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data};
use crate::services::field::type_options::checkbox_type_option::{NO, YES};
use crate::services::field::FieldBuilder;
use crate::entities::FieldType;
use crate::services::cell::{CellDataOperation};
use crate::services::field::type_options::checkbox_type_option::*;
use crate::services::field::FieldBuilder;
use flowy_grid_data_model::revision::FieldRevision;
#[test]
fn checkout_box_description_test() {
let field_rev = FieldBuilder::from_field_type(&FieldType::Checkbox).build();
let data = apply_cell_data_changeset("true", None, &field_rev).unwrap();
assert_eq!(decode_any_cell_data(data, &field_rev).to_string(), YES);
let type_option = CheckboxTypeOption::default();
let field_type = FieldType::Checkbox;
let field_rev = FieldBuilder::from_field_type(&field_type).build();
let data = apply_cell_data_changeset("1", None, &field_rev).unwrap();
assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES);
// the checkout value will be checked if the value is "1", "true" or "yes"
assert_checkbox(&type_option, "1", CHECK, &field_type, &field_rev);
assert_checkbox(&type_option, "true", CHECK, &field_type, &field_rev);
assert_checkbox(&type_option, "yes", CHECK, &field_type, &field_rev);
let data = apply_cell_data_changeset("yes", None, &field_rev).unwrap();
assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES);
// the checkout value will be uncheck if the value is "false" or "No"
assert_checkbox(&type_option, "false", UNCHECK, &field_type, &field_rev);
assert_checkbox(&type_option, "No", UNCHECK, &field_type, &field_rev);
let data = apply_cell_data_changeset("false", None, &field_rev).unwrap();
assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO);
// the checkout value will be empty if the value is letters or empty string
assert_checkbox(&type_option, "abc", "", &field_type, &field_rev);
assert_checkbox(&type_option, "", "", &field_type, &field_rev);
}
let data = apply_cell_data_changeset("no", None, &field_rev).unwrap();
assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO);
let data = apply_cell_data_changeset("12", None, &field_rev).unwrap();
assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), "");
fn assert_checkbox(
type_option: &CheckboxTypeOption,
input_str: &str,
expected_str: &str,
field_type: &FieldType,
field_rev: &FieldRevision,
) {
assert_eq!(
type_option
.decode_cell_data(input_str.to_owned().into(), field_type, field_rev)
.unwrap()
.to_string(),
expected_str.to_owned()
);
}
}

View File

@ -3,14 +3,14 @@ use bytes::Bytes;
use flowy_error::{FlowyError, FlowyResult};
use std::str::FromStr;
pub const YES: &str = "Yes";
pub const NO: &str = "No";
pub const CHECK: &str = "Yes";
pub const UNCHECK: &str = "No";
pub struct CheckboxCellData(String);
impl CheckboxCellData {
pub fn is_check(&self) -> bool {
self.0 == YES
self.0 == CHECK
}
}
@ -36,8 +36,8 @@ impl FromStr for CheckboxCellData {
};
match val {
Some(true) => Ok(Self(YES.to_string())),
Some(false) => Ok(Self(NO.to_string())),
Some(true) => Ok(Self(CHECK.to_string())),
Some(false) => Ok(Self(UNCHECK.to_string())),
None => Ok(Self("".to_string())),
}
}

View File

@ -1,29 +1,12 @@
#[cfg(test)]
mod tests {
use crate::entities::FieldType;
use crate::services::cell::{CellDataChangeset, CellDataOperation};
use crate::services::cell::{CellDataOperation};
use crate::services::field::*;
// use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat};
use flowy_grid_data_model::revision::FieldRevision;
use strum::IntoEnumIterator;
#[test]
fn date_type_option_invalid_input_test() {
let type_option = DateTypeOption::default();
let field_type = FieldType::DateTime;
let field_rev = FieldBuilder::from_field_type(&field_type).build();
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some("1e".to_string()),
time: Some("23:00".to_owned()),
},
&field_type,
&field_rev,
"",
);
}
#[test]
fn date_type_option_date_format_test() {
let mut type_option = DateTypeOption::default();
@ -32,23 +15,23 @@ mod tests {
type_option.date_format = date_format;
match date_format {
DateFormat::Friendly => {
assert_decode_timestamp(1647251762, &type_option, &field_rev, "Mar 14,2022");
assert_date(&type_option, 1647251762, None, "Mar 14,2022", &field_rev);
}
DateFormat::US => {
assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022/03/14");
assert_date(&type_option, 1647251762, None, "2022/03/14", &field_rev);
}
DateFormat::ISO => {
assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022-03-14");
assert_date(&type_option, 1647251762, None, "2022-03-14", &field_rev);
}
DateFormat::Local => {
assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022/03/14");
assert_date(&type_option, 1647251762, None, "2022/03/14", &field_rev);
}
}
}
}
#[test]
fn date_type_option_time_format_test() {
fn date_type_option_different_time_format_test() {
let mut type_option = DateTypeOption::default();
let field_type = FieldType::DateTime;
let field_rev = FieldBuilder::from_field_type(&field_type).build();
@ -58,59 +41,23 @@ mod tests {
type_option.include_time = true;
match time_format {
TimeFormat::TwentyFourHour => {
assert_changeset_result(
assert_date(&type_option, 1653609600, None, "May 27,2022", &field_rev);
assert_date(
&type_option,
DateCellChangesetPB {
date: Some(1653609600.to_string()),
time: None,
},
&field_type,
&field_rev,
"May 27,2022",
);
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(1653609600.to_string()),
time: Some("23:00".to_owned()),
},
&field_type,
&field_rev,
1653609600,
Some("23:00".to_owned()),
"May 27,2022 23:00",
&field_rev,
);
}
TimeFormat::TwelveHour => {
assert_changeset_result(
assert_date(&type_option, 1653609600, None, "May 27,2022", &field_rev);
assert_date(
&type_option,
DateCellChangesetPB {
date: Some(1653609600.to_string()),
time: None,
},
&field_type,
&field_rev,
"May 27,2022",
);
//
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(1653609600.to_string()),
time: Some("".to_owned()),
},
&field_type,
&field_rev,
"May 27,2022",
);
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(1653609600.to_string()),
time: Some("11:23 pm".to_owned()),
},
&field_type,
&field_rev,
1653609600,
Some("11:23 pm".to_owned()),
"May 27,2022 11:23 PM",
&field_rev,
);
}
}
@ -118,141 +65,71 @@ mod tests {
}
#[test]
fn date_type_option_apply_changeset_test() {
let mut type_option = DateTypeOption::new();
fn date_type_option_invalid_date_str_test() {
let type_option = DateTypeOption::default();
let field_type = FieldType::DateTime;
let field_rev = FieldBuilder::from_field_type(&field_type).build();
let date_timestamp = "1653609600".to_owned();
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(date_timestamp.clone()),
time: None,
},
&field_type,
&field_rev,
"May 27,2022",
);
assert_date(&type_option, "abc", None, "", &field_rev);
}
#[test]
#[should_panic]
fn date_type_option_invalid_include_time_str_test() {
let mut type_option = DateTypeOption::new();
type_option.include_time = true;
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(date_timestamp.clone()),
time: None,
},
&field_type,
&field_rev,
"May 27,2022",
);
let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
assert_changeset_result(
assert_date(
&type_option,
DateCellChangesetPB {
date: Some(date_timestamp.clone()),
time: Some("1:00".to_owned()),
},
&field_type,
&field_rev,
1653609600,
Some("1:".to_owned()),
"May 27,2022 01:00",
);
type_option.time_format = TimeFormat::TwelveHour;
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(date_timestamp),
time: Some("1:00 am".to_owned()),
},
&field_type,
&field_rev,
);
}
#[test]
fn date_type_option_empty_include_time_str_test() {
let mut type_option = DateTypeOption::new();
type_option.include_time = true;
let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
assert_date(&type_option, 1653609600, Some("".to_owned()), "May 27,2022", &field_rev);
}
/// The default time format is TwentyFourHour, so the include_time_str in twelve_hours_format will cause parser error.
#[test]
#[should_panic]
fn date_type_option_twelve_hours_include_time_str_in_twenty_four_hours_format() {
let mut type_option = DateTypeOption::new();
type_option.include_time = true;
let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
assert_date(
&type_option,
1653609600,
Some("1:00 am".to_owned()),
"May 27,2022 01:00 AM",
&field_rev,
);
}
#[test]
#[should_panic]
fn date_type_option_apply_changeset_error_test() {
let mut type_option = DateTypeOption::new();
type_option.include_time = true;
let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
let date_timestamp = "1653609600".to_owned();
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(date_timestamp.clone()),
time: Some("1:".to_owned()),
},
&FieldType::DateTime,
&field_rev,
"May 27,2022 01:00",
);
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(date_timestamp),
time: Some("1:00".to_owned()),
},
&FieldType::DateTime,
&field_rev,
"May 27,2022 01:00",
);
}
#[test]
#[should_panic]
fn date_type_option_twelve_hours_to_twenty_four_hours() {
let mut type_option = DateTypeOption::new();
type_option.include_time = true;
let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
let date_timestamp = "1653609600".to_owned();
assert_changeset_result(
&type_option,
DateCellChangesetPB {
date: Some(date_timestamp),
time: Some("1:00 am".to_owned()),
},
&FieldType::DateTime,
&field_rev,
"May 27,2022 01:00",
);
}
fn assert_changeset_result(
fn assert_date<T: ToString>(
type_option: &DateTypeOption,
changeset: DateCellChangesetPB,
_field_type: &FieldType,
timestamp: T,
include_time_str: Option<String>,
expected_str: &str,
field_rev: &FieldRevision,
expected: &str,
) {
let changeset = CellDataChangeset(Some(changeset));
let encoded_data = type_option.apply_changeset(changeset, None).unwrap();
assert_eq!(
expected.to_owned(),
decode_cell_data(encoded_data, type_option, field_rev)
);
}
fn assert_decode_timestamp(
timestamp: i64,
type_option: &DateTypeOption,
field_rev: &FieldRevision,
expected: &str,
) {
let s = serde_json::to_string(&DateCellChangesetPB {
date: Some(timestamp.to_string()),
time: None,
time: include_time_str,
})
.unwrap();
let encoded_data = type_option.apply_changeset(s.into(), None).unwrap();
assert_eq!(
expected.to_owned(),
decode_cell_data(encoded_data, type_option, field_rev)
decode_cell_data(encoded_data, type_option, field_rev),
expected_str.to_owned(),
);
}

View File

@ -1,5 +1,5 @@
use crate::entities::CellChangesetPB;
use crate::entities::{CellIdentifierParams, GridCellIdentifierPayloadPB};
use crate::entities::{GridCellIdParams, GridCellIdPB};
use crate::services::cell::{CellBytesParser, FromCellChangeset, FromCellString};
use bytes::Bytes;
@ -24,7 +24,7 @@ pub struct DateCellDataPB {
#[derive(Clone, Debug, Default, ProtoBuf)]
pub struct DateChangesetPayloadPB {
#[pb(index = 1)]
pub cell_identifier: GridCellIdentifierPayloadPB,
pub cell_identifier: GridCellIdPB,
#[pb(index = 2, one_of)]
pub date: Option<String>,
@ -34,7 +34,7 @@ pub struct DateChangesetPayloadPB {
}
pub struct DateChangesetParams {
pub cell_identifier: CellIdentifierParams,
pub cell_identifier: GridCellIdParams,
pub date: Option<String>,
pub time: Option<String>,
}
@ -43,7 +43,7 @@ impl TryInto<DateChangesetParams> for DateChangesetPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<DateChangesetParams, Self::Error> {
let cell_identifier: CellIdentifierParams = self.cell_identifier.try_into()?;
let cell_identifier: GridCellIdParams = self.cell_identifier.try_into()?;
Ok(DateChangesetParams {
cell_identifier,
date: self.date,

View File

@ -7,25 +7,30 @@ mod tests {
use flowy_grid_data_model::revision::FieldRevision;
use strum::IntoEnumIterator;
/// Testing when the input is not a number.
#[test]
fn number_type_option_invalid_input_test() {
let type_option = NumberTypeOption::default();
let field_type = FieldType::Number;
let field_rev = FieldBuilder::from_field_type(&field_type).build();
assert_equal(&type_option, "", "", &field_type, &field_rev);
assert_equal(&type_option, "abc", "", &field_type, &field_rev);
// Input is empty String
assert_number(&type_option, "", "", &field_type, &field_rev);
// Input is letter
assert_number(&type_option, "abc", "", &field_type, &field_rev);
}
/// Testing the strip_currency_symbol function. It should return the string without the input symbol.
#[test]
fn number_type_option_strip_symbol_test() {
let mut type_option = NumberTypeOption::new();
type_option.format = NumberFormat::USD;
// Remove the $ symbol
assert_eq!(strip_currency_symbol("$18,443"), "18,443".to_owned());
type_option.format = NumberFormat::Yuan;
assert_eq!(strip_currency_symbol("$0.2"), "0.2".to_owned());
// Remove the ¥ symbol
assert_eq!(strip_currency_symbol("¥0.2"), "0.2".to_owned());
}
/// Format the input number to the corresponding format string.
#[test]
fn number_type_option_format_number_test() {
let mut type_option = NumberTypeOption::default();
@ -36,25 +41,26 @@ mod tests {
type_option.format = format;
match format {
NumberFormat::Num => {
assert_equal(&type_option, "18443", "18443", &field_type, &field_rev);
assert_number(&type_option, "18443", "18443", &field_type, &field_rev);
}
NumberFormat::USD => {
assert_equal(&type_option, "18443", "$18,443", &field_type, &field_rev);
assert_number(&type_option, "18443", "$18,443", &field_type, &field_rev);
}
NumberFormat::Yen => {
assert_equal(&type_option, "18443", "¥18,443", &field_type, &field_rev);
assert_number(&type_option, "18443", "¥18,443", &field_type, &field_rev);
}
NumberFormat::Yuan => {
assert_equal(&type_option, "18443", "CN¥18,443", &field_type, &field_rev);
assert_number(&type_option, "18443", "CN¥18,443", &field_type, &field_rev);
}
NumberFormat::EUR => {
assert_equal(&type_option, "18443", "€18.443", &field_type, &field_rev);
assert_number(&type_option, "18443", "€18.443", &field_type, &field_rev);
}
_ => {}
}
}
}
/// Format the input String to the corresponding format string.
#[test]
fn number_type_option_format_str_test() {
let mut type_option = NumberTypeOption::default();
@ -65,33 +71,34 @@ mod tests {
type_option.format = format;
match format {
NumberFormat::Num => {
assert_equal(&type_option, "18443", "18443", &field_type, &field_rev);
assert_equal(&type_option, "0.2", "0.2", &field_type, &field_rev);
assert_number(&type_option, "18443", "18443", &field_type, &field_rev);
assert_number(&type_option, "0.2", "0.2", &field_type, &field_rev);
}
NumberFormat::USD => {
assert_equal(&type_option, "$18,44", "$1,844", &field_type, &field_rev);
assert_equal(&type_option, "$0.2", "$0.2", &field_type, &field_rev);
assert_equal(&type_option, "", "", &field_type, &field_rev);
assert_equal(&type_option, "abc", "", &field_type, &field_rev);
assert_number(&type_option, "$18,44", "$1,844", &field_type, &field_rev);
assert_number(&type_option, "$0.2", "$0.2", &field_type, &field_rev);
assert_number(&type_option, "", "", &field_type, &field_rev);
assert_number(&type_option, "abc", "", &field_type, &field_rev);
}
NumberFormat::Yen => {
assert_equal(&type_option, "¥18,44", "¥1,844", &field_type, &field_rev);
assert_equal(&type_option, "¥1844", "¥1,844", &field_type, &field_rev);
assert_number(&type_option, "¥18,44", "¥1,844", &field_type, &field_rev);
assert_number(&type_option, "¥1844", "¥1,844", &field_type, &field_rev);
}
NumberFormat::Yuan => {
assert_equal(&type_option, "CN¥18,44", "CN¥1,844", &field_type, &field_rev);
assert_equal(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field_rev);
assert_number(&type_option, "CN¥18,44", "CN¥1,844", &field_type, &field_rev);
assert_number(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field_rev);
}
NumberFormat::EUR => {
assert_equal(&type_option, "€18.44", "€18,44", &field_type, &field_rev);
assert_equal(&type_option, "€0.5", "€0,5", &field_type, &field_rev);
assert_equal(&type_option, "€1844", "€1.844", &field_type, &field_rev);
assert_number(&type_option, "€18.44", "€18,44", &field_type, &field_rev);
assert_number(&type_option, "€0.5", "€0,5", &field_type, &field_rev);
assert_number(&type_option, "€1844", "€1.844", &field_type, &field_rev);
}
_ => {}
}
}
}
/// Carry out the sign positive to input number
#[test]
fn number_description_sign_test() {
let mut type_option = NumberTypeOption {
@ -105,32 +112,32 @@ mod tests {
type_option.format = format;
match format {
NumberFormat::Num => {
assert_equal(&type_option, "18443", "18443", &field_type, &field_rev);
assert_number(&type_option, "18443", "18443", &field_type, &field_rev);
}
NumberFormat::USD => {
assert_equal(&type_option, "18443", "-$18,443", &field_type, &field_rev);
assert_number(&type_option, "18443", "-$18,443", &field_type, &field_rev);
}
NumberFormat::Yen => {
assert_equal(&type_option, "18443", "-¥18,443", &field_type, &field_rev);
assert_number(&type_option, "18443", "-¥18,443", &field_type, &field_rev);
}
NumberFormat::EUR => {
assert_equal(&type_option, "18443", "-€18.443", &field_type, &field_rev);
assert_number(&type_option, "18443", "-€18.443", &field_type, &field_rev);
}
_ => {}
}
}
}
fn assert_equal(
fn assert_number(
type_option: &NumberTypeOption,
cell_data: &str,
input_str: &str,
expected_str: &str,
field_type: &FieldType,
field_rev: &FieldRevision,
) {
assert_eq!(
type_option
.decode_cell_data(cell_data.to_owned().into(), field_type, field_rev)
.decode_cell_data(input_str.to_owned().into(), field_type, field_rev)
.unwrap()
.to_string(),
expected_str.to_owned()

View File

@ -1,4 +1,4 @@
use crate::entities::{CellChangesetPB, CellIdentifierParams, FieldType, GridCellIdentifierPayloadPB};
use crate::entities::{CellChangesetPB, GridCellIdParams, FieldType, GridCellIdPB};
use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString};
use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB};
use bytes::Bytes;
@ -225,7 +225,7 @@ impl CellBytesParser for SelectOptionCellDataParser {
#[derive(Clone, Debug, Default, ProtoBuf)]
pub struct SelectOptionCellChangesetPayloadPB {
#[pb(index = 1)]
pub cell_identifier: GridCellIdentifierPayloadPB,
pub cell_identifier: GridCellIdPB,
#[pb(index = 2, one_of)]
pub insert_option_id: Option<String>,
@ -235,7 +235,7 @@ pub struct SelectOptionCellChangesetPayloadPB {
}
pub struct SelectOptionCellChangesetParams {
pub cell_identifier: CellIdentifierParams,
pub cell_identifier: GridCellIdParams,
pub insert_option_id: Option<String>,
pub delete_option_id: Option<String>,
}
@ -260,7 +260,7 @@ impl TryInto<SelectOptionCellChangesetParams> for SelectOptionCellChangesetPaylo
type Error = ErrorCode;
fn try_into(self) -> Result<SelectOptionCellChangesetParams, Self::Error> {
let cell_identifier: CellIdentifierParams = self.cell_identifier.try_into()?;
let cell_identifier: GridCellIdParams = self.cell_identifier.try_into()?;
let insert_option_id = match self.insert_option_id {
None => None,
Some(insert_option_id) => Some(
@ -334,7 +334,7 @@ pub struct SelectOptionCellDataPB {
#[derive(Clone, Debug, Default, ProtoBuf)]
pub struct SelectOptionChangesetPayloadPB {
#[pb(index = 1)]
pub cell_identifier: GridCellIdentifierPayloadPB,
pub cell_identifier: GridCellIdPB,
#[pb(index = 2, one_of)]
pub insert_option: Option<SelectOptionPB>,
@ -347,7 +347,7 @@ pub struct SelectOptionChangesetPayloadPB {
}
pub struct SelectOptionChangeset {
pub cell_identifier: CellIdentifierParams,
pub cell_identifier: GridCellIdParams,
pub insert_option: Option<SelectOptionPB>,
pub update_option: Option<SelectOptionPB>,
pub delete_option: Option<SelectOptionPB>,

View File

@ -6,49 +6,53 @@ mod tests {
use crate::services::field::{URLCellDataPB, URLTypeOption};
use flowy_grid_data_model::revision::FieldRevision;
/// The expected_str will equal to the input string, but the expected_url will be empty if there's no
/// http url in the input string.
#[test]
fn url_type_option_test_no_url() {
fn url_type_option_does_not_contain_url_test() {
let type_option = URLTypeOption::default();
let field_type = FieldType::URL;
let field_rev = FieldBuilder::from_field_type(&field_type).build();
assert_changeset(&type_option, "123", &field_type, &field_rev, "123", "");
assert_url(&type_option, "123", "123", "", &field_type, &field_rev);
}
/// The expected_str will equal to the input string, but the expected_url will not be empty
/// if there's a http url in the input string.
#[test]
fn url_type_option_test_contains_url() {
fn url_type_option_contains_url_test() {
let type_option = URLTypeOption::default();
let field_type = FieldType::URL;
let field_rev = FieldBuilder::from_field_type(&field_type).build();
assert_changeset(
assert_url(
&type_option,
"AppFlowy website - https://www.appflowy.io",
&field_type,
&field_rev,
"AppFlowy website - https://www.appflowy.io",
"https://www.appflowy.io/",
);
assert_changeset(
&type_option,
"AppFlowy website appflowy.io",
&field_type,
&field_rev,
);
assert_url(
&type_option,
"AppFlowy website appflowy.io",
"AppFlowy website appflowy.io",
"https://appflowy.io",
&field_type,
&field_rev,
);
}
fn assert_changeset(
fn assert_url(
type_option: &URLTypeOption,
cell_data: &str,
input_str: &str,
expected_str: &str,
expected_url: &str,
field_type: &FieldType,
field_rev: &FieldRevision,
expected: &str,
expected_url: &str,
) {
let encoded_data = type_option.apply_changeset(cell_data.to_owned().into(), None).unwrap();
let encoded_data = type_option.apply_changeset(input_str.to_owned().into(), None).unwrap();
let decode_cell_data = decode_cell_data(encoded_data, type_option, field_rev, field_type);
assert_eq!(expected.to_owned(), decode_cell_data.content);
assert_eq!(expected_str.to_owned(), decode_cell_data.content);
assert_eq!(expected_url.to_owned(), decode_cell_data.url);
}

View File

@ -1,5 +1,5 @@
use crate::dart_notification::{send_dart_notification, GridNotification};
use crate::entities::CellIdentifierParams;
use crate::entities::GridCellIdParams;
use crate::entities::*;
use crate::manager::{GridTaskSchedulerRwLock, GridUser};
use crate::services::block_manager::GridBlockManager;
@ -339,12 +339,12 @@ impl GridRevisionEditor {
Ok(())
}
pub async fn get_cell(&self, params: &CellIdentifierParams) -> Option<GridCellPB> {
pub async fn get_cell(&self, params: &GridCellIdParams) -> Option<GridCellPB> {
let cell_bytes = self.get_cell_bytes(params).await?;
Some(GridCellPB::new(&params.field_id, cell_bytes.to_vec()))
}
pub async fn get_cell_bytes(&self, params: &CellIdentifierParams) -> Option<CellBytes> {
pub async fn get_cell_bytes(&self, params: &GridCellIdParams) -> Option<CellBytes> {
let field_rev = self.get_field_rev(&params.field_id).await?;
let row_rev = self.block_manager.get_row_rev(&params.row_id).await.ok()??;

View File

@ -2,7 +2,7 @@ use crate::grid::block_test::script::RowScript::*;
use crate::grid::block_test::script::{CreateRowScriptBuilder, GridRowTest};
use crate::grid::grid_editor::{COMPLETED, FACEBOOK, GOOGLE, PAUSED, TWITTER};
use flowy_grid::entities::FieldType;
use flowy_grid::services::field::{NO, SELECTION_IDS_SEPARATOR};
use flowy_grid::services::field::{SELECTION_IDS_SEPARATOR, UNCHECK};
use flowy_grid_data_model::revision::RowMetaChangeset;
#[tokio::test]
@ -72,7 +72,7 @@ async fn grid_row_add_cells_test() {
builder.insert(FieldType::RichText, "hello world", "hello world");
builder.insert(FieldType::DateTime, "1647251762", "2022/03/14");
builder.insert(FieldType::Number, "18,443", "$18,443.00");
builder.insert(FieldType::Checkbox, "false", NO);
builder.insert(FieldType::Checkbox, "false", UNCHECK);
builder.insert(FieldType::URL, "https://appflowy.io", "https://appflowy.io");
builder.insert_single_select_cell(|mut options| options.remove(0), COMPLETED);
builder.insert_multi_select_cell(

View File

@ -2,7 +2,7 @@ use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow};
use crate::grid::block_test::util::GridRowTestBuilder;
use crate::grid::grid_editor::GridEditorTest;
use flowy_grid::entities::{CellIdentifierParams, FieldType, GridRowPB};
use flowy_grid::entities::{GridCellIdParams, FieldType, GridRowPB};
use flowy_grid::services::field::*;
use flowy_grid_data_model::revision::{
GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision,
@ -109,7 +109,7 @@ impl GridRowTest {
field_type,
expected,
} => {
let id = CellIdentifierParams {
let id = GridCellIdParams {
grid_id: self.grid_id.clone(),
field_id,
row_id,
@ -154,7 +154,7 @@ impl GridRowTest {
}
}
async fn compare_cell_content(&self, cell_id: CellIdentifierParams, field_type: FieldType, expected: String) {
async fn compare_cell_content(&self, cell_id: GridCellIdParams, field_type: FieldType, expected: String) {
match field_type {
FieldType::RichText => {
let cell_data = self