diff --git a/help/demo-organizations.md b/help/demo-organizations.md index 52751af829..5f7469f44b 100644 --- a/help/demo-organizations.md +++ b/help/demo-organizations.md @@ -62,15 +62,35 @@ and set a password for their account. ## Convert a demo organization to a permanent organization +{!owner-only.md!} + +If you'd like to keep your demo organization user and message history, +you can convert it to a permanent Zulip organization. You'll need to +choose a new subdomain for your new permanent organization URL. + +Also, as part of the process of converting a demo organization to a +permanent organization: + +* Users will be logged out of existing sessions on the web, mobile and + desktop apps and need to log in again. +* Any [API clients](/api) or [integrations](/integrations/) will need + to be updated to point to the new organization URL. + {start_tabs} {settings_tab|organization-profile} -1. Click the **Convert organization** link at the end of the red - "This is a demo organization" notice on top. +1. Click the **Convert to make it permanent** link at the end of the + "This demo organization will be automatically deleted ..." notice. -1. Enter the URL you would like to use for the organization and click - **Convert**. +1. Enter the subdomain you would like to use for the new organization + URL and click **Convert**. + +!!! warn "" + + **Note:** You will be logged out when the demo organization is + successfully converted to a permanent Zulip organization and be + redirected to new organization URL log-in page. {end_tabs} diff --git a/tools/lib/capitalization.py b/tools/lib/capitalization.py index 90679140e1..13a24f22f1 100644 --- a/tools/lib/capitalization.py +++ b/tools/lib/capitalization.py @@ -69,6 +69,7 @@ IGNORED_PHRASES = [ r"keyword", r"streamname", r"user@example\.com", + r"acme", # Fragments of larger strings r"your subscriptions on your Streams page", r"Add global time
Everyone sees global times in their own time zone\.", diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 02894f8464..74477484bb 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -82,6 +82,7 @@ EXEMPT_FILES = make_set( "web/src/custom_profile_fields_ui.js", "web/src/dark_theme.ts", "web/src/debug.ts", + "web/src/demo_organizations_ui.js", "web/src/deprecated_feature_notice.ts", "web/src/desktop_integration.js", "web/src/dialog_widget.ts", diff --git a/web/src/admin.js b/web/src/admin.js index ea57b86cb9..786119ac6d 100644 --- a/web/src/admin.js +++ b/web/src/admin.js @@ -4,6 +4,7 @@ import render_admin_tab from "../templates/settings/admin_tab.hbs"; import render_settings_organization_settings_tip from "../templates/settings/organization_settings_tip.hbs"; import * as bot_data from "./bot_data"; +import * as demo_organizations_ui from "./demo_organizations_ui"; import {$t, get_language_name, language_list} from "./i18n"; import {page_params} from "./page_params"; import {realm_user_settings_defaults} from "./realm_user_settings_defaults"; @@ -232,6 +233,11 @@ export function build_page() { settings_invites.update_invite_user_panel(); insert_tip_box(); + if (page_params.demo_organization_scheduled_deletion_date && page_params.is_admin) { + demo_organizations_ui.insert_demo_organization_warning(); + demo_organizations_ui.handle_demo_organization_conversion(); + } + $("#id_realm_bot_creation_policy").val(page_params.realm_bot_creation_policy); $("#id_realm_digest_weekday").val(options.realm_digest_weekday); diff --git a/web/src/demo_organizations_ui.js b/web/src/demo_organizations_ui.js new file mode 100644 index 0000000000..aa7537fcb5 --- /dev/null +++ b/web/src/demo_organizations_ui.js @@ -0,0 +1,107 @@ +import $ from "jquery"; + +import render_convert_demo_organization_form from "../templates/settings/convert_demo_organization_form.hbs"; +import render_demo_organization_warning from "../templates/settings/demo_organization_warning.hbs"; + +import * as channel from "./channel"; +import * as dialog_widget from "./dialog_widget"; +import {$t} from "./i18n"; +import * as keydown_util from "./keydown_util"; +import {get_demo_organization_deadline_days_remaining} from "./navbar_alerts"; +import {page_params} from "./page_params"; +import * as settings_config from "./settings_config"; +import * as settings_data from "./settings_data"; +import * as settings_org from "./settings_org"; + +export function insert_demo_organization_warning() { + const days_remaining = get_demo_organization_deadline_days_remaining(); + const rendered_demo_organization_warning = render_demo_organization_warning({ + is_demo_organization: page_params.demo_organization_scheduled_deletion_date, + is_owner: page_params.is_owner, + days_remaining, + }); + $(".organization-box").find(".settings-section").prepend(rendered_demo_organization_warning); +} + +export function handle_demo_organization_conversion() { + $(".convert-demo-organization-button").on("click", () => { + if (!page_params.is_owner) { + return; + } + + const email_set = !settings_data.user_email_not_configured(); + const parts = new URL(page_params.realm_uri).hostname.split("."); + parts.shift(); + const domain = parts.join("."); + const html_body = render_convert_demo_organization_form({ + realm_domain: domain, + user_has_email_set: email_set, + realm_org_type_values: settings_org.get_org_type_dropdown_options(), + }); + + function demo_organization_conversion_post_render() { + const $convert_submit_button = $( + "#demo-organization-conversion-modal .dialog_submit_button", + ); + $convert_submit_button.prop("disabled", true); + $("#add_organization_type").val(page_params.realm_org_type); + + if (!email_set) { + // Disable form fields if demo organization owner email not set. + $("#add_organization_type").prop("disabled", true); + $("#new_subdomain").prop("disabled", true); + } else { + // Disable submit button if either form field blank. + $("#convert-demo-organization-form").on("input change", () => { + const string_id = $("#new_subdomain").val().trim(); + const org_type = $("#add_organization_type").val(); + $convert_submit_button.prop( + "disabled", + string_id === "" || + Number.parseInt(org_type, 10) === + settings_config.all_org_type_values.unspecified.code, + ); + }); + } + } + + function submit_subdomain() { + const $string_id = $("#new_subdomain"); + const $organization_type = $("#add_organization_type"); + const data = { + string_id: $string_id.val(), + org_type: $organization_type.val(), + }; + const opts = { + success_continuation(data) { + window.location.href = data.realm_uri; + }, + }; + dialog_widget.submit_api_request(channel.patch, "/json/realm", data, opts); + } + + dialog_widget.launch({ + html_heading: $t({defaultMessage: "Make organization permanent"}), + html_body, + on_click: submit_subdomain, + post_render: demo_organization_conversion_post_render, + html_submit_button: $t({defaultMessage: "Convert"}), + id: "demo-organization-conversion-modal", + loading_spinner: true, + help_link: + "/help/demo-organizations#convert-a-demo-organization-to-a-permanent-organization", + }); + }); + + // Treat Enter with convert demo organization link as a click. + $(".demo-organization-warning").on( + "keyup", + ".convert-demo-organization-button[role=button]", + function (e) { + e.stopPropagation(); + if (keydown_util.is_enter_event(e)) { + $(this).trigger("click"); + } + }, + ); +} diff --git a/web/styles/app_components.css b/web/styles/app_components.css index f61b813f22..e155099465 100644 --- a/web/styles/app_components.css +++ b/web/styles/app_components.css @@ -587,6 +587,30 @@ div.overlay { margin-right: 8px; } +.demo-organization-warning { + position: relative; + display: block; + background-color: hsl(4deg 35% 90%); + border: 1px solid hsl(3deg 57% 33% / 40%); + border-radius: 4px; + padding: 10px; + margin: 10px 0; + font-size: 1rem; + line-height: 1.5; + color: hsl(4deg 58% 33%); + + a { + text-decoration: none; + } + + .convert-demo-organization-button { + &:focus { + outline: 1px solid hsl(200deg 100% 25%); + outline-offset: 0; + } + } +} + /* We are mostly consistent in how we style unread counts, except for starred messages. This is the common section. diff --git a/web/styles/dark_theme.css b/web/styles/dark_theme.css index 1d942df20a..ff6d692a03 100644 --- a/web/styles/dark_theme.css +++ b/web/styles/dark_theme.css @@ -13,6 +13,19 @@ @extend .placeholder; } + .demo-organization-warning { + background-color: hsl(0deg 60% 19%); + border-color: hsl(3deg 73% 74% / 40%); + color: hsl(3deg 73% 80%); + + .convert-demo-organization-button { + &:focus { + color: hsl(200deg 79% 66%); + outline-color: hsl(200deg 79% 66%); + } + } + } + & a:hover { color: hsl(200deg 79% 66%); diff --git a/web/styles/settings.css b/web/styles/settings.css index 0e25fcf956..91af685898 100644 --- a/web/styles/settings.css +++ b/web/styles/settings.css @@ -628,6 +628,12 @@ input[type="checkbox"] { } } +#convert-demo-organization-form { + .domain_label { + display: inline-block; + } +} + #profile-settings { .custom-profile-fields-form .custom_user_field label, .full-name-change-container label, diff --git a/web/templates/settings/convert_demo_organization_form.hbs b/web/templates/settings/convert_demo_organization_form.hbs new file mode 100644 index 0000000000..e4834c369b --- /dev/null +++ b/web/templates/settings/convert_demo_organization_form.hbs @@ -0,0 +1,33 @@ +
+
+ {{#unless user_has_email_set}} + {{#tr}} + You must configure your email to access this feature. + {{#*inline "z-link"}}{{> @partial-block }}{{/inline}} + {{/tr}} + {{else}} + {{t "All users will need to log in again at your new organization URL." }} + {{/unless}} +
+ +

{{t "You can convert this demo organization to a permanent Zulip organization. All users and message history will be preserved." }}

+
+
+ + +
+
+ +
+ + +
+
+
+
diff --git a/web/templates/settings/demo_organization_warning.hbs b/web/templates/settings/demo_organization_warning.hbs new file mode 100644 index 0000000000..7a550431da --- /dev/null +++ b/web/templates/settings/demo_organization_warning.hbs @@ -0,0 +1,15 @@ +{{#if is_demo_organization }} +
+ {{#if is_owner }} + {{#tr}} + This demo organization will be automatically deleted in {days_remaining} days, unless it's converted into a permanent organization. + {{#*inline "z-link"}}{{> @partial-block}}{{/inline}} + {{/tr}} + {{else}} + {{#tr}} + This demo organization will be automatically deleted in {days_remaining} days, unless it's converted into a permanent organization. + {{#*inline "z-link"}}{{> @partial-block }}{{/inline}} + {{/tr}} + {{/if}} +
+{{/if}}