diff --git a/models/user/user.go b/models/user/user.go index 86a3549345..7c871bf575 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -831,6 +831,20 @@ type CountUserFilter struct { IsActive optional.Option[bool] } +// HasUsers checks whether there are any users in the database, or only one user exists. +func HasUsers(ctx context.Context) (ret struct { + HasAnyUser, HasOnlyOneUser bool +}, err error, +) { + res, err := db.GetEngine(ctx).Table(&User{}).Cols("id").Limit(2).Query() + if err != nil { + return ret, fmt.Errorf("error checking user existence: %w", err) + } + ret.HasAnyUser = len(res) != 0 + ret.HasOnlyOneUser = len(res) == 1 + return ret, nil +} + // CountUsers returns number of users. func CountUsers(ctx context.Context, opts *CountUserFilter) int64 { return countUsers(ctx, opts) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 9a7c5f876f..dae5aeea21 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -421,6 +421,7 @@ remember_me.compromised = The login token is not valid anymore which may indicat forgot_password_title= Forgot Password forgot_password = Forgot password? need_account = Need an account? +sign_up_tip = You are registering the first account in the system, which has administrator privileges. Please carefully remember your username and password. If you forget the username or password, please refer to the Gitea documentation to recover the account. sign_up_now = Register now. sign_up_successful = Account was successfully created. Welcome! confirmation_mail_sent_prompt_ex = A new confirmation email has been sent to %s. Please check your inbox within the next %s to complete the registration process. If your registration email address is incorrect, you can sign in again and change it. @@ -2817,6 +2818,7 @@ team_permission_desc = Permission team_unit_desc = Allow Access to Repository Sections team_unit_disabled = (Disabled) +form.name_been_taken = The organisation name "%s" has already been taken. form.name_reserved = The organization name "%s" is reserved. form.name_pattern_not_allowed = The pattern "%s" is not allowed in an organization name. form.create_org_not_allowed = You are not allowed to create an organization. @@ -2838,15 +2840,28 @@ settings.visibility.private_shortname = Private settings.update_settings = Update Settings settings.update_setting_success = Organization settings have been updated. -settings.change_orgname_prompt = Note: Changing the organization name will also change your organization's URL and free the old name. -settings.change_orgname_redirect_prompt = The old name will redirect until it is claimed. + +settings.rename = Rename Organization +settings.rename_desc = Changing the organization name will also change your organization's URL and free the old name. +settings.rename_success = Organization %[1]s have been renamed to %[2]s successfully. +settings.rename_no_change = Organization name is no change. +settings.rename_new_org_name = New Organization Name +settings.rename_failed = Rename Organization failed because of internal error +settings.rename_notices_1 = This operation CANNOT be undone. +settings.rename_notices_2 = The old name will redirect until it is claimed. + settings.update_avatar_success = The organization's avatar has been updated. settings.delete = Delete Organization settings.delete_account = Delete This Organization settings.delete_prompt = The organization will be permanently removed. This CANNOT be undone! +settings.name_confirm = Enter the organization name as confirmation: +settings.delete_notices_1 = This operation CANNOT be undone. +settings.delete_notices_2 = This operation will permanently delete all the repositories of %s including code, issues, comments, wiki data and collaborator settings. +settings.delete_notices_3 = This operation will permanently delete all the packages of %s. +settings.delete_notices_4 = This operation will permanently delete all the projects of %s. settings.confirm_delete_account = Confirm Deletion -settings.delete_org_title = Delete Organization -settings.delete_org_desc = This organization will be deleted permanently. Continue? +settings.delete_failed = Delete Organization failed because of internal error +settings.delete_successful = Organization %s has been deleted successfully. settings.hooks_desc = Add webhooks which will be triggered for all repositories under this organization. settings.labels_desc = Add labels which can be used on issues for all repositories under this organization. diff --git a/routers/install/install.go b/routers/install/install.go index b9bc41dfcf..c1da79454a 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -601,5 +601,7 @@ func SubmitInstall(ctx *context.Context) { // InstallDone shows the "post-install" page, makes it easier to develop the page. // The name is not called as "PostInstall" to avoid misinterpretation as a handler for "POST /install" func InstallDone(ctx *context.Context) { //nolint + hasUsers, _ := user_model.HasUsers(ctx) + ctx.Data["IsAccountCreated"] = hasUsers.HasAnyUser ctx.HTML(http.StatusOK, tplPostInstall) } diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 87edbc357b..94f75f69ff 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -421,9 +421,11 @@ func SignOut(ctx *context.Context) { // SignUp render the register page func SignUp(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("sign_up") - ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up" + hasUsers, _ := user_model.HasUsers(ctx) + ctx.Data["IsFirstTimeRegistration"] = !hasUsers.HasAnyUser + oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, optional.Some(true)) if err != nil { ctx.ServerError("UserSignUp", err) @@ -610,7 +612,13 @@ func createUserInContext(ctx *context.Context, tpl templates.TplName, form any, // sends a confirmation email if required. func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.User) (ok bool) { // Auto-set admin for the only user. - if user_model.CountUsers(ctx, nil) == 1 { + hasUsers, err := user_model.HasUsers(ctx) + if err != nil { + ctx.ServerError("HasUsers", err) + return false + } + if hasUsers.HasOnlyOneUser { + // the only user is the one just created, will set it as admin opts := &user_service.UpdateOptions{ IsActive: optional.Some(true), IsAdmin: user_service.UpdateOptionFieldFromValue(true), diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 9dd0a98160..2bc1e8bc43 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -18,6 +18,7 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" shared_user "code.gitea.io/gitea/routers/web/shared/user" user_setting "code.gitea.io/gitea/routers/web/user/setting" @@ -31,8 +32,6 @@ import ( const ( // tplSettingsOptions template path for render settings tplSettingsOptions templates.TplName = "org/settings/options" - // tplSettingsDelete template path for render delete repository - tplSettingsDelete templates.TplName = "org/settings/delete" // tplSettingsHooks template path for render hook settings tplSettingsHooks templates.TplName = "org/settings/hooks" // tplSettingsLabels template path for render labels settings @@ -71,26 +70,6 @@ func SettingsPost(ctx *context.Context) { org := ctx.Org.Organization - if org.Name != form.Name { - if err := user_service.RenameUser(ctx, org.AsUser(), form.Name); err != nil { - if user_model.IsErrUserAlreadyExist(err) { - ctx.Data["Err_Name"] = true - ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tplSettingsOptions, &form) - } else if db.IsErrNameReserved(err) { - ctx.Data["Err_Name"] = true - ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplSettingsOptions, &form) - } else if db.IsErrNamePatternNotAllowed(err) { - ctx.Data["Err_Name"] = true - ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form) - } else { - ctx.ServerError("RenameUser", err) - } - return - } - - ctx.Org.OrgLink = setting.AppSubURL + "/org/" + url.PathEscape(org.Name) - } - if form.Email != "" { if err := user_service.ReplacePrimaryEmailAddress(ctx, org.AsUser(), form.Email); err != nil { ctx.Data["Err_Email"] = true @@ -163,42 +142,27 @@ func SettingsDeleteAvatar(ctx *context.Context) { ctx.JSONRedirect(ctx.Org.OrgLink + "/settings") } -// SettingsDelete response for deleting an organization -func SettingsDelete(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("org.settings") - ctx.Data["PageIsOrgSettings"] = true - ctx.Data["PageIsSettingsDelete"] = true +// SettingsDeleteOrgPost response for deleting an organization +func SettingsDeleteOrgPost(ctx *context.Context) { + if ctx.Org.Organization.Name != ctx.FormString("org_name") { + ctx.JSONError(ctx.Tr("form.enterred_invalid_org_name")) + return + } - if ctx.Req.Method == http.MethodPost { - if ctx.Org.Organization.Name != ctx.FormString("org_name") { - ctx.Data["Err_OrgName"] = true - ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_org_name"), tplSettingsDelete, nil) - return - } - - if err := org_service.DeleteOrganization(ctx, ctx.Org.Organization, false); err != nil { - if repo_model.IsErrUserOwnRepos(err) { - ctx.Flash.Error(ctx.Tr("form.org_still_own_repo")) - ctx.Redirect(ctx.Org.OrgLink + "/settings/delete") - } else if packages_model.IsErrUserOwnPackages(err) { - ctx.Flash.Error(ctx.Tr("form.org_still_own_packages")) - ctx.Redirect(ctx.Org.OrgLink + "/settings/delete") - } else { - ctx.ServerError("DeleteOrganization", err) - } + if err := org_service.DeleteOrganization(ctx, ctx.Org.Organization, false /* no purge */); err != nil { + if repo_model.IsErrUserOwnRepos(err) { + ctx.JSONError(ctx.Tr("form.org_still_own_repo")) + } else if packages_model.IsErrUserOwnPackages(err) { + ctx.JSONError(ctx.Tr("form.org_still_own_packages")) } else { - log.Trace("Organization deleted: %s", ctx.Org.Organization.Name) - ctx.Redirect(setting.AppSubURL + "/") + log.Error("DeleteOrganization: %v", err) + ctx.JSONError(util.Iif(ctx.Doer.IsAdmin, err.Error(), string(ctx.Tr("org.settings.delete_failed")))) } return } - if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil { - ctx.ServerError("RenderUserOrgHeader", err) - return - } - - ctx.HTML(http.StatusOK, tplSettingsDelete) + ctx.Flash.Success(ctx.Tr("org.settings.delete_successful", ctx.Org.Organization.Name)) + ctx.JSONRedirect(setting.AppSubURL + "/") } // Webhooks render webhook list page @@ -250,3 +214,40 @@ func Labels(ctx *context.Context) { ctx.HTML(http.StatusOK, tplSettingsLabels) } + +// SettingsRenamePost response for renaming organization +func SettingsRenamePost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.RenameOrgForm) + if ctx.HasError() { + ctx.JSONError(ctx.GetErrMsg()) + return + } + + oldOrgName, newOrgName := ctx.Org.Organization.Name, form.NewOrgName + + if form.OrgName != oldOrgName { + ctx.JSONError(ctx.Tr("form.enterred_invalid_org_name")) + return + } + if newOrgName == oldOrgName { + ctx.JSONError(ctx.Tr("org.settings.rename_no_change")) + return + } + + if err := user_service.RenameUser(ctx, ctx.Org.Organization.AsUser(), newOrgName); err != nil { + if user_model.IsErrUserAlreadyExist(err) { + ctx.JSONError(ctx.Tr("org.form.name_been_taken", newOrgName)) + } else if db.IsErrNameReserved(err) { + ctx.JSONError(ctx.Tr("org.form.name_reserved", newOrgName)) + } else if db.IsErrNamePatternNotAllowed(err) { + ctx.JSONError(ctx.Tr("org.form.name_pattern_not_allowed", newOrgName)) + } else { + log.Error("RenameOrganization: %v", err) + ctx.JSONError(util.Iif(ctx.Doer.IsAdmin, err.Error(), string(ctx.Tr("org.settings.rename_failed")))) + } + return + } + + ctx.Flash.Success(ctx.Tr("org.settings.rename_success", oldOrgName, newOrgName)) + ctx.JSONRedirect(setting.AppSubURL + "/org/" + url.PathEscape(newOrgName) + "/settings") +} diff --git a/routers/web/web.go b/routers/web/web.go index f00bea35c1..4b5d68b260 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -964,7 +964,8 @@ func registerWebRoutes(m *web.Router) { addSettingsVariablesRoutes() }, actions.MustEnableActions) - m.Methods("GET,POST", "/delete", org.SettingsDelete) + m.Post("/rename", web.Bind(forms.RenameOrgForm{}), org.SettingsRenamePost) + m.Post("/delete", org.SettingsDeleteOrgPost) m.Group("/packages", func() { m.Get("", org.Packages) diff --git a/services/forms/org.go b/services/forms/org.go index db182f7e96..2ac18ef25c 100644 --- a/services/forms/org.go +++ b/services/forms/org.go @@ -36,7 +36,6 @@ func (f *CreateOrgForm) Validate(req *http.Request, errs binding.Errors) binding // UpdateOrgSettingForm form for updating organization settings type UpdateOrgSettingForm struct { - Name string `binding:"Required;Username;MaxSize(40)" locale:"org.org_name_holder"` FullName string `binding:"MaxSize(100)"` Email string `binding:"MaxSize(255)"` Description string `binding:"MaxSize(255)"` @@ -53,6 +52,11 @@ func (f *UpdateOrgSettingForm) Validate(req *http.Request, errs binding.Errors) return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } +type RenameOrgForm struct { + OrgName string `binding:"Required"` + NewOrgName string `binding:"Required;Username;MaxSize(40)" locale:"org.org_name_holder"` +} + // ___________ // \__ ___/___ _____ _____ // | |_/ __ \\__ \ / \ diff --git a/templates/org/settings/delete.tmpl b/templates/org/settings/delete.tmpl deleted file mode 100644 index e1ef471e34..0000000000 --- a/templates/org/settings/delete.tmpl +++ /dev/null @@ -1,35 +0,0 @@ -{{template "org/settings/layout_head" (dict "ctxData" . "pageClass" "organization settings delete")}} - -
-

- {{ctx.Locale.Tr "org.settings.delete_account"}} -

-
-
-

{{svg "octicon-alert"}} {{ctx.Locale.Tr "org.settings.delete_prompt"}}

-
-
- {{.CsrfTokenHtml}} -
- - -
- -
-
-
- - - -{{template "org/settings/layout_footer" .}} diff --git a/templates/org/settings/navbar.tmpl b/templates/org/settings/navbar.tmpl index ce792f667c..58475de7e7 100644 --- a/templates/org/settings/navbar.tmpl +++ b/templates/org/settings/navbar.tmpl @@ -41,8 +41,5 @@ {{end}} - - {{ctx.Locale.Tr "org.settings.delete"}} - diff --git a/templates/org/settings/options.tmpl b/templates/org/settings/options.tmpl index f4583bbe36..d94bb4c62b 100644 --- a/templates/org/settings/options.tmpl +++ b/templates/org/settings/options.tmpl @@ -1,101 +1,97 @@ {{template "org/settings/layout_head" (dict "ctxData" . "pageClass" "organization settings options")}} -
-

- {{ctx.Locale.Tr "org.settings.options"}} -

-
-
- {{.CsrfTokenHtml}} -
- - -
-
- - -
-
- - -
-
- {{/* it is rendered as markdown, but the length is limited, so at the moment we do not use the markdown editor here */}} - - -
-
- - -
-
- - -
-
-
- -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
+
+

+ {{ctx.Locale.Tr "org.settings.options"}} +

+
+ + {{.CsrfTokenHtml}} +
+ + +
+
+ + +
+
+ {{/* it is rendered as markdown, but the length is limited, so at the moment we do not use the markdown editor here */}} + + +
+
+ + +
+
+ + +
-
- -
-
- - -
-
-
- - {{if .SignedUser.IsAdmin}} -
- -
- - -

{{ctx.Locale.Tr "admin.users.max_repo_creation_desc"}}

-
- {{end}} - -
- -
- - -
- -
- {{.CsrfTokenHtml}} -
- {{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}} -
-
- - -
-
+
+
+ +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+ +
+ +
+
+ + +
+
+
+ + {{if .SignedUser.IsAdmin}} +
+ +
+ + +

{{ctx.Locale.Tr "admin.users.max_repo_creation_desc"}}

+
+ {{end}} + +
+ +
+ + +
+ +
+ {{.CsrfTokenHtml}} +
+ {{template "shared/avatar_upload_crop" dict "LabelText" (ctx.Locale.Tr "settings.choose_new_avatar")}} +
+
+ + +
+
+
+
+ +{{template "org/settings/options_dangerzone" .}} + {{template "org/settings/layout_footer" .}} diff --git a/templates/org/settings/options_dangerzone.tmpl b/templates/org/settings/options_dangerzone.tmpl new file mode 100644 index 0000000000..01cf3fd405 --- /dev/null +++ b/templates/org/settings/options_dangerzone.tmpl @@ -0,0 +1,93 @@ +

+ {{ctx.Locale.Tr "repo.settings.danger_zone"}} +

+
+
+
+
+
{{ctx.Locale.Tr "org.settings.rename"}}
+
{{ctx.Locale.Tr "org.settings.rename_desc"}}
+
+
+ +
+
+ +
+
+
{{ctx.Locale.Tr "org.settings.delete_account"}}
+
{{ctx.Locale.Tr "org.settings.delete_prompt"}}
+
+
+ +
+
+
+
+ + + + diff --git a/templates/post-install.tmpl b/templates/post-install.tmpl index 0c9aa35c90..9baac4f84c 100644 --- a/templates/post-install.tmpl +++ b/templates/post-install.tmpl @@ -4,7 +4,7 @@
diff --git a/templates/user/auth/signup_inner.tmpl b/templates/user/auth/signup_inner.tmpl index d66568199d..a3f6e1471f 100644 --- a/templates/user/auth/signup_inner.tmpl +++ b/templates/user/auth/signup_inner.tmpl @@ -7,6 +7,9 @@ {{end}}
+ {{if .IsFirstTimeRegistration}} +

{{ctx.Locale.Tr "auth.sign_up_tip"}}

+ {{end}}
{{.CsrfTokenHtml}} {{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister)}} diff --git a/web_src/css/base.css b/web_src/css/base.css index b50abf79f1..dc58fb850a 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -30,6 +30,10 @@ --page-spacing: 16px; /* space between page elements */ --page-margin-x: 32px; /* minimum space on left and right side of page */ --page-space-bottom: 64px; /* space between last page element and footer */ + + /* z-index */ + --z-index-modal: 1001; /* modal dialog, hard-coded from Fomantic modal.css */ + --z-index-toast: 1002; /* should be larger than modal */ } @media (min-width: 768px) and (max-width: 1200px) { diff --git a/web_src/css/modules/dimmer.css b/web_src/css/modules/dimmer.css index 8924821370..7d1ca6171a 100644 --- a/web_src/css/modules/dimmer.css +++ b/web_src/css/modules/dimmer.css @@ -20,7 +20,7 @@ opacity: 1; } -.ui.dimmer > * { +.ui.dimmer > .ui.modal { position: static; margin-top: auto !important; margin-bottom: auto !important; diff --git a/web_src/css/modules/toast.css b/web_src/css/modules/toast.css index 1145f3b1b5..330d3b176e 100644 --- a/web_src/css/modules/toast.css +++ b/web_src/css/modules/toast.css @@ -3,7 +3,7 @@ position: fixed; opacity: 0; transition: all .2s ease; - z-index: 500; + z-index: var(--z-index-toast); border-radius: var(--border-radius); box-shadow: 0 8px 24px var(--color-shadow); display: flex; diff --git a/web_src/fomantic/build/components/dropdown.js b/web_src/fomantic/build/components/dropdown.js index 85530c7991..3ad0984865 100644 --- a/web_src/fomantic/build/components/dropdown.js +++ b/web_src/fomantic/build/components/dropdown.js @@ -525,7 +525,7 @@ $.fn.dropdown = function(parameters) { return true; } if(settings.onShow.call(element) !== false) { - settings.onAfterFiltered.call(element); // GITEA-PATCH: callback to correctly handle the filtered items + $module.fomanticExt.onDropdownAfterFiltered.call(element); // GITEA-PATCH: callback to correctly handle the filtered items module.animate.show(function() { if( module.can.click() ) { module.bind.intent(); @@ -753,7 +753,7 @@ $.fn.dropdown = function(parameters) { if(module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() ) { module.show(); } - settings.onAfterFiltered.call(element); // GITEA-PATCH: callback to correctly handle the filtered items + $module.fomanticExt.onDropdownAfterFiltered.call(element); // GITEA-PATCH: callback to correctly handle the filtered items } ; if(settings.useLabels && module.has.maxSelections()) { @@ -3994,8 +3994,6 @@ $.fn.dropdown.settings = { onShow : function(){}, onHide : function(){}, - onAfterFiltered: function(){}, // GITEA-PATCH: callback to correctly handle the filtered items - /* Component */ name : 'Dropdown', namespace : 'dropdown', diff --git a/web_src/fomantic/build/components/modal.js b/web_src/fomantic/build/components/modal.js index 420ecc250b..3f578ccfcc 100644 --- a/web_src/fomantic/build/components/modal.js +++ b/web_src/fomantic/build/components/modal.js @@ -467,7 +467,7 @@ $.fn.modal = function(parameters) { ignoreRepeatedEvents = false; return false; } - + $module.fomanticExt.onModalBeforeHidden.call(element); // GITEA-PATCH: handle more UI updates before hidden if( module.is.animating() || module.is.active() ) { if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) { module.remove.active(); @@ -641,7 +641,7 @@ $.fn.modal = function(parameters) { $module .off('mousedown' + elementEventNamespace) ; - } + } $dimmer .off('mousedown' + elementEventNamespace) ; @@ -877,7 +877,7 @@ $.fn.modal = function(parameters) { ? $(document).scrollTop() + settings.padding : $(document).scrollTop() + (module.cache.contextHeight - module.cache.height - settings.padding), marginLeft: -(module.cache.width / 2) - }) + }) ; } else { $module @@ -886,7 +886,7 @@ $.fn.modal = function(parameters) { ? -(module.cache.height / 2) : settings.padding / 2, marginLeft: -(module.cache.width / 2) - }) + }) ; } module.verbose('Setting modal offset for legacy mode'); diff --git a/web_src/js/features/common-fetch-action.ts b/web_src/js/features/common-fetch-action.ts index 5b6430779f..9359713454 100644 --- a/web_src/js/features/common-fetch-action.ts +++ b/web_src/js/features/common-fetch-action.ts @@ -1,5 +1,5 @@ import {request} from '../modules/fetch.ts'; -import {showErrorToast} from '../modules/toast.ts'; +import {hideToastsAll, showErrorToast} from '../modules/toast.ts'; import {addDelegatedEventListener, submitEventSubmitter} from '../utils/dom.ts'; import {confirmModal} from './comp/ConfirmModal.ts'; import type {RequestOpts} from '../types.ts'; @@ -24,6 +24,7 @@ function fetchActionDoRedirect(redirect: string) { async function fetchActionDoRequest(actionElem: HTMLElement, url: string, opt: RequestOpts) { try { + hideToastsAll(); const resp = await request(url, opt); if (resp.status === 200) { let {redirect} = await resp.json(); @@ -35,7 +36,9 @@ async function fetchActionDoRequest(actionElem: HTMLElement, url: string, opt: R window.location.reload(); } return; - } else if (resp.status >= 400 && resp.status < 500) { + } + + if (resp.status >= 400 && resp.status < 500) { const data = await resp.json(); // the code was quite messy, sometimes the backend uses "err", sometimes it uses "error", and even "user_error" // but at the moment, as a new approach, we only use "errorMessage" here, backend can use JSONError() to respond. diff --git a/web_src/js/features/install.ts b/web_src/js/features/install.ts index 34df4757f9..ca4bcce881 100644 --- a/web_src/js/features/install.ts +++ b/web_src/js/features/install.ts @@ -104,7 +104,7 @@ function initPreInstall() { } function initPostInstall() { - const el = document.querySelector('#goto-user-login'); + const el = document.querySelector('#goto-after-install'); if (!el) return; const targetUrl = el.getAttribute('href'); diff --git a/web_src/js/modules/fomantic/dropdown.ts b/web_src/js/modules/fomantic/dropdown.ts index 02fee5a267..ccc22073d7 100644 --- a/web_src/js/modules/fomantic/dropdown.ts +++ b/web_src/js/modules/fomantic/dropdown.ts @@ -9,9 +9,9 @@ const fomanticDropdownFn = $.fn.dropdown; // use our own `$().dropdown` function to patch Fomantic's dropdown module export function initAriaDropdownPatch() { if ($.fn.dropdown === ariaDropdownFn) throw new Error('initAriaDropdownPatch could only be called once'); - $.fn.dropdown.settings.onAfterFiltered = onAfterFiltered; $.fn.dropdown = ariaDropdownFn; $.fn.fomanticExt.onResponseKeepSelectedItem = onResponseKeepSelectedItem; + $.fn.fomanticExt.onDropdownAfterFiltered = onDropdownAfterFiltered; (ariaDropdownFn as FomanticInitFunction).settings = fomanticDropdownFn.settings; } @@ -71,7 +71,7 @@ function updateSelectionLabel(label: HTMLElement) { } } -function onAfterFiltered(this: any) { +function onDropdownAfterFiltered(this: any) { const $dropdown = $(this).closest('.ui.dropdown'); // "this" can be the "ui dropdown" or "