feat(update): allow opting into the dev channel from a stable build

The panel version button opened the GitHub releases page on a stable, up-to-date build, and the dev-channel toggle only rendered on dev builds, so there was no in-panel path from stable to dev. Drop the IsDevBuild() guard in devChannelActive (the toggle alone drives the channel now), always open the update modal instead of releases, and always render the Dev channel switch.
This commit is contained in:
MHSanaei
2026-06-26 18:01:51 +02:00
parent 522b1b64b0
commit 8e4c368200
3 changed files with 15 additions and 27 deletions
+2 -9
View File
@@ -66,7 +66,6 @@ export default function IndexPage() {
useEffect(() => { setMessageInstance(messageApi); }, [messageApi]);
const [accessLogEnable, setAccessLogEnable] = useState(false);
const [isDevBuild, setIsDevBuild] = useState(false);
const [devChannelEnable, setDevChannelEnable] = useState(false);
const [panelUpdateInfo, setPanelUpdateInfo] = useState<PanelUpdateInfo>({
currentVersion: '',
@@ -90,12 +89,11 @@ export default function IndexPage() {
const [loadingTip, setLoadingTip] = useState(t('loading'));
useEffect(() => {
HttpUtil.post<{ accessLogEnable?: boolean; isDevBuild?: boolean; devChannelEnable?: boolean }>(
HttpUtil.post<{ accessLogEnable?: boolean; devChannelEnable?: boolean }>(
'/panel/api/setting/defaultSettings',
).then((msg) => {
if (msg?.success && msg.obj) {
setAccessLogEnable(!!msg.obj.accessLogEnable);
setIsDevBuild(!!msg.obj.isDevBuild);
setDevChannelEnable(!!msg.obj.devChannelEnable);
}
});
@@ -128,11 +126,7 @@ export default function IndexPage() {
}, [refresh]);
function openPanelVersion() {
if (panelUpdateInfo.updateAvailable || isDevBuild) {
setPanelUpdateOpen(true);
} else {
window.open('https://github.com/MHSanaei/3x-ui/releases', '_blank', 'noopener,noreferrer');
}
setPanelUpdateOpen(true);
}
async function handleChannelChange(dev: boolean) {
@@ -463,7 +457,6 @@ export default function IndexPage() {
<PanelUpdateModal
open={panelUpdateOpen}
info={panelUpdateInfo}
isDevBuild={isDevBuild}
devChannelEnable={devChannelEnable}
onChannelChange={handleChannelChange}
onClose={() => setPanelUpdateOpen(false)}
+9 -13
View File
@@ -25,7 +25,6 @@ interface BusyEvent {
interface PanelUpdateModalProps {
open: boolean;
info: PanelUpdateInfo;
isDevBuild?: boolean;
devChannelEnable?: boolean;
onChannelChange?: (dev: boolean) => void | Promise<void>;
onClose: () => void;
@@ -35,7 +34,6 @@ interface PanelUpdateModalProps {
export default function PanelUpdateModal({
open,
info,
isDevBuild,
devChannelEnable,
onChannelChange,
onClose,
@@ -113,18 +111,16 @@ export default function PanelUpdateModal({
/>
)}
{isDevBuild && (
<div className="version-list">
<div className="version-list-item">
<span>{t('pages.index.devChannel')}</span>
<Switch
checked={!!devChannelEnable}
loading={channelBusy}
onChange={handleChannel}
/>
</div>
<div className="version-list">
<div className="version-list-item">
<span>{t('pages.index.devChannel')}</span>
<Switch
checked={!!devChannelEnable}
loading={channelBusy}
onChange={handleChannel}
/>
</div>
)}
</div>
{devChannelEnable && (
<Alert
+4 -5
View File
@@ -90,12 +90,11 @@ func (s *PanelService) GetUpdateInfo() (*PanelUpdateInfo, error) {
}
// devChannelActive reports whether self-update should track the rolling dev
// release. It requires both the opt-in setting and a dev build, so a stable
// binary with the toggle left on never cross-grades to the dev channel.
// release. It is driven solely by the opt-in setting so the panel can
// cross-grade a stable build onto the dev channel once the user enables it;
// nothing updates without an explicit user action, so an unattended stable
// binary with the toggle off stays on the stable channel.
func devChannelActive() bool {
if !config.IsDevBuild() {
return false
}
enabled, err := (&service.SettingService{}).GetDevChannelEnable()
return err == nil && enabled
}