From 785b043a59cc2c89995d62fb0f3eef7d638fff63 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Tue, 6 May 2025 16:30:07 +0700 Subject: [PATCH 01/19] Add "Where's my project?" page to Lexbox Page content is placeholder for now --- frontend/src/lib/i18n/locales/en.json | 6 +++++ .../layout/FeatureFlagAlternateContent.svelte | 22 ++++++++++++++++++ .../wheresMyProject/+page.svelte | 23 +++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 frontend/src/lib/layout/FeatureFlagAlternateContent.svelte create mode 100644 frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index c2b32d5437..4ef66abaf8 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -668,6 +668,12 @@ If you don't see a dialog or already closed it, click the button below:", "admin": "Admin", "user": "User" }, + "where_is_my_project": { + "title": "Where's my project?", + "body": "**TODO**: Add instructions for clicking on the button on the project page", + "user_not_in_beta": "FieldWorks Lite is currently in beta testing, and open to users who\n\ +ask to be part of the beta. (**TODO**: Add button to request beta access right now).", + }, "errors": { "apology": "Woops, something went wrong on our end. Sorry!", "mail_us_at": "If you're stuck, let us know about this at", diff --git a/frontend/src/lib/layout/FeatureFlagAlternateContent.svelte b/frontend/src/lib/layout/FeatureFlagAlternateContent.svelte new file mode 100644 index 0000000000..eb30742c2f --- /dev/null +++ b/frontend/src/lib/layout/FeatureFlagAlternateContent.svelte @@ -0,0 +1,22 @@ + + + +{#if hasFeatureFlag(page.data.user, flag)} + {@render (hasFlagContent ?? children)?.()} +{:else} + {@render missingFlagContent?.()} +{/if} diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte new file mode 100644 index 0000000000..165d767545 --- /dev/null +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte @@ -0,0 +1,23 @@ + + + + +
+ + {#snippet hasFlagContent()} + + {/snippet} + {#snippet missingFlagContent()} + + {/snippet} + +
+
+ + From 1ebac79bbf2aafd94b7fca5061aaf0db1412ec5f Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Wed, 7 May 2025 12:45:52 +0700 Subject: [PATCH 02/19] Add button to email admins to ask to join beta Email will contain a link to approve the request. Link doesn't yet do anything; that implementation is next. --- backend/LexBoxApi/GraphQL/UserMutations.cs | 28 +++++++++++- .../Services/Email/EmailTemplates.cs | 2 + .../LexBoxApi/Services/Email/IEmailService.cs | 1 + backend/LexBoxApi/Services/EmailService.cs | 8 ++++ frontend/schema.graphql | 13 ++++++ .../lib/email/JoinFWLiteBetaRequest.svelte | 14 ++++++ frontend/src/lib/i18n/locales/en.json | 14 +++++- .../wheresMyProject/+page.svelte | 9 ++++ .../(authenticated)/wheresMyProject/+page.ts | 44 +++++++++++++++++++ frontend/src/routes/email/emails.ts | 9 ++++ 10 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 frontend/src/lib/email/JoinFWLiteBetaRequest.svelte create mode 100644 frontend/src/routes/(authenticated)/wheresMyProject/+page.ts diff --git a/backend/LexBoxApi/GraphQL/UserMutations.cs b/backend/LexBoxApi/GraphQL/UserMutations.cs index bfd107dbfb..e364b5816b 100644 --- a/backend/LexBoxApi/GraphQL/UserMutations.cs +++ b/backend/LexBoxApi/GraphQL/UserMutations.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using System.Security.Cryptography; using LexBoxApi.Auth; using LexBoxApi.Auth.Attributes; @@ -36,6 +36,32 @@ public record CreateGuestUserByAdminInput( string PasswordHash, int PasswordStrength, Guid? OrgId); + public record SendFWLiteBetaRequestEmailInput(Guid UserId, string Name); + + [Error] + [Error] + [Error] + [UseMutationConvention] + [RefreshJwt] + public async Task SendFWLiteBetaRequestEmail( + LoggedInContext loggedInContext, + SendFWLiteBetaRequestEmailInput input, + LexBoxDbContext dbContext, + IEmailService emailService + ) + { + if (loggedInContext.User.Id != input.UserId) throw new UnauthorizedAccessException(); + var user = await dbContext.Users.FindAsync(input.UserId); + NotFoundException.ThrowIfNull(user); + await emailService.SendJoinFWLiteBetaEmail(user); + return new MeDto + { + Id = user.Id, + Name = user.Name, + Email = user.Email, + Locale = user.LocalizationCode + }; + } [Error] [Error] diff --git a/backend/LexBoxApi/Services/Email/EmailTemplates.cs b/backend/LexBoxApi/Services/Email/EmailTemplates.cs index 8f58910a3c..e02b31bcf4 100644 --- a/backend/LexBoxApi/Services/Email/EmailTemplates.cs +++ b/backend/LexBoxApi/Services/Email/EmailTemplates.cs @@ -23,6 +23,7 @@ public enum EmailTemplate CreateProjectRequest, ApproveProjectRequest, UserAdded, + JoinFWLiteBetaRequest, } public record ForgotPasswordEmail(string Name, string ResetUrl, TimeSpan lifetime) : EmailTemplateBase(EmailTemplate.ForgotPassword); @@ -41,3 +42,4 @@ public record CreateProjectRequestUser(string Name, string Email); public record CreateProjectRequestEmail(string Name, CreateProjectRequestUser User, CreateProjectInput Project) : EmailTemplateBase(EmailTemplate.CreateProjectRequest); public record ApproveProjectRequestEmail(string Name, CreateProjectRequestUser User, CreateProjectInput Project) : EmailTemplateBase(EmailTemplate.ApproveProjectRequest); public record UserAddedEmail(string Name, string Email, string ProjectName, string ProjectCode) : EmailTemplateBase(EmailTemplate.UserAdded); +public record JoinFWLiteBetaEmail(string Name, string Email) : EmailTemplateBase(EmailTemplate.JoinFWLiteBetaRequest); diff --git a/backend/LexBoxApi/Services/Email/IEmailService.cs b/backend/LexBoxApi/Services/Email/IEmailService.cs index ba7942a87a..2201b829bb 100644 --- a/backend/LexBoxApi/Services/Email/IEmailService.cs +++ b/backend/LexBoxApi/Services/Email/IEmailService.cs @@ -57,5 +57,6 @@ public Task SendCreateAccountWithProjectEmail( public Task SendCreateProjectRequestEmail(LexAuthUser user, CreateProjectInput projectInput); public Task SendApproveProjectRequestEmail(User user, CreateProjectInput projectInput); public Task SendUserAddedEmail(User user, string projectName, string projectCode); + public Task SendJoinFWLiteBetaEmail(User user); public Task SendEmailAsync(MimeMessage message); } diff --git a/backend/LexBoxApi/Services/EmailService.cs b/backend/LexBoxApi/Services/EmailService.cs index 3fe3c0686a..6baf81c038 100644 --- a/backend/LexBoxApi/Services/EmailService.cs +++ b/backend/LexBoxApi/Services/EmailService.cs @@ -215,6 +215,14 @@ public async Task SendUserAddedEmail(User user, string projectName, string proje await RenderEmail(email, new UserAddedEmail(user.Name, user.Email!, projectName, projectCode), user.LocalizationCode); await SendEmailWithRetriesAsync(email); } + + public async Task SendJoinFWLiteBetaEmail(User user) + { + var email = StartUserEmail("Lexbox Support", "lexbox_support@groups.sil.org"); // TODO: Get from environment + await RenderEmail(email, new JoinFWLiteBetaEmail(user.Name, user.Email ?? ""), user.LocalizationCode); + await SendEmailWithRetriesAsync(email); + } + public async Task SendEmailAsync(MimeMessage message) { message.From.Add(MailboxAddress.Parse(_emailConfig.From)); diff --git a/frontend/schema.graphql b/frontend/schema.graphql index 85a5ca1443..bf1ee599c9 100644 --- a/frontend/schema.graphql +++ b/frontend/schema.graphql @@ -275,6 +275,7 @@ type Mutation { removeProjectMember(input: RemoveProjectMemberInput!): RemoveProjectMemberPayload! @cost(weight: "10") deleteDraftProject(input: DeleteDraftProjectInput!): DeleteDraftProjectPayload! @authorize(policy: "AdminRequiredPolicy") @cost(weight: "10") softDeleteProject(input: SoftDeleteProjectInput!): SoftDeleteProjectPayload! @cost(weight: "10") + sendFWLiteBetaRequestEmail(input: SendFWLiteBetaRequestEmailInput!): SendFWLiteBetaRequestEmailPayload! @cost(weight: "10") changeUserAccountBySelf(input: ChangeUserAccountBySelfInput!): ChangeUserAccountBySelfPayload! @cost(weight: "10") changeUserAccountByAdmin(input: ChangeUserAccountByAdminInput!): ChangeUserAccountByAdminPayload! @authorize(policy: "AdminRequiredPolicy") @cost(weight: "10") sendNewVerificationEmailByAdmin(input: SendNewVerificationEmailByAdminInput!): SendNewVerificationEmailByAdminPayload! @authorize(policy: "AdminRequiredPolicy") @cost(weight: "10") @@ -493,6 +494,11 @@ type RequiredError implements Error { message: String! } +type SendFWLiteBetaRequestEmailPayload { + meDto: MeDto + errors: [SendFWLiteBetaRequestEmailError!] +} + type SendNewVerificationEmailByAdminPayload { user: User errors: [SendNewVerificationEmailByAdminError!] @@ -645,6 +651,8 @@ union LeaveProjectError = NotFoundError | LastMemberCantLeaveError union RemoveProjectFromOrgError = DbError | NotFoundError +union SendFWLiteBetaRequestEmailError = NotFoundError | DbError | UniqueValueError + union SendNewVerificationEmailByAdminError = NotFoundError | DbError | InvalidOperationError union SetOrgMemberRoleError = DbError | NotFoundError | OrgMemberInvitedByEmail | OrgMembersMustBeVerified | OrgMembersMustBeVerifiedForRole @@ -1094,6 +1102,11 @@ input RetentionPolicyOperationFilterInput { nin: [RetentionPolicy!] @cost(weight: "10") } +input SendFWLiteBetaRequestEmailInput { + userId: UUID! + name: String! +} + input SendNewVerificationEmailByAdminInput { userId: UUID! } diff --git a/frontend/src/lib/email/JoinFWLiteBetaRequest.svelte b/frontend/src/lib/email/JoinFWLiteBetaRequest.svelte new file mode 100644 index 0000000000..e5e4f4b97c --- /dev/null +++ b/frontend/src/lib/email/JoinFWLiteBetaRequest.svelte @@ -0,0 +1,14 @@ + + + + {$t('emails.join_fw_lite_beta_request_email.body', { name })} + {$t('emails.join_fw_lite_beta_request_email.approve_button')} + diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 4ef66abaf8..01ae32ec09 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -670,9 +670,14 @@ If you don't see a dialog or already closed it, click the button below:", }, "where_is_my_project": { "title": "Where's my project?", - "body": "**TODO**: Add instructions for clicking on the button on the project page", + "body": "If you don't see your project in FieldWorks Lite, please go to the project page on Lexbox and look for the \"Try FieldWorks Lite?\" button\n\ +near the top of the page. Click on that button and your project's data will be imported into FieldWorks Lite. This process may take a few minutes, but when\n\ +it's done, you should see your project in FieldWorks Lite and be able to use it.", "user_not_in_beta": "FieldWorks Lite is currently in beta testing, and open to users who\n\ -ask to be part of the beta. (**TODO**: Add button to request beta access right now).", +have chosen to be part of the beta. If you want to try FieldWorks Lite, please click the button below\n\ +to ask to join the beta test. Depending on what time zone you're in, it might take a day or two for us\n\ +to see your email and respond.", + "request_beta_access": "I want to help test FieldWorks Lite", }, "errors": { "apology": "Woops, something went wrong on our end. Sorry!", @@ -742,6 +747,11 @@ ask to be part of the beta. (**TODO**: Add button to request beta access right n "heading": "The project you requested, {projectName}, has been approved and created.", "view_button": "View Project" }, + "join_fw_lite_beta_request_email": { + "subject": "FW Lite Beta join request: {name} wants to join the FW Lite beta", + "body": "User {name} requested to join the FW Lite beta. Click below to approve this request.", + "approve_button": "Approve Request" + }, "user_added": { "subject": "You joined project: {projectName}!", "body": "You have been added to the project: {projectName}.", diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte index 165d767545..c1f7e758f5 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte @@ -3,6 +3,14 @@ import t from '$lib/i18n'; import Markdown from 'svelte-exmarkdown'; import FeatureFlagAlternateContent from '$lib/layout/FeatureFlagAlternateContent.svelte'; + import Button from '$lib/forms/Button.svelte'; + import { page } from '$app/state'; + import { _sendFWLiteBetaRequestEmail } from './+page'; + import type {UUID} from 'crypto'; + + async function requestBetaAccess(): Promise { + await _sendFWLiteBetaRequestEmail(page.data.user.id as UUID, page.data.user.name); + } @@ -14,6 +22,7 @@ {/snippet} {#snippet missingFlagContent()} + {/snippet} diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts new file mode 100644 index 0000000000..48d2d5042c --- /dev/null +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts @@ -0,0 +1,44 @@ +import { getClient, graphql } from '$lib/gql'; + +// import type {PageLoadEvent} from './$types'; +// import {type LexAuthUser} from '$lib/user'; +// import {redirect} from '@sveltejs/kit'; +// import {getBoolSearchParam, getSearchParam} from '$lib/util/query-params'; +// import {isGuid} from '$lib/util/guid'; +import type { + $OpResult, + SendFwLiteBetaRequestEmailPayload, + // SendFwLiteBetaRequestEmailMutation, // TODO Why isn't this one being created? +} from '$lib/gql/types'; +// import type {LoadAdminDashboardProjectsQuery, LoadAdminDashboardUsersQuery} from '$lib/gql/types'; +// import type {ProjectFilters} from '$lib/components/Projects'; +// import {DEFAULT_PAGE_SIZE} from '$lib/components/Paging'; +// import type {AdminTabId} from './AdminTabs.svelte'; +// import {derived, readable} from 'svelte/store'; +// import type {UserType} from '$lib/components/Users/UserFilter.svelte'; +import type { UUID } from 'crypto'; + +export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $OpResult { // SendFwLiteBetaRequestEmailPayload + //language=GraphQL + const result = await getClient() + .mutation( + graphql(` + mutation SendFWLiteBetaRequestEmail($input: SendFwLiteBetaRequestEmailInput!) { + sendFWLiteBetaRequestEmail(input: $input) + user { + id + email + } + errors { + __typename + ... on Error { + message + } + } + } + } + `), + { input: { userId, name } } + ) + return result; +} diff --git a/frontend/src/routes/email/emails.ts b/frontend/src/routes/email/emails.ts index 0e846ecfb5..efdde2a5ec 100644 --- a/frontend/src/routes/email/emails.ts +++ b/frontend/src/routes/email/emails.ts @@ -3,6 +3,7 @@ import NewAdmin from '$lib/email/NewAdmin.svelte'; import VerifyEmailAddress from '$lib/email/VerifyEmailAddress.svelte'; import PasswordChanged from '$lib/email/PasswordChanged.svelte'; import JoinProjectRequest from '$lib/email/JoinProjectRequest.svelte'; +import JoinFWLiteBetaRequest from '$lib/email/JoinFWLiteBetaRequest.svelte'; import CreateProjectRequest from '$lib/email/CreateProjectRequest.svelte'; import type {CreateProjectInput} from '$lib/gql/generated/graphql'; import ApproveProjectRequest from '$lib/email/ApproveProjectRequest.svelte'; @@ -21,6 +22,7 @@ export const enum EmailTemplate { JoinProjectRequest = 'JOIN_PROJECT_REQUEST', CreateProjectRequest = 'CREATE_PROJECT_REQUEST', ApproveProjectRequest = 'APPROVE_PROJECT_REQUEST', + JoinFWLiteBetaRequest = 'JOIN_FW_LITE_BETA_REQUEST', UserAdded = 'USER_ADDED', } @@ -34,6 +36,7 @@ export const componentMap = { [EmailTemplate.JoinProjectRequest]: JoinProjectRequest, [EmailTemplate.CreateProjectRequest]: CreateProjectRequest, [EmailTemplate.ApproveProjectRequest]: ApproveProjectRequest, + [EmailTemplate.JoinFWLiteBetaRequest]: JoinFWLiteBetaRequest, [EmailTemplate.UserAdded]: UserAdded, } satisfies Record>; // Note: Foo means "Foo but I don't care what T is" and is apparently preferred over Foo in modern Typescript @@ -97,6 +100,11 @@ interface UserAddedProps extends EmailTemplatePropsBase projectCode: string; } +interface JoinFWLiteBetaRequestProps extends EmailTemplatePropsBase { + name: string; + userId: string; +} + export type EmailTemplateProps = ForgotPasswordProps | NewAdminProps @@ -107,4 +115,5 @@ export type EmailTemplateProps = | CreateProjectProps | ApproveProjectProps | UserAddedProps + | JoinFWLiteBetaRequestProps | EmailTemplatePropsBase; From e4520de63ebd6c4786fbd2c298e5c1c143293f42 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Wed, 7 May 2025 13:30:21 +0700 Subject: [PATCH 03/19] Beware inconsistent capitalization: FW vs Fw --- frontend/src/routes/(authenticated)/wheresMyProject/+page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts index 48d2d5042c..91e0a0ef68 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts @@ -23,7 +23,7 @@ export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $ const result = await getClient() .mutation( graphql(` - mutation SendFWLiteBetaRequestEmail($input: SendFwLiteBetaRequestEmailInput!) { + mutation SendFWLiteBetaRequestEmail($input: SendFWLiteBetaRequestEmailInput!) { sendFWLiteBetaRequestEmail(input: $input) user { id From 70328e95b01cca0a34e082793662c686a4aa227d Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Wed, 7 May 2025 08:56:16 +0200 Subject: [PATCH 04/19] Make FwLiteBetaRequestEmail mutation happy --- .../(authenticated)/wheresMyProject/+page.ts | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts index 91e0a0ef68..75809d073e 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts @@ -1,31 +1,16 @@ -import { getClient, graphql } from '$lib/gql'; +import type {$OpResult, SendFwLiteBetaRequestEmailMutation} from '$lib/gql/types'; +import {getClient, graphql} from '$lib/gql'; -// import type {PageLoadEvent} from './$types'; -// import {type LexAuthUser} from '$lib/user'; -// import {redirect} from '@sveltejs/kit'; -// import {getBoolSearchParam, getSearchParam} from '$lib/util/query-params'; -// import {isGuid} from '$lib/util/guid'; -import type { - $OpResult, - SendFwLiteBetaRequestEmailPayload, - // SendFwLiteBetaRequestEmailMutation, // TODO Why isn't this one being created? -} from '$lib/gql/types'; -// import type {LoadAdminDashboardProjectsQuery, LoadAdminDashboardUsersQuery} from '$lib/gql/types'; -// import type {ProjectFilters} from '$lib/components/Projects'; -// import {DEFAULT_PAGE_SIZE} from '$lib/components/Paging'; -// import type {AdminTabId} from './AdminTabs.svelte'; -// import {derived, readable} from 'svelte/store'; -// import type {UserType} from '$lib/components/Users/UserFilter.svelte'; -import type { UUID } from 'crypto'; +import type {UUID} from 'crypto'; -export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $OpResult { // SendFwLiteBetaRequestEmailPayload +export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $OpResult { // SendFwLiteBetaRequestEmailPayload //language=GraphQL const result = await getClient() .mutation( graphql(` mutation SendFWLiteBetaRequestEmail($input: SendFWLiteBetaRequestEmailInput!) { - sendFWLiteBetaRequestEmail(input: $input) - user { + sendFWLiteBetaRequestEmail(input: $input) { + meDto { id email } @@ -38,7 +23,7 @@ export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $ } } `), - { input: { userId, name } } + {input: {userId, name}} ) return result; } From 3a49d6258b14eb89b96ca92630d34d1d4ae86114 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Thu, 8 May 2025 09:24:08 +0700 Subject: [PATCH 05/19] Fix up code after Svelte 5 migration --- .../src/routes/(authenticated)/wheresMyProject/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte index c1f7e758f5..ace96a9b54 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte @@ -22,7 +22,7 @@ {/snippet} {#snippet missingFlagContent()} - + {/snippet} From 9be8cbfeba4d64d0bf17435c0eb5d4aafc074d50 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Thu, 8 May 2025 09:38:14 +0700 Subject: [PATCH 06/19] Remove now-unnecessary comment --- frontend/src/routes/(authenticated)/wheresMyProject/+page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts index 75809d073e..25b3ce9a81 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts @@ -3,7 +3,7 @@ import {getClient, graphql} from '$lib/gql'; import type {UUID} from 'crypto'; -export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $OpResult { // SendFwLiteBetaRequestEmailPayload +export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $OpResult { //language=GraphQL const result = await getClient() .mutation( From 20387b43303dadc696529c29f7c1a609cbd65384 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Tue, 13 May 2025 10:59:36 +0700 Subject: [PATCH 07/19] Add "Where's my project?" link in FW Lite --- frontend/viewer/src/home/HomeView.svelte | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontend/viewer/src/home/HomeView.svelte b/frontend/viewer/src/home/HomeView.svelte index 5f7072c6b4..dd60168850 100644 --- a/frontend/viewer/src/home/HomeView.svelte +++ b/frontend/viewer/src/home/HomeView.svelte @@ -206,6 +206,15 @@ + {#if projects.some((p) => p.fwdata)}

{$t`Classic FieldWorks Projects`}

From cad870bd288820632344849013f02cc51245581a Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Tue, 13 May 2025 13:51:06 +0700 Subject: [PATCH 08/19] Rename JoinFWLite to JoinFwLite for less ambiguity Serialization of C# enums was a little ambiguous when the name was FWLite, so FwLite removes all ambiguity re how the name will end up. --- backend/LexBoxApi/GraphQL/UserMutations.cs | 2 +- backend/LexBoxApi/Services/Email/EmailTemplates.cs | 4 ++-- backend/LexBoxApi/Services/Email/IEmailService.cs | 2 +- backend/LexBoxApi/Services/EmailService.cs | 4 ++-- ...BetaRequest.svelte => JoinFwLiteBetaRequest.svelte} | 2 +- frontend/src/routes/email/emails.ts | 10 +++++----- frontend/src/routes/email/tester/+page@.svelte | 7 +++++++ 7 files changed, 19 insertions(+), 12 deletions(-) rename frontend/src/lib/email/{JoinFWLiteBetaRequest.svelte => JoinFwLiteBetaRequest.svelte} (81%) diff --git a/backend/LexBoxApi/GraphQL/UserMutations.cs b/backend/LexBoxApi/GraphQL/UserMutations.cs index e364b5816b..276adab900 100644 --- a/backend/LexBoxApi/GraphQL/UserMutations.cs +++ b/backend/LexBoxApi/GraphQL/UserMutations.cs @@ -53,7 +53,7 @@ IEmailService emailService if (loggedInContext.User.Id != input.UserId) throw new UnauthorizedAccessException(); var user = await dbContext.Users.FindAsync(input.UserId); NotFoundException.ThrowIfNull(user); - await emailService.SendJoinFWLiteBetaEmail(user); + await emailService.SendJoinFwLiteBetaEmail(user); return new MeDto { Id = user.Id, diff --git a/backend/LexBoxApi/Services/Email/EmailTemplates.cs b/backend/LexBoxApi/Services/Email/EmailTemplates.cs index e02b31bcf4..b60ec1508f 100644 --- a/backend/LexBoxApi/Services/Email/EmailTemplates.cs +++ b/backend/LexBoxApi/Services/Email/EmailTemplates.cs @@ -23,7 +23,7 @@ public enum EmailTemplate CreateProjectRequest, ApproveProjectRequest, UserAdded, - JoinFWLiteBetaRequest, + JoinFwLiteBetaRequest, } public record ForgotPasswordEmail(string Name, string ResetUrl, TimeSpan lifetime) : EmailTemplateBase(EmailTemplate.ForgotPassword); @@ -42,4 +42,4 @@ public record CreateProjectRequestUser(string Name, string Email); public record CreateProjectRequestEmail(string Name, CreateProjectRequestUser User, CreateProjectInput Project) : EmailTemplateBase(EmailTemplate.CreateProjectRequest); public record ApproveProjectRequestEmail(string Name, CreateProjectRequestUser User, CreateProjectInput Project) : EmailTemplateBase(EmailTemplate.ApproveProjectRequest); public record UserAddedEmail(string Name, string Email, string ProjectName, string ProjectCode) : EmailTemplateBase(EmailTemplate.UserAdded); -public record JoinFWLiteBetaEmail(string Name, string Email) : EmailTemplateBase(EmailTemplate.JoinFWLiteBetaRequest); +public record JoinFwLiteBetaEmail(string Name, string Email) : EmailTemplateBase(EmailTemplate.JoinFwLiteBetaRequest); diff --git a/backend/LexBoxApi/Services/Email/IEmailService.cs b/backend/LexBoxApi/Services/Email/IEmailService.cs index 2201b829bb..de26b3622e 100644 --- a/backend/LexBoxApi/Services/Email/IEmailService.cs +++ b/backend/LexBoxApi/Services/Email/IEmailService.cs @@ -57,6 +57,6 @@ public Task SendCreateAccountWithProjectEmail( public Task SendCreateProjectRequestEmail(LexAuthUser user, CreateProjectInput projectInput); public Task SendApproveProjectRequestEmail(User user, CreateProjectInput projectInput); public Task SendUserAddedEmail(User user, string projectName, string projectCode); - public Task SendJoinFWLiteBetaEmail(User user); + public Task SendJoinFwLiteBetaEmail(User user); public Task SendEmailAsync(MimeMessage message); } diff --git a/backend/LexBoxApi/Services/EmailService.cs b/backend/LexBoxApi/Services/EmailService.cs index 6baf81c038..2e9b954ebc 100644 --- a/backend/LexBoxApi/Services/EmailService.cs +++ b/backend/LexBoxApi/Services/EmailService.cs @@ -216,10 +216,10 @@ public async Task SendUserAddedEmail(User user, string projectName, string proje await SendEmailWithRetriesAsync(email); } - public async Task SendJoinFWLiteBetaEmail(User user) + public async Task SendJoinFwLiteBetaEmail(User user) { var email = StartUserEmail("Lexbox Support", "lexbox_support@groups.sil.org"); // TODO: Get from environment - await RenderEmail(email, new JoinFWLiteBetaEmail(user.Name, user.Email ?? ""), user.LocalizationCode); + await RenderEmail(email, new JoinFwLiteBetaEmail(user.Name, user.Email ?? ""), user.LocalizationCode); await SendEmailWithRetriesAsync(email); } diff --git a/frontend/src/lib/email/JoinFWLiteBetaRequest.svelte b/frontend/src/lib/email/JoinFwLiteBetaRequest.svelte similarity index 81% rename from frontend/src/lib/email/JoinFWLiteBetaRequest.svelte rename to frontend/src/lib/email/JoinFwLiteBetaRequest.svelte index e5e4f4b97c..1ab78f7fd6 100644 --- a/frontend/src/lib/email/JoinFWLiteBetaRequest.svelte +++ b/frontend/src/lib/email/JoinFwLiteBetaRequest.svelte @@ -5,7 +5,7 @@ export let name: string; export let email: string; export let baseUrl: string; - let approveUrl = new URL(`/admin/approveFWBetaRequest?userEmail=${encodeURIComponent(email)}`, baseUrl); + let approveUrl = new URL(`/admin/?userSearch=${encodeURIComponent(email)}`, baseUrl); diff --git a/frontend/src/routes/email/emails.ts b/frontend/src/routes/email/emails.ts index efdde2a5ec..0931077bff 100644 --- a/frontend/src/routes/email/emails.ts +++ b/frontend/src/routes/email/emails.ts @@ -3,7 +3,7 @@ import NewAdmin from '$lib/email/NewAdmin.svelte'; import VerifyEmailAddress from '$lib/email/VerifyEmailAddress.svelte'; import PasswordChanged from '$lib/email/PasswordChanged.svelte'; import JoinProjectRequest from '$lib/email/JoinProjectRequest.svelte'; -import JoinFWLiteBetaRequest from '$lib/email/JoinFWLiteBetaRequest.svelte'; +import JoinFwLiteBetaRequest from '$lib/email/JoinFwLiteBetaRequest.svelte'; import CreateProjectRequest from '$lib/email/CreateProjectRequest.svelte'; import type {CreateProjectInput} from '$lib/gql/generated/graphql'; import ApproveProjectRequest from '$lib/email/ApproveProjectRequest.svelte'; @@ -22,7 +22,7 @@ export const enum EmailTemplate { JoinProjectRequest = 'JOIN_PROJECT_REQUEST', CreateProjectRequest = 'CREATE_PROJECT_REQUEST', ApproveProjectRequest = 'APPROVE_PROJECT_REQUEST', - JoinFWLiteBetaRequest = 'JOIN_FW_LITE_BETA_REQUEST', + JoinFwLiteBetaRequest = 'JOIN_FW_LITE_BETA_REQUEST', UserAdded = 'USER_ADDED', } @@ -36,7 +36,7 @@ export const componentMap = { [EmailTemplate.JoinProjectRequest]: JoinProjectRequest, [EmailTemplate.CreateProjectRequest]: CreateProjectRequest, [EmailTemplate.ApproveProjectRequest]: ApproveProjectRequest, - [EmailTemplate.JoinFWLiteBetaRequest]: JoinFWLiteBetaRequest, + [EmailTemplate.JoinFwLiteBetaRequest]: JoinFwLiteBetaRequest, [EmailTemplate.UserAdded]: UserAdded, } satisfies Record>; // Note: Foo means "Foo but I don't care what T is" and is apparently preferred over Foo in modern Typescript @@ -100,7 +100,7 @@ interface UserAddedProps extends EmailTemplatePropsBase projectCode: string; } -interface JoinFWLiteBetaRequestProps extends EmailTemplatePropsBase { +interface JoinFwLiteBetaRequestProps extends EmailTemplatePropsBase { name: string; userId: string; } @@ -115,5 +115,5 @@ export type EmailTemplateProps = | CreateProjectProps | ApproveProjectProps | UserAddedProps - | JoinFWLiteBetaRequestProps + | JoinFwLiteBetaRequestProps | EmailTemplatePropsBase; diff --git a/frontend/src/routes/email/tester/+page@.svelte b/frontend/src/routes/email/tester/+page@.svelte index d193cdd54d..43a0f8c190 100644 --- a/frontend/src/routes/email/tester/+page@.svelte +++ b/frontend/src/routes/email/tester/+page@.svelte @@ -17,6 +17,13 @@ resetUrl: absoluteUrl('resetPassword'), lifetime: '3.00:00:00', // 3 days }, + { + template: EmailTemplate.JoinFwLiteBetaRequest, + label: 'Join FW Lite Beta', + baseUrl: location.origin, + name: 'Test Editor', + email: 'editor@test.com', + }, { template: EmailTemplate.VerifyEmailAddress, name: 'Bob', From f777cb0e87ed1c87e2d307c48512fbd766b30c11 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Tue, 13 May 2025 14:20:04 +0700 Subject: [PATCH 09/19] Add rename that got accidentally reverted --- frontend/src/routes/email/emails.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/email/emails.ts b/frontend/src/routes/email/emails.ts index 0931077bff..6a4f8ea3f5 100644 --- a/frontend/src/routes/email/emails.ts +++ b/frontend/src/routes/email/emails.ts @@ -102,7 +102,7 @@ interface UserAddedProps extends EmailTemplatePropsBase interface JoinFwLiteBetaRequestProps extends EmailTemplatePropsBase { name: string; - userId: string; + email: string; } export type EmailTemplateProps = From 6ec13afa121505033f1eb5aa47a458b0069cb3c5 Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Thu, 15 May 2025 15:44:07 +0200 Subject: [PATCH 10/19] Touch up buttons --- .../wheresMyProject/+page.svelte | 4 ++- frontend/viewer/src/home/HomeView.svelte | 9 ------- frontend/viewer/src/home/Server.svelte | 27 +++++++++++++------ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte index ace96a9b54..94ccb472f0 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte @@ -22,7 +22,9 @@ {/snippet} {#snippet missingFlagContent()} - +
+ +
{/snippet}
diff --git a/frontend/viewer/src/home/HomeView.svelte b/frontend/viewer/src/home/HomeView.svelte index dd60168850..5f7072c6b4 100644 --- a/frontend/viewer/src/home/HomeView.svelte +++ b/frontend/viewer/src/home/HomeView.svelte @@ -206,15 +206,6 @@ - {#if projects.some((p) => p.fwdata)}

{$t`Classic FieldWorks Projects`}

diff --git a/frontend/viewer/src/home/Server.svelte b/frontend/viewer/src/home/Server.svelte index 809cf04e91..d3cd2dc311 100644 --- a/frontend/viewer/src/home/Server.svelte +++ b/frontend/viewer/src/home/Server.svelte @@ -4,11 +4,13 @@ import {createEventDispatcher} from 'svelte'; import {mdiBookArrowDownOutline, mdiBookSyncOutline, mdiCloud, mdiRefresh} from '@mdi/js'; import LoginButton from '$lib/auth/LoginButton.svelte'; - import {Button, ListItem, Settings} from 'svelte-ux'; + import {Button as UxButton, ListItem, Settings} from 'svelte-ux'; import ButtonListItem from '$lib/utils/ButtonListItem.svelte'; import {useProjectsService} from '$lib/services/service-provider'; import {t} from 'svelte-i18n-lingui'; import ProjectTitle from './ProjectTitle.svelte'; + import {Button} from '$lib/components/ui/button'; + import {Icon} from '$lib/components/ui/icon'; const projectsService = useProjectsService(); @@ -55,7 +57,7 @@
{#if status?.loggedIn} - {:else} dispatch('refreshAll')}/> {/if} @@ -93,9 +98,9 @@ title={project.name} loading={downloading === project.name}>
- +
@@ -106,14 +111,20 @@ {loading}>
- +
{/if} {/each} +
+ +
{/if} From af9c45ccbafe68f8489f09334b41fbb7a902f223 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Mon, 19 May 2025 16:21:07 +0700 Subject: [PATCH 11/19] Accept wording improvements suggested by Tim --- frontend/src/lib/i18n/locales/en.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 01ae32ec09..6246053791 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -669,14 +669,13 @@ If you don't see a dialog or already closed it, click the button below:", "user": "User" }, "where_is_my_project": { - "title": "Where's my project?", - "body": "If you don't see your project in FieldWorks Lite, please go to the project page on Lexbox and look for the \"Try FieldWorks Lite?\" button\n\ -near the top of the page. Click on that button and your project's data will be imported into FieldWorks Lite. This process may take a few minutes, but when\n\ + "title": "FieldWorks Lite - Where's my project?", + "body": "If you don't see your project in FieldWorks Lite, navigate to the project here on Lexbox and look for the \"Try FieldWorks Lite?\" button\n\ +near the top of the page. Use that button to make your project available in FieldWorks Lite. This process may take a few minutes. When\n\ it's done, you should see your project in FieldWorks Lite and be able to use it.", - "user_not_in_beta": "FieldWorks Lite is currently in beta testing, and open to users who\n\ -have chosen to be part of the beta. If you want to try FieldWorks Lite, please click the button below\n\ -to ask to join the beta test. Depending on what time zone you're in, it might take a day or two for us\n\ -to see your email and respond.", + "user_not_in_beta": ""FieldWorks Lite is currently in a beta testing phase. \n\ +Only selected early access users can download Lexbox projects in FieldWorks Lite. \n\ +Click the button below to request to join the early access program. It may take a few days for us to respond.", "request_beta_access": "I want to help test FieldWorks Lite", }, "errors": { From 64fb1ac3d1cf8d1a5889bd5bdc24130389507d2e Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Mon, 19 May 2025 16:25:00 +0700 Subject: [PATCH 12/19] One more wording improvement --- frontend/src/lib/i18n/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 6246053791..1fd6e41b3f 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -676,7 +676,7 @@ it's done, you should see your project in FieldWorks Lite and be able to use it. "user_not_in_beta": ""FieldWorks Lite is currently in a beta testing phase. \n\ Only selected early access users can download Lexbox projects in FieldWorks Lite. \n\ Click the button below to request to join the early access program. It may take a few days for us to respond.", - "request_beta_access": "I want to help test FieldWorks Lite", + "request_beta_access": "Request early access to FieldWorks Lite", }, "errors": { "apology": "Woops, something went wrong on our end. Sorry!", From 948df48113068c6f40197ee8ef1f1eb2191cb197 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Mon, 19 May 2025 16:26:33 +0700 Subject: [PATCH 13/19] Fix en.json typo --- frontend/src/lib/i18n/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 1fd6e41b3f..c88d93df84 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -673,7 +673,7 @@ If you don't see a dialog or already closed it, click the button below:", "body": "If you don't see your project in FieldWorks Lite, navigate to the project here on Lexbox and look for the \"Try FieldWorks Lite?\" button\n\ near the top of the page. Use that button to make your project available in FieldWorks Lite. This process may take a few minutes. When\n\ it's done, you should see your project in FieldWorks Lite and be able to use it.", - "user_not_in_beta": ""FieldWorks Lite is currently in a beta testing phase. \n\ + "user_not_in_beta": "FieldWorks Lite is currently in a beta testing phase. \n\ Only selected early access users can download Lexbox projects in FieldWorks Lite. \n\ Click the button below to request to join the early access program. It may take a few days for us to respond.", "request_beta_access": "Request early access to FieldWorks Lite", From 3b90ddf2fdbc75fb08d959725529e84ea771316e Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Mon, 19 May 2025 17:17:09 +0700 Subject: [PATCH 14/19] Add notification when request email is sent Also notify user if they were already in the beta, in which case no email was sent. --- backend/LexBoxApi/GraphQL/UserMutations.cs | 21 ++++++++++--------- frontend/schema.graphql | 9 ++++++-- frontend/src/lib/i18n/locales/en.json | 2 ++ .../wheresMyProject/+page.svelte | 19 +++++++++++++++-- .../(authenticated)/wheresMyProject/+page.ts | 7 ++----- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/backend/LexBoxApi/GraphQL/UserMutations.cs b/backend/LexBoxApi/GraphQL/UserMutations.cs index 276adab900..219a39982d 100644 --- a/backend/LexBoxApi/GraphQL/UserMutations.cs +++ b/backend/LexBoxApi/GraphQL/UserMutations.cs @@ -37,13 +37,16 @@ public record CreateGuestUserByAdminInput( int PasswordStrength, Guid? OrgId); public record SendFWLiteBetaRequestEmailInput(Guid UserId, string Name); + public enum SendFWLiteBetaRequestEmailResult + { + UserAlreadyInBeta, + BetaAccessRequestSent, + }; [Error] - [Error] - [Error] [UseMutationConvention] [RefreshJwt] - public async Task SendFWLiteBetaRequestEmail( + public async Task SendFWLiteBetaRequestEmail( LoggedInContext loggedInContext, SendFWLiteBetaRequestEmailInput input, LexBoxDbContext dbContext, @@ -53,14 +56,12 @@ IEmailService emailService if (loggedInContext.User.Id != input.UserId) throw new UnauthorizedAccessException(); var user = await dbContext.Users.FindAsync(input.UserId); NotFoundException.ThrowIfNull(user); - await emailService.SendJoinFwLiteBetaEmail(user); - return new MeDto + if (user.FeatureFlags.Contains(FeatureFlag.FwLiteBeta)) { - Id = user.Id, - Name = user.Name, - Email = user.Email, - Locale = user.LocalizationCode - }; + return SendFWLiteBetaRequestEmailResult.UserAlreadyInBeta; + } + await emailService.SendJoinFwLiteBetaEmail(user); + return SendFWLiteBetaRequestEmailResult.BetaAccessRequestSent; } [Error] diff --git a/frontend/schema.graphql b/frontend/schema.graphql index bf1ee599c9..eb050a867c 100644 --- a/frontend/schema.graphql +++ b/frontend/schema.graphql @@ -495,7 +495,7 @@ type RequiredError implements Error { } type SendFWLiteBetaRequestEmailPayload { - meDto: MeDto + sendFWLiteBetaRequestEmailResult: SendFWLiteBetaRequestEmailResult errors: [SendFWLiteBetaRequestEmailError!] } @@ -651,7 +651,7 @@ union LeaveProjectError = NotFoundError | LastMemberCantLeaveError union RemoveProjectFromOrgError = DbError | NotFoundError -union SendFWLiteBetaRequestEmailError = NotFoundError | DbError | UniqueValueError +union SendFWLiteBetaRequestEmailError = NotFoundError union SendNewVerificationEmailByAdminError = NotFoundError | DbError | InvalidOperationError @@ -1295,6 +1295,11 @@ enum RetentionPolicy { TRAINING } +enum SendFWLiteBetaRequestEmailResult { + USER_ALREADY_IN_BETA + BETA_ACCESS_REQUEST_SENT +} + enum SortEnumType { ASC DESC diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index c88d93df84..11091eea11 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -677,6 +677,8 @@ it's done, you should see your project in FieldWorks Lite and be able to use it. Only selected early access users can download Lexbox projects in FieldWorks Lite. \n\ Click the button below to request to join the early access program. It may take a few days for us to respond.", "request_beta_access": "Request early access to FieldWorks Lite", + "access_request_sent": "Early access request has been sent", + "already_in_beta": "You're already in the early access program", }, "errors": { "apology": "Woops, something went wrong on our end. Sorry!", diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte index 94ccb472f0..493b51d929 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte @@ -6,10 +6,25 @@ import Button from '$lib/forms/Button.svelte'; import { page } from '$app/state'; import { _sendFWLiteBetaRequestEmail } from './+page'; - import type {UUID} from 'crypto'; + import type { UUID } from 'crypto'; + import { SendFwLiteBetaRequestEmailResult } from '$lib/gql/generated/graphql'; + import { useNotifications } from '$lib/notify'; + const { notifySuccess } = useNotifications(); async function requestBetaAccess(): Promise { - await _sendFWLiteBetaRequestEmail(page.data.user.id as UUID, page.data.user.name); + const gqlResult = await _sendFWLiteBetaRequestEmail(page.data.user.id as UUID, page.data.user.name); + if (gqlResult.error) { + if (gqlResult.error.byType('NotFoundError')) { + console.log('User not found, no dialog shown'); + } + } + const result = gqlResult.data?.sendFWLiteBetaRequestEmail.sendFWLiteBetaRequestEmailResult; + if (result === SendFwLiteBetaRequestEmailResult.BetaAccessRequestSent) { + notifySuccess($t('where_is_my_project.access_request_sent')); + } + if (result === SendFwLiteBetaRequestEmailResult.UserAlreadyInBeta) { + notifySuccess($t('where_is_my_project.already_in_beta')); + } } diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts index 25b3ce9a81..541b8fed9f 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.ts @@ -10,10 +10,7 @@ export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $ graphql(` mutation SendFWLiteBetaRequestEmail($input: SendFWLiteBetaRequestEmailInput!) { sendFWLiteBetaRequestEmail(input: $input) { - meDto { - id - email - } + sendFWLiteBetaRequestEmailResult errors { __typename ... on Error { @@ -23,7 +20,7 @@ export async function _sendFWLiteBetaRequestEmail(userId: UUID, name: string): $ } } `), - {input: {userId, name}} + { input: { userId, name } } ) return result; } From 429b4f0405b739cefa55a6c59a6ed824e08797bd Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Mon, 19 May 2025 17:18:31 +0700 Subject: [PATCH 15/19] Remove duplicate home breadcrumb --- frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte index 493b51d929..1cc400b442 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte @@ -28,7 +28,6 @@ } -
From 5f5eb579909a4d9caf29309f6d43e680e328b8cf Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Mon, 19 May 2025 15:13:30 +0200 Subject: [PATCH 16/19] Fix up request email --- frontend/src/lib/email/Email.svelte | 2 +- frontend/src/lib/email/JoinFwLiteBetaRequest.svelte | 2 +- frontend/src/lib/i18n/locales/en.json | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/email/Email.svelte b/frontend/src/lib/email/Email.svelte index e11b1e0608..ae0ef4f24b 100644 --- a/frontend/src/lib/email/Email.svelte +++ b/frontend/src/lib/email/Email.svelte @@ -5,7 +5,7 @@ const lexboxLogo = 'https://lexbox.org/images/logo-dark.png'; interface Props { subject: string; - name: string; + name?: string; children?: Snippet; } diff --git a/frontend/src/lib/email/JoinFwLiteBetaRequest.svelte b/frontend/src/lib/email/JoinFwLiteBetaRequest.svelte index 1ab78f7fd6..91492c65aa 100644 --- a/frontend/src/lib/email/JoinFwLiteBetaRequest.svelte +++ b/frontend/src/lib/email/JoinFwLiteBetaRequest.svelte @@ -8,7 +8,7 @@ let approveUrl = new URL(`/admin/?userSearch=${encodeURIComponent(email)}`, baseUrl); - + {$t('emails.join_fw_lite_beta_request_email.body', { name })} {$t('emails.join_fw_lite_beta_request_email.approve_button')} diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 11091eea11..7d43ef0c6c 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -677,7 +677,7 @@ it's done, you should see your project in FieldWorks Lite and be able to use it. Only selected early access users can download Lexbox projects in FieldWorks Lite. \n\ Click the button below to request to join the early access program. It may take a few days for us to respond.", "request_beta_access": "Request early access to FieldWorks Lite", - "access_request_sent": "Early access request has been sent", + "access_request_sent": "Your request to join the early access program has been submitted", "already_in_beta": "You're already in the early access program", }, "errors": { @@ -749,7 +749,7 @@ Click the button below to request to join the early access program. It may take "view_button": "View Project" }, "join_fw_lite_beta_request_email": { - "subject": "FW Lite Beta join request: {name} wants to join the FW Lite beta", + "subject": "FW Lite Beta join request: {name}", "body": "User {name} requested to join the FW Lite beta. Click below to approve this request.", "approve_button": "Approve Request" }, From f163b4f262012aa1fe82f9e7d42555aab5d4fa8c Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Mon, 19 May 2025 15:13:47 +0200 Subject: [PATCH 17/19] Only refresh token if necessary --- backend/LexBoxApi/GraphQL/UserMutations.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/LexBoxApi/GraphQL/UserMutations.cs b/backend/LexBoxApi/GraphQL/UserMutations.cs index 219a39982d..18616f340c 100644 --- a/backend/LexBoxApi/GraphQL/UserMutations.cs +++ b/backend/LexBoxApi/GraphQL/UserMutations.cs @@ -45,11 +45,11 @@ public enum SendFWLiteBetaRequestEmailResult [Error] [UseMutationConvention] - [RefreshJwt] public async Task SendFWLiteBetaRequestEmail( LoggedInContext loggedInContext, SendFWLiteBetaRequestEmailInput input, LexBoxDbContext dbContext, + LexAuthService lexAuthService, IEmailService emailService ) { @@ -58,6 +58,8 @@ IEmailService emailService NotFoundException.ThrowIfNull(user); if (user.FeatureFlags.Contains(FeatureFlag.FwLiteBeta)) { + if (!loggedInContext.User.FeatureFlags.Contains(FeatureFlag.FwLiteBeta)) + await lexAuthService.RefreshUser(); return SendFWLiteBetaRequestEmailResult.UserAlreadyInBeta; } await emailService.SendJoinFwLiteBetaEmail(user); From 9b826b248be08af8a336be13c98482f96e24ea4c Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Mon, 19 May 2025 15:14:20 +0200 Subject: [PATCH 18/19] Add request button loading state --- .../wheresMyProject/+page.svelte | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte index 1cc400b442..89236df13b 100644 --- a/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte +++ b/frontend/src/routes/(authenticated)/wheresMyProject/+page.svelte @@ -1,5 +1,5 @@ @@ -37,12 +45,9 @@ {#snippet missingFlagContent()}
- +
{/snippet}
- - From 98bf5af466fdaaf9e3fc9641fcfcd5cb6f34c46b Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Mon, 19 May 2025 15:14:31 +0200 Subject: [PATCH 19/19] Tweak padding --- frontend/viewer/src/home/Server.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/viewer/src/home/Server.svelte b/frontend/viewer/src/home/Server.svelte index 621fddff50..0f34070a99 100644 --- a/frontend/viewer/src/home/Server.svelte +++ b/frontend/viewer/src/home/Server.svelte @@ -123,7 +123,7 @@ {/if} {/each} -
+