mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-01 18:43:22 +00:00
feat: last publish name (#6766)
* chore: wip update client api * feat: add unpublished information * feat: keep the last publish name * test: add re-publish test * test: add empty name test * chore: update cloud version to 0.7.6 --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
parent
cd3be696dc
commit
3b304747f2
1
.github/workflows/ios_ci.yaml
vendored
1
.github/workflows/ios_ci.yaml
vendored
@ -22,7 +22,6 @@ on:
|
||||
env:
|
||||
FLUTTER_VERSION: "3.22.0"
|
||||
RUST_TOOLCHAIN: "1.80.1"
|
||||
CLOUD_VERSION: 0.6.51
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
|
||||
2
.github/workflows/rust_ci.yaml
vendored
2
.github/workflows/rust_ci.yaml
vendored
@ -20,7 +20,7 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
CLOUD_VERSION: 0.6.51-amd64
|
||||
CLOUD_VERSION: 0.7.6-amd64
|
||||
RUST_TOOLCHAIN: "1.77.2"
|
||||
|
||||
jobs:
|
||||
|
||||
@ -106,9 +106,21 @@ void main() {
|
||||
await tester.pumpUntilFound(errorToast2);
|
||||
await tester.pumpUntilNotFound(errorToast2);
|
||||
|
||||
// rename with empty name
|
||||
await tester.tap(inputField);
|
||||
await tester.enterText(inputField, '');
|
||||
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// expect to see the toast with error message
|
||||
final errorToast3 = find.text(
|
||||
LocaleKeys.settings_sites_error_publishNameCannotBeEmpty.tr(),
|
||||
);
|
||||
await tester.pumpUntilFound(errorToast3);
|
||||
await tester.pumpUntilNotFound(errorToast3);
|
||||
|
||||
// input the new path name
|
||||
await tester.tap(inputField);
|
||||
await tester.enterText(inputField, 'new-path-name');
|
||||
// click save button
|
||||
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
|
||||
@ -137,5 +149,72 @@ void main() {
|
||||
isTrue,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('re-publish the document', (tester) async {
|
||||
await tester.initializeAppFlowy(
|
||||
cloudType: AuthenticatorType.appflowyCloudSelfHost,
|
||||
);
|
||||
await tester.tapGoogleLoginInButton();
|
||||
await tester.expectToSeeHomePageWithGetStartedPage();
|
||||
|
||||
const pageName = 'Document';
|
||||
|
||||
await tester.createNewPageInSpace(
|
||||
spaceName: Constants.generalSpaceName,
|
||||
layout: ViewLayoutPB.Document,
|
||||
pageName: pageName,
|
||||
);
|
||||
|
||||
// open the publish menu
|
||||
await tester.openPublishMenu();
|
||||
|
||||
// publish the document
|
||||
final publishButton = find.byType(PublishButton);
|
||||
await tester.tapButton(publishButton);
|
||||
|
||||
// rename the path name
|
||||
final inputField = find.descendant(
|
||||
of: find.byType(ShareMenu),
|
||||
matching: find.byType(TextField),
|
||||
);
|
||||
|
||||
// input the new path name
|
||||
const newName = 'new-path-name';
|
||||
await tester.enterText(inputField, newName);
|
||||
// click save button
|
||||
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// expect to see the toast with success message
|
||||
final successToast = find.text(
|
||||
LocaleKeys.settings_sites_success_updatePathNameSuccess.tr(),
|
||||
);
|
||||
await tester.pumpUntilNotFound(successToast);
|
||||
|
||||
// unpublish the document
|
||||
final unpublishButton = find.byType(UnPublishButton);
|
||||
await tester.tapButton(unpublishButton);
|
||||
|
||||
final unpublishSuccessToast = find.text(
|
||||
LocaleKeys.publish_unpublishSuccessfully.tr(),
|
||||
);
|
||||
await tester.pumpUntilNotFound(unpublishSuccessToast);
|
||||
|
||||
// re-publish the document
|
||||
await tester.tapButton(publishButton);
|
||||
|
||||
// expect to see the toast with success message
|
||||
final rePublishSuccessToast = find.text(
|
||||
LocaleKeys.publish_publishSuccessfully.tr(),
|
||||
);
|
||||
await tester.pumpUntilNotFound(rePublishSuccessToast);
|
||||
|
||||
// check the clipboard has the link
|
||||
final content = await Clipboard.getData(Clipboard.kTextPlain);
|
||||
expect(
|
||||
content?.text?.contains(newName),
|
||||
isTrue,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import 'package:appflowy/plugins/shared/share/constants.dart';
|
||||
import 'package:appflowy/plugins/shared/share/publish_name_generator.dart';
|
||||
import 'package:appflowy/plugins/shared/share/share_bloc.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/util/string_extension.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/prelude.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
@ -97,9 +98,12 @@ class MobileViewPageMoreBottomSheet extends StatelessWidget {
|
||||
|
||||
Future<void> _publish(BuildContext context) async {
|
||||
final id = context.read<ShareBloc>().view.id;
|
||||
final publishName = await generatePublishName(
|
||||
id,
|
||||
view.name,
|
||||
final lastPublishName = context.read<ShareBloc>().state.pathName;
|
||||
final publishName = lastPublishName.orDefault(
|
||||
await generatePublishName(
|
||||
id,
|
||||
view.name,
|
||||
),
|
||||
);
|
||||
if (context.mounted) {
|
||||
context.read<ShareBloc>().add(
|
||||
|
||||
@ -9,6 +9,7 @@ import 'package:appflowy/plugins/shared/share/publish_name_generator.dart';
|
||||
import 'package:appflowy/plugins/shared/share/share_bloc.dart';
|
||||
import 'package:appflowy/shared/error_code/error_code_map.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/util/string_extension.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
@ -50,9 +51,12 @@ class PublishTab extends StatelessWidget {
|
||||
return _PublishWidget(
|
||||
onPublish: (selectedViews) async {
|
||||
final id = context.read<ShareBloc>().view.id;
|
||||
final publishName = await generatePublishName(
|
||||
id,
|
||||
viewName,
|
||||
final lastPublishName = context.read<ShareBloc>().state.pathName;
|
||||
final publishName = lastPublishName.orDefault(
|
||||
await generatePublishName(
|
||||
id,
|
||||
viewName,
|
||||
),
|
||||
);
|
||||
|
||||
if (selectedViews.isNotEmpty) {
|
||||
|
||||
@ -7,6 +7,7 @@ import 'package:appflowy/workspace/application/view/view_listener.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/code.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
@ -188,39 +189,47 @@ class ShareBloc extends Bloc<ShareEvent, ShareState> {
|
||||
(v) => v.authenticator == AuthenticatorPB.AppFlowyCloud,
|
||||
(p) => false,
|
||||
);
|
||||
|
||||
Log.info(
|
||||
'get publish info: $publishInfo for view: ${view.name}(${view.id})',
|
||||
);
|
||||
|
||||
String workspaceId = state.workspaceId;
|
||||
if (workspaceId.isEmpty) {
|
||||
workspaceId = await UserBackendService.getCurrentWorkspace()
|
||||
.fold((s) => s.id, (f) => '');
|
||||
workspaceId = await UserBackendService.getCurrentWorkspace().fold(
|
||||
(s) => s.id,
|
||||
(f) => '',
|
||||
);
|
||||
}
|
||||
publishInfo.fold((s) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPublished: true,
|
||||
namespace: s.namespace,
|
||||
pathName: s.publishName,
|
||||
url: ShareConstants.buildPublishUrl(
|
||||
|
||||
final (isPublished, namespace, pathName, url) = publishInfo.fold(
|
||||
(s) {
|
||||
return (
|
||||
// if the unpublishedAtTimestampSec is not set, it means the view is not unpublished.
|
||||
!s.hasUnpublishedAtTimestampSec(),
|
||||
s.namespace,
|
||||
s.publishName,
|
||||
ShareConstants.buildPublishUrl(
|
||||
nameSpace: s.namespace,
|
||||
publishName: s.publishName,
|
||||
),
|
||||
viewName: view.name,
|
||||
enablePublish: enablePublish,
|
||||
workspaceId: workspaceId,
|
||||
viewId: view.id,
|
||||
),
|
||||
);
|
||||
}, (f) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPublished: false,
|
||||
url: '',
|
||||
viewName: view.name,
|
||||
enablePublish: enablePublish,
|
||||
workspaceId: workspaceId,
|
||||
viewId: view.id,
|
||||
),
|
||||
);
|
||||
});
|
||||
);
|
||||
},
|
||||
(f) => (false, '', '', ''),
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPublished: isPublished,
|
||||
namespace: namespace,
|
||||
pathName: pathName,
|
||||
url: url,
|
||||
viewName: view.name,
|
||||
enablePublish: enablePublish,
|
||||
workspaceId: workspaceId,
|
||||
viewId: view.id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _updatePathName(
|
||||
@ -232,6 +241,21 @@ class ShareBloc extends Bloc<ShareEvent, ShareState> {
|
||||
updatePathNameResult: null,
|
||||
),
|
||||
);
|
||||
|
||||
if (pathName.isEmpty) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
updatePathNameResult: FlowyResult.failure(
|
||||
FlowyError(
|
||||
code: ErrorCode.ViewNameInvalid,
|
||||
msg: 'Path name is invalid',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final request = SetPublishNamePB()
|
||||
..viewId = view.id
|
||||
..newName = pathName;
|
||||
|
||||
@ -14,6 +14,8 @@ extension PublishNameErrorCodeMap on ErrorCode {
|
||||
LocaleKeys.settings_sites_error_publishNameTooLong.tr(),
|
||||
ErrorCode.UserUnauthorized =>
|
||||
LocaleKeys.settings_sites_error_publishPermissionDenied.tr(),
|
||||
ErrorCode.ViewNameInvalid =>
|
||||
LocaleKeys.settings_sites_error_publishNameCannotBeEmpty.tr(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@ -487,7 +487,8 @@
|
||||
"publishNameTooLong": "The path name is too long, please try another one",
|
||||
"publishNameAlreadyInUse": "The path name is already in use, please try another one",
|
||||
"namespaceContainsInvalidCharacters": "The namespace contains invalid character(s), please try another one",
|
||||
"publishPermissionDenied": "Only the workspace owner or page publisher can manage the publish settings"
|
||||
"publishPermissionDenied": "Only the workspace owner or page publisher can manage the publish settings",
|
||||
"publishNameCannotBeEmpty": "The path name cannot be empty, please try another one"
|
||||
},
|
||||
"success": {
|
||||
"namespaceUpdated": "Updated namespace successfully",
|
||||
|
||||
24
frontend/rust-lib/Cargo.lock
generated
24
frontend/rust-lib/Cargo.lock
generated
@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -183,7 +183,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "appflowy-ai-client"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -780,7 +780,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"again",
|
||||
"anyhow",
|
||||
@ -835,7 +835,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"collab-entity",
|
||||
"collab-rt-entity",
|
||||
@ -848,7 +848,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
@ -1117,7 +1117,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -1142,7 +1142,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1537,7 +1537,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -2979,7 +2979,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -2996,7 +2996,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -3358,7 +3358,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -5663,7 +5663,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a#e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ed4c14d53aa77496a68df0875f5f668f278a21bf#ed4c14d53aa77496a68df0875f5f668f278a21bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
|
||||
@ -106,8 +106,8 @@ dashmap = "6.0.1"
|
||||
# Run the script.add_workspace_members:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a" }
|
||||
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "e31e541d07b8ef5e3f33b0b3dd54ebc22a79f86a" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ed4c14d53aa77496a68df0875f5f668f278a21bf" }
|
||||
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ed4c14d53aa77496a68df0875f5f668f278a21bf" }
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
|
||||
@ -74,6 +74,8 @@ pub struct PublishInfoResponsePB {
|
||||
pub publisher_email: String,
|
||||
#[pb(index = 5)]
|
||||
pub publish_timestamp_sec: i64,
|
||||
#[pb(index = 6, one_of)]
|
||||
pub unpublished_at_timestamp_sec: Option<i64>,
|
||||
}
|
||||
|
||||
impl From<PublishInfo> for PublishInfoResponsePB {
|
||||
@ -84,6 +86,7 @@ impl From<PublishInfo> for PublishInfoResponsePB {
|
||||
namespace: Some(info.namespace),
|
||||
publisher_email: info.publisher_email,
|
||||
publish_timestamp_sec: info.publish_timestamp.timestamp(),
|
||||
unpublished_at_timestamp_sec: info.unpublished_timestamp.map(|t| t.timestamp()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user