Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
cf696d2
release: v1.3.0 #8835
sriramveeraghanta Apr 6, 2026
d0a4adc
release: v1.3.1 #8917
sriramveeraghanta May 14, 2026
917b23a
release: v1.4.0 #9160
sriramveeraghanta Jul 31, 2026
5662b76
release: v1.4.1 #9545
sriramveeraghanta Aug 7, 2026
19d48d9
fix(security): stop rendering raw comment HTML unescaped in email not…
kovalancik06-max Aug 20, 2026
5f7d927
release: v1.4.2 #9632
sriramveeraghanta Aug 23, 2026
b99f74d
[WEB-7946] fix: add rate limiting to email/password sign-in and sign-…
mguptahub Aug 27, 2026
79b6075
[WEB-8103] fix: stop leaking webhook HMAC secret_key on reads (#9382)
mguptahub Aug 27, 2026
2146cfd
[WEB-8110] fix: sanitize page list order_by against an allowlist (#9387)
mguptahub Aug 27, 2026
1e1248a
[WEB-8283] fix: bind Spaces board object IDs to the anchor's project …
mguptahub Aug 27, 2026
5c4d9b1
[WEB-8352] fix(security): scope SubIssuesEndpoint to the URL project …
mguptahub Aug 27, 2026
e3324b6
fix(api): validate assignees/labels in IssueSerializer instead of sil…
houssaineamzil Sep 2, 2026
c9b56cf
[GIT-221] fix(cycle): guard against no end_date when archiving cycle …
Rahulcheryala Sep 2, 2026
cd98fab
fix(api): avoid re-crawling issue link on update when url is unchange…
Tyagiquamar Sep 7, 2026
fea9426
[INFRA-962] fix(minio): pull MinIO images from quay.io instead of the…
pratapalakshmi Sep 15, 2026
a5595ea
[WEB-8289] fix: scope draft-to-issue conversion to the draft owner (#…
mguptahub Sep 15, 2026
b2dd757
[WEB-9166] fix(project): scope project-join membership lookup to the …
sriramveeraghanta Sep 22, 2026
6fc1010
chore: bump version to 1.4.3
sriramveeraghanta Sep 22, 2026
c6be1fa
chore: upgrade pnpm to 11.10, turbo to latest, fix dependabot alert (…
sriramveeraghanta Sep 1, 2026
a97680d
chore(deps): bump sanitize-html (#9736)
dependabot[bot] Sep 2, 2026
00ecb12
[INFRA-843] fix(security): clear nightly Trivy findings (#9773)
pratapalakshmi Sep 7, 2026
1258f53
fix(security): clear the 2026-09-10 nightly Trivy findings (#9806)
pratapalakshmi Sep 10, 2026
ec1e5de
fix(deps): resolve dependabot security alerts (#9839)
sriramveeraghanta Sep 15, 2026
5fcc65f
fix(security): bump the fast-uri pin to 3.1.8 (#9919)
pratapalakshmi Oct 1, 2026
5864647
[INFRA-804] fix(airgapped and minio): harden community restore-airgap…
akshat5302 Oct 1, 2026
b348e44
[INFRA-1039] fix(deployments): find the latest release when the GitHu…
akshat5302 Oct 1, 2026
90717e5
fix: address v1.4.3 release review comments (#9925)
sriramveeraghanta Oct 1, 2026
28301f7
[INFRA-1089] chore(deps): switch MinIO image to pgsty/silo (#9962) (#…
sriramveeraghanta Oct 8, 2026
a13ed1c
fix(charts): limit ideal burndown tooltip precision
HaiYangBG1 Oct 9, 2026
dc93e16
[SECUR-247] fix(security): require project membership to publish (#10…
sriramveeraghanta Oct 16, 2026
d9726d5
[GIT-384] Fix voting on published work items with no votes (#10103)
Rahulcheryala Oct 23, 2026
bc0b1bb
[GIT-384] Fix voting on published work items with no votes (#10103)
Rahulcheryala Oct 23, 2026
92054a2
[INFRA-843] fix: close the 2026-10-26 nightly Trivy findings (#10120)
pratapalakshmi Oct 26, 2026
b4b48c9
[WIKI-1268] chore: upgrade Tiptap and Hocuspocus to v3 (#10101)
sriramveeraghanta Oct 26, 2026
0d7b541
[WEB-8291] fix: gate project invitation list/retrieve/destroy to proj…
mguptahub Oct 26, 2026
2bd5af2
[WEB-8374] fix(security): scope ProjectMemberPreferenceEndpoint to th…
mguptahub Oct 26, 2026
a42b536
[WEB-8401] fix(security): scope public Space asset mutations to the c…
mguptahub Oct 26, 2026
2cac83e
[SECUR-236] fix: grouped-paginator cursor bound + Project mass-assign…
mguptahub Oct 26, 2026
2802c15
[INFRA-501] fix(security): enforce project membership on every worksp…
mguptahub Oct 26, 2026
549ec76
[INFRA-772] fix(security): stop trusting body-supplied created_by/cre…
mguptahub Oct 26, 2026
5d2b4a6
[WEB-8353] fix(security): enforce guest issue visibility on attachmen…
mguptahub Oct 26, 2026
a5e958e
[INFRA-778] fix(security): scope ExportIssuesEndpoint.get to the requ…
mguptahub Oct 26, 2026
442b396
[INFRA-496] fix(security): refuse routed actions served by unauthoriz…
mguptahub Oct 26, 2026
be4b4ab
[INFRA-499] fix(security): require workspace membership to read a glo…
mguptahub Oct 26, 2026
af5f783
[INFRA-777] fix(security): scope ProjectArchiveUnarchiveAPIEndpoint t…
mguptahub Oct 26, 2026
a9e7036
[WEB-8400] fix(security): scope DeployBoardViewSet queryset to the UR…
mguptahub Oct 26, 2026
37a15d9
Merge pull request #9867 from makeplane/release/v1.4.3
vihar Oct 28, 2026
19f552b
sync: master branch to preview
sriramveeraghanta Oct 28, 2026
52d3e54
Merge pull request #9651 from kovalancik06-max/fix/xss-comment-email-…
vihar Oct 28, 2026
476053d
Merge pull request #10126 from makeplane/fix/timeline-fullscreen
vamsikrishnamathala Oct 28, 2026
8e07d40
[WIKI-1268] fix: honor collaboration forced disconnects (#10121)
saivallampati Oct 28, 2026
9d10be3
chore: bump version
sriramveeraghanta Oct 28, 2026
4190800
chore: replace mguptahub with pratapalakshmi as deployments code owne…
sriramveeraghanta Oct 28, 2026
b98e1de
[INFRA-843] fix: close the 2026-10-29 nightly Trivy findings (#10144)
pratapalakshmi Oct 29, 2026
3388318
fix(web): allow saving profile settings with an empty last name (#101…
ghazy2001 Nov 2, 2026
efa46d2
feat: sync web, Space and Admin UI with the Propel design system (#10…
anmolsinghbhatia Nov 2, 2026
052f6e7
fix(charts): preserve tooltip formatting with updated preview
HaiYangBG1 Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ apps/web/ @sriramveeraghanta
apps/space/ @sriramveeraghanta
apps/admin/ @sriramveeraghanta
apps/live/ @saivallampati
deployments/ @mguptahub
deployments/ @pratapalakshmi
4 changes: 3 additions & 1 deletion apps/admin/Dockerfile.admin
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,15 @@ RUN XCADDY_SKIP_CLEANUP=1 xcaddy build \
# x/net v0.60.0 requires x/crypto v0.57.0 and x/text v0.42.0, hence those floors.
# grpc and otel move together: grpc >= v1.83.0 requires otel v1.44.0, so bump
# the otel pair in lockstep or go walks grpc backwards to satisfy the older one.
# go-jose v4 is also Caddy's own pin; CVE-2026-116587 is fixed in v4.1.6.
RUN cd "$(find /tmp -maxdepth 1 -name 'buildenv_*' -type d | head -1)" && \
go get golang.org/x/crypto@v0.57.0 && \
go get golang.org/x/net@v0.60.0 && \
go get golang.org/x/text@v0.42.0 && \
go get google.golang.org/grpc@v1.83.2 && \
go get go.opentelemetry.io/otel@v1.46.0 && \
go get go.opentelemetry.io/otel/sdk@v1.46.0 && \
go get github.com/go-jose/go-jose/v4@v4.1.6 && \
go mod tidy && \
go build -o /usr/bin/caddy -ldflags "-w -s" -trimpath .

Expand All @@ -111,7 +113,7 @@ FROM caddy:2.11.4-alpine AS production
# OS security updates too: --available forces reinstall from the current repos;
# bump APK_SECURITY_PATCH to bust buildx's cached layer (keyed on this command
# string), otherwise a rebuild silently re-ships the old packages.
ARG APK_SECURITY_PATCH=2026-10-22
ARG APK_SECURITY_PATCH=2026-10-26
RUN echo "apk-security-patch ${APK_SECURITY_PATCH}" && apk update && apk upgrade --no-cache --available && apk add --no-cache curl && rm -rf /var/cache/apk/*

COPY --from=caddy-builder /usr/bin/caddy /usr/bin/caddy
Expand Down
4 changes: 2 additions & 2 deletions apps/admin/app/(all)/(dashboard)/ai/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ export function InstanceAIForm(props: IInstanceAIForm) {
<div className="space-y-8">
<div className="space-y-3">
<div>
<div className="pb-1 text-18 font-medium text-primary">OpenAI</div>
<div className="text-13 font-regular text-tertiary">If you use ChatGPT, this is for you.</div>
<div className="pb-1 text-h6-medium text-primary">OpenAI</div>
<div className="text-body-sm-regular text-tertiary">If you use ChatGPT, this is for you.</div>
</div>
<div className="grid-col grid w-full grid-cols-1 items-center justify-between gap-x-12 gap-y-8 lg:grid-cols-3">
{aiFormFields.map((field) => (
Expand Down
2 changes: 1 addition & 1 deletion apps/admin/app/(all)/(dashboard)/ai/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { observer } from "mobx-react";
import useSWR from "swr";
// components
import { PageWrapper } from "@/components/common/page-wrapper";
import { Skeleton } from "@/components/common/skeleton";
import { Skeleton } from "@plane/blocks/skeleton";
// hooks
import { useInstance } from "@/hooks/store";
// types
Expand Down
12 changes: 6 additions & 6 deletions apps/admin/app/(all)/(dashboard)/authentication/gitea/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ export function InstanceGiteaConfigForm(props: Props) {
handleClose={() => setIsDiscardChangesModalOpen(false)}
/>
<div className="flex flex-col gap-8">
<div className="grid w-full grid-cols-2 gap-x-12 gap-y-8">
<div className="grid w-full grid-cols-2 gap-x-8 gap-y-8">
<div className="col-span-2 flex flex-col gap-y-4 pt-1 md:col-span-1">
<div className="pt-2.5 text-18 font-medium">Gitea-provided details for Plane</div>
<div className="text-h6-medium text-primary">Gitea-provided details for Plane</div>
{GITEA_FORM_FIELDS.map((field) => (
<ControllerInput
key={field.key}
Expand All @@ -192,7 +192,7 @@ export function InstanceGiteaConfigForm(props: Props) {
))}
<ControllerSwitch control={control} field={GITEA_FORM_SWITCH_FIELD} />
<div className="flex flex-col gap-1 pt-4">
<div className="flex items-center gap-4">
<div className="flex flex-wrap items-center gap-2">
<Button
variant="primary"
size="md"
Expand All @@ -213,9 +213,9 @@ export function InstanceGiteaConfigForm(props: Props) {
</div>
</div>
</div>
<div className="col-span-2 md:col-span-1">
<div className="flex flex-col gap-y-4 rounded-lg bg-layer-1 px-6 pt-1.5 pb-4">
<div className="pt-2 text-18 font-medium">Plane-provided details for Gitea</div>
<div className="col-span-2 flex flex-col gap-y-6 md:col-span-1">
<div className="text-h6-medium text-primary">Plane-provided details for Gitea</div>
<div className="flex flex-col gap-y-4 rounded-lg bg-layer-1 px-6 py-4">
{GITEA_SERVICE_FIELD.map((field) => (
<CopyField key={field.key} label={field.label} url={field.url} description={field.description} />
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import giteaLogo from "@/app/assets/logos/gitea-logo.svg?url";
// components
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
import { PageWrapper } from "@/components/common/page-wrapper";
import { Skeleton } from "@/components/common/skeleton";
import { Skeleton } from "@plane/blocks/skeleton";
import { setPromiseToast } from "@plane/blocks/toast";
// hooks
import { useInstance } from "@/hooks/store";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@ export function InstanceGithubConfigForm(props: Props) {
handleClose={() => setIsDiscardChangesModalOpen(false)}
/>
<div className="flex flex-col gap-8">
<div className="grid w-full grid-cols-2 gap-x-12 gap-y-8">
<div className="grid w-full grid-cols-2 gap-x-8 gap-y-8">
<div className="col-span-2 flex flex-col gap-y-4 pt-1 md:col-span-1">
<div className="pt-2.5 text-18 font-medium">GitHub-provided details for Plane</div>
<div className="text-h6-medium text-primary">GitHub-provided details for Plane</div>
{GITHUB_FORM_FIELDS.map((field) => (
<ControllerInput
key={field.key}
Expand All @@ -213,7 +213,7 @@ export function InstanceGithubConfigForm(props: Props) {
))}
<ControllerSwitch control={control} field={GITHUB_FORM_SWITCH_FIELD} />
<div className="flex flex-col gap-1 pt-4">
<div className="flex items-center gap-4">
<div className="flex flex-wrap items-center gap-2">
<Button
variant="primary"
size="md"
Expand All @@ -235,7 +235,7 @@ export function InstanceGithubConfigForm(props: Props) {
</div>
</div>
<div className="col-span-2 flex flex-col gap-y-6 md:col-span-1">
<div className="pt-2 text-18 font-medium">Plane-provided details for GitHub</div>
<div className="text-h6-medium text-primary">Plane-provided details for GitHub</div>

<div className="flex flex-col gap-y-4">
{/* common service details */}
Expand All @@ -247,8 +247,8 @@ export function InstanceGithubConfigForm(props: Props) {

{/* web service details */}
<div className="flex flex-col overflow-hidden rounded-lg">
<div className="flex items-center gap-x-3 bg-layer-3 px-6 py-3 text-11 font-medium text-secondary uppercase">
<MonitorOutline className="h-3 w-3" />
<div className="flex items-center gap-x-2 bg-layer-3 px-6 py-3 text-caption-sm-medium text-secondary uppercase">
<MonitorOutline className="size-3.5" />
Web
</div>
<div className="flex flex-col gap-y-4 bg-layer-1 px-6 py-4">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import githubDarkModeImage from "@/app/assets/logos/github-white.png?url";
// components
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
import { PageWrapper } from "@/components/common/page-wrapper";
import { Skeleton } from "@/components/common/skeleton";
import { Skeleton } from "@plane/blocks/skeleton";
import { setPromiseToast } from "@plane/blocks/toast";
// hooks
import { useInstance } from "@/hooks/store";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@ export function InstanceGitlabConfigForm(props: Props) {
handleClose={() => setIsDiscardChangesModalOpen(false)}
/>
<div className="flex flex-col gap-8">
<div className="grid w-full grid-cols-2 gap-x-12 gap-y-8">
<div className="grid w-full grid-cols-2 gap-x-8 gap-y-8">
<div className="col-span-2 flex flex-col gap-y-4 pt-1 md:col-span-1">
<div className="pt-2.5 text-18 font-medium">GitLab-provided details for Plane</div>
<div className="text-h6-medium text-primary">GitLab-provided details for Plane</div>
{GITLAB_FORM_FIELDS.map((field) => (
<ControllerInput
key={field.key}
Expand All @@ -195,7 +195,7 @@ export function InstanceGitlabConfigForm(props: Props) {
))}
<ControllerSwitch control={control} field={GITLAB_FORM_SWITCH_FIELD} />
<div className="flex flex-col gap-1 pt-4">
<div className="flex items-center gap-4">
<div className="flex flex-wrap items-center gap-2">
<Button
variant="primary"
size="md"
Expand All @@ -216,9 +216,9 @@ export function InstanceGitlabConfigForm(props: Props) {
</div>
</div>
</div>
<div className="col-span-2 md:col-span-1">
<div className="flex flex-col gap-y-4 rounded-lg bg-layer-3 px-6 pt-1.5 pb-4">
<div className="pt-2 text-18 font-medium">Plane-provided details for GitLab</div>
<div className="col-span-2 flex flex-col gap-y-6 md:col-span-1">
<div className="text-h6-medium text-primary">Plane-provided details for GitLab</div>
<div className="flex flex-col gap-y-4 rounded-lg bg-layer-1 px-6 py-4">
{GITLAB_SERVICE_FIELD.map((field) => (
<CopyField key={field.key} label={field.label} url={field.url} description={field.description} />
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import GitlabLogo from "@/app/assets/logos/gitlab-logo.svg?url";
// components
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
import { PageWrapper } from "@/components/common/page-wrapper";
import { Skeleton } from "@/components/common/skeleton";
import { Skeleton } from "@plane/blocks/skeleton";
import { setPromiseToast } from "@plane/blocks/toast";
// hooks
import { useInstance } from "@/hooks/store";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ export function InstanceGoogleConfigForm(props: Props) {
handleClose={() => setIsDiscardChangesModalOpen(false)}
/>
<div className="flex flex-col gap-8">
<div className="grid w-full grid-cols-2 gap-x-12 gap-y-8">
<div className="grid w-full grid-cols-2 gap-x-8 gap-y-8">
<div className="col-span-2 flex flex-col gap-y-4 pt-1 md:col-span-1">
<div className="pt-2.5 text-18 font-medium">Google-provided details for Plane</div>
<div className="text-h6-medium text-primary">Google-provided details for Plane</div>
{GOOGLE_FORM_FIELDS.map((field) => (
<ControllerInput
key={field.key}
Expand All @@ -205,7 +205,7 @@ export function InstanceGoogleConfigForm(props: Props) {
))}
<ControllerSwitch control={control} field={GOOGLE_FORM_SWITCH_FIELD} />
<div className="flex flex-col gap-1 pt-4">
<div className="flex items-center gap-4">
<div className="flex flex-wrap items-center gap-2">
<Button
variant="primary"
size="md"
Expand All @@ -227,7 +227,7 @@ export function InstanceGoogleConfigForm(props: Props) {
</div>
</div>
<div className="col-span-2 flex flex-col gap-y-6 md:col-span-1">
<div className="pt-2 text-18 font-medium">Plane-provided details for Google</div>
<div className="text-h6-medium text-primary">Plane-provided details for Google</div>

<div className="flex flex-col gap-y-4">
{/* common service details */}
Expand All @@ -239,8 +239,8 @@ export function InstanceGoogleConfigForm(props: Props) {

{/* web service details */}
<div className="flex flex-col overflow-hidden rounded-lg">
<div className="flex items-center gap-x-3 bg-layer-3 px-6 py-3 text-11 font-medium text-secondary uppercase">
<MonitorOutline className="h-3 w-3" />
<div className="flex items-center gap-x-2 bg-layer-3 px-6 py-3 text-caption-sm-medium text-secondary uppercase">
<MonitorOutline className="size-3.5" />
Web
</div>
<div className="flex flex-col gap-y-4 bg-layer-1 px-6 py-4">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import GoogleLogo from "@/app/assets/logos/google-logo.svg?url";
// components
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
import { PageWrapper } from "@/components/common/page-wrapper";
import { Skeleton } from "@/components/common/skeleton";
import { Skeleton } from "@plane/blocks/skeleton";
import { setPromiseToast } from "@plane/blocks/toast";
// hooks
import { useInstance } from "@/hooks/store";
Expand Down
18 changes: 10 additions & 8 deletions apps/admin/app/(all)/(dashboard)/authentication/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { cn, resolveGeneralTheme } from "@plane/utils";
// components
import { PageWrapper } from "@/components/common/page-wrapper";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
import { Skeleton } from "@/components/common/skeleton";
import { Skeleton } from "@plane/blocks/skeleton";
import { setPromiseToast, setToast } from "@plane/blocks/toast";
// helpers
import { canDisableAuthMethod } from "@/helpers/authentication";
Expand Down Expand Up @@ -120,16 +120,18 @@ const InstanceAuthenticationPage = observer(function InstanceAuthenticationPage(
>
{formattedConfig ? (
<div className="space-y-3">
<div className={cn("flex w-full items-center gap-14 rounded-sm")}>
<div className="flex grow items-center gap-4">
<div className="grow">
<div className="pb-1 text-16 font-medium">Allow anyone to sign up even without an invite</div>
<div className={cn("text-11 leading-5 font-regular text-tertiary")}>
<div className="flex w-full items-start justify-between gap-4 rounded-lg border border-subtle bg-layer-2 px-4 py-3 md:items-center md:gap-8">
<div className="flex min-w-0 grow items-center gap-4">
<div className="min-w-0 grow">
<div className="pb-1 text-body-sm-medium text-primary">
Allow anyone to sign up even without an invite
</div>
<div className="text-body-xs-regular leading-5 text-tertiary">
Toggling this off will only let users sign up when they are invited.
</div>
</div>
</div>
<div className={`shrink-0 pr-4 ${isSubmitting && "opacity-70"}`}>
<div className={cn("shrink-0", { "opacity-70": isSubmitting })}>
<div className="flex items-center gap-4">
<Switch
aria-label="Allow anyone to sign up even without an invite"
Expand All @@ -147,7 +149,7 @@ const InstanceAuthenticationPage = observer(function InstanceAuthenticationPage(
</div>
</div>
</div>
<div className="text-lg pt-6 font-medium">Available authentication modes</div>
<h3 className="pt-3 text-h6-medium text-primary">Available authentication modes</h3>
{authenticationModes.map((method) => (
<AuthenticationMethodCard
key={method.key}
Expand Down
52 changes: 32 additions & 20 deletions apps/admin/app/(all)/(dashboard)/email/email-config-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* See the LICENSE file for details.
*/

import { useMemo, useState } from "react";
import { useId, useMemo, useState } from "react";
import { useForm } from "react-hook-form";
// types
import { Button } from "@makeplane/propel/components/button";
Expand Down Expand Up @@ -35,6 +35,7 @@ const EMAIL_SECURITY_OPTIONS: { [key in TEmailSecurityKeys]: string } = {

export function InstanceEmailForm(props: IInstanceEmailForm) {
const { config } = props;
const emailSecurityLabelId = useId();
// states
const [isSendTestEmailModalOpen, setIsSendTestEmailModalOpen] = useState(false);
// store hooks
Expand All @@ -45,6 +46,7 @@ export function InstanceEmailForm(props: IInstanceEmailForm) {
watch,
setValue,
control,
reset,
formState: { errors, isValid, isDirty, isSubmitting },
} = useForm<EmailFormValues>({
defaultValues: {
Expand Down Expand Up @@ -109,15 +111,18 @@ export function InstanceEmailForm(props: IInstanceEmailForm) {
const onSubmit = async (formData: EmailFormValues) => {
const payload: Partial<EmailFormValues> = { ...formData, ENABLE_SMTP: "1" };

await updateInstanceConfigurations(payload)
.then(() =>
setToast({
type: "success",
title: "Success",
message: "Email Settings updated successfully",
})
)
.catch((err) => console.error(err));
try {
await updateInstanceConfigurations(payload);
// the saved values become the new baseline, so Save disables again until the next edit
reset(payload);
setToast({
type: "success",
title: "Success",
message: "Email Settings updated successfully",
});
} catch (err) {
console.error(err);
}
};

const useTLSValue = watch("EMAIL_USE_TLS");
Expand All @@ -130,16 +135,16 @@ export function InstanceEmailForm(props: IInstanceEmailForm) {

const handleEmailSecurityChange = (key: TEmailSecurityKeys) => {
if (key === "EMAIL_USE_SSL") {
setValue("EMAIL_USE_TLS", "0");
setValue("EMAIL_USE_SSL", "1");
setValue("EMAIL_USE_TLS", "0", { shouldDirty: true });
setValue("EMAIL_USE_SSL", "1", { shouldDirty: true });
}
if (key === "EMAIL_USE_TLS") {
setValue("EMAIL_USE_TLS", "1");
setValue("EMAIL_USE_SSL", "0");
setValue("EMAIL_USE_TLS", "1", { shouldDirty: true });
setValue("EMAIL_USE_SSL", "0", { shouldDirty: true });
}
if (key === "NONE") {
setValue("EMAIL_USE_TLS", "0");
setValue("EMAIL_USE_SSL", "0");
setValue("EMAIL_USE_TLS", "0", { shouldDirty: true });
setValue("EMAIL_USE_SSL", "0", { shouldDirty: true });
}
};

Expand All @@ -162,13 +167,20 @@ export function InstanceEmailForm(props: IInstanceEmailForm) {
/>
))}
<div className="flex flex-col gap-1">
<h4 className="text-13 text-tertiary">Email security</h4>
<span id={emailSecurityLabelId} className="text-body-xs-medium text-primary">
Email security
</span>
<Select
items={EMAIL_SECURITY_OPTIONS}
value={emailSecurityKey}
onValueChange={(value) => handleEmailSecurityChange(value as TEmailSecurityKeys)}
>
<SelectTrigger size="lg" placeholder="Select email security" />
<SelectTrigger
variant="secondary"
size="lg"
placeholder="Select email security"
aria-labelledby={emailSecurityLabelId}
/>
<SelectContent>
<SelectList>
{Object.entries(EMAIL_SECURITY_OPTIONS).map(([key, value]) => (
Expand All @@ -183,8 +195,8 @@ export function InstanceEmailForm(props: IInstanceEmailForm) {
<div className="flex w-full max-w-xl flex-col gap-y-10 px-1">
<div className="mr-8 flex items-center gap-10 pt-4">
<div className="grow">
<div className="text-13 font-medium text-primary">Authentication</div>
<div className="text-11 font-regular text-tertiary">
<div className="text-body-xs-medium text-primary">Authentication</div>
<div className="text-caption-sm-regular text-tertiary">
This is optional, but we recommend setting up a username and a password for your SMTP server.
</div>
</div>
Expand Down
Loading
Loading