diff --git a/src/components/ha-form/ha-form.ts b/src/components/ha-form/ha-form.ts index 3062c2317d..98c177f482 100644 --- a/src/components/ha-form/ha-form.ts +++ b/src/components/ha-form/ha-form.ts @@ -34,6 +34,8 @@ const getValue = (obj, item) => const getError = (obj, item) => (obj && item.name ? obj[item.name] : null); +const getWarning = (obj, item) => (obj && item.name ? obj[item.name] : null); + @customElement("ha-form") export class HaForm extends LitElement implements HaFormElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -44,10 +46,14 @@ export class HaForm extends LitElement implements HaFormElement { @property() public error?: Record; + @property() public warning?: Record; + @property({ type: Boolean }) public disabled = false; @property() public computeError?: (schema: any, error) => string; + @property() public computeWarning?: (schema: any, warning) => string; + @property() public computeLabel?: ( schema: any, data: HaFormDataContainer @@ -98,6 +104,7 @@ export class HaForm extends LitElement implements HaFormElement { : ""} ${this.schema.map((item) => { const error = getError(this.error, item); + const warning = getWarning(this.warning, item); return html` ${error @@ -106,6 +113,12 @@ export class HaForm extends LitElement implements HaFormElement { ${this._computeError(error, item)} ` + : warning + ? html` + + ${this._computeWarning(warning, item)} + + ` : ""} ${"selector" in item ? html` * { diff --git a/src/data/supervisor/mounts.ts b/src/data/supervisor/mounts.ts index 474991fd93..ea4fc8da6f 100644 --- a/src/data/supervisor/mounts.ts +++ b/src/data/supervisor/mounts.ts @@ -22,6 +22,8 @@ interface MountOptions { default_backup_mount?: string | null; } +export type CIFSVersion = "auto" | "1.0" | "2.0"; + interface SupervisorMountBase { name: string; usage: SupervisorMountUsage; @@ -42,6 +44,7 @@ export interface SupervisorNFSMount extends SupervisorMountResponse { export interface SupervisorCIFSMount extends SupervisorMountResponse { type: SupervisorMountType.CIFS; share: string; + version?: CIFSVersion; } export type SupervisorMount = SupervisorNFSMount | SupervisorCIFSMount; @@ -51,6 +54,7 @@ export type SupervisorNFSMountRequestParams = SupervisorNFSMount; export interface SupervisorCIFSMountRequestParams extends SupervisorCIFSMount { username?: string; password?: string; + version?: CIFSVersion; } export type SupervisorMountRequestParams = diff --git a/src/panels/config/storage/dialog-mount-view.ts b/src/panels/config/storage/dialog-mount-view.ts index 52592a9b67..e0b0b6302d 100644 --- a/src/panels/config/storage/dialog-mount-view.ts +++ b/src/panels/config/storage/dialog-mount-view.ts @@ -26,7 +26,8 @@ const mountSchema = memoizeOne( ( localize: LocalizeFunc, existing?: boolean, - mountType?: SupervisorMountType + mountType?: SupervisorMountType, + showCIFSVersion?: boolean ) => [ { @@ -90,6 +91,41 @@ const mountSchema = memoizeOne( ] as const) : mountType === "cifs" ? ([ + ...(showCIFSVersion + ? ([ + { + name: "version", + required: true, + selector: { + select: { + options: [ + { + label: localize( + "ui.panel.config.storage.network_mounts.cifs_versions.auto" + ), + value: "auto", + }, + { + label: localize( + "ui.panel.config.storage.network_mounts.cifs_versions.legacy", + { version: "2.0" } + ), + value: "2.0", + }, + { + label: localize( + "ui.panel.config.storage.network_mounts.cifs_versions.legacy", + { version: "1.0" } + ), + value: "1.0", + }, + ], + mode: "dropdown", + }, + }, + }, + ] as const) + : ([] as const)), { name: "share", required: true, @@ -122,8 +158,12 @@ class ViewMountDialog extends LitElement { @state() private _validationError?: Record; + @state() private _validationWarning?: Record; + @state() private _existing?: boolean; + @state() private _showCIFSVersion?: boolean; + @state() private _reloadMounts?: () => void; public async showDialog( @@ -132,6 +172,13 @@ class ViewMountDialog extends LitElement { this._data = dialogParams.mount; this._existing = dialogParams.mount !== undefined; this._reloadMounts = dialogParams.reloadMounts; + if ( + dialogParams.mount?.type === "cifs" && + dialogParams.mount.version && + dialogParams.mount.version !== "auto" + ) { + this._showCIFSVersion = true; + } } public closeDialog(): void { @@ -139,7 +186,9 @@ class ViewMountDialog extends LitElement { this._waiting = undefined; this._error = undefined; this._validationError = undefined; + this._validationWarning = undefined; this._existing = undefined; + this._showCIFSVersion = undefined; this._reloadMounts = undefined; fireEvent(this, "dialog-closed", { dialog: this.localName }); } @@ -197,12 +246,15 @@ class ViewMountDialog extends LitElement { .schema=${mountSchema( this.hass.localize, this._existing, - this._data?.type + this._data?.type, + this._showCIFSVersion )} .error=${this._validationError} + .warning=${this._validationWarning} .computeLabel=${this._computeLabelCallback} .computeHelper=${this._computeHelperCallback} .computeError=${this._computeErrorCallback} + .computeWarning=${this._computeWarningCallback} @value-changed=${this._valueChanged} dialogInitialFocus > @@ -256,12 +308,29 @@ class ViewMountDialog extends LitElement { `ui.panel.config.storage.network_mounts.errors.${error}` ) || error; + private _computeWarningCallback = (warning: string): string => + this.hass.localize( + // @ts-ignore + `ui.panel.config.storage.network_mounts.warnings.${warning}` + ) || warning; + private _valueChanged(ev: CustomEvent) { this._validationError = {}; + this._validationWarning = {}; this._data = ev.detail.value; if (this._data?.name && !/^\w+$/.test(this._data.name)) { this._validationError.name = "invalid_name"; } + if (this._data?.type === "cifs" && !this._data.version) { + this._data.version = "auto"; + } + if ( + this._data?.type === "cifs" && + this._data.version && + ["1.0", "2.0"].includes(this._data.version) + ) { + this._validationWarning.version = "not_recomeded_cifs_version"; + } } private async _connectMount() { @@ -276,6 +345,9 @@ class ViewMountDialog extends LitElement { } catch (err: any) { this._error = extractApiErrorMessage(err); this._waiting = false; + if (this._data!.type === "cifs" && !this._showCIFSVersion) { + this._showCIFSVersion = true; + } return; } if (this._reloadMounts) { diff --git a/src/translations/en.json b/src/translations/en.json index 6e3b200d7f..6a4f63360d 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -4131,6 +4131,10 @@ "nfs": "Network File Share (NFS)", "cifs": "Samba/Windows (CIFS)" }, + "cifs_versions": { + "auto": "Auto (2.1+)", + "legacy": "Legacy ({version})" + }, "options": { "name": { "title": "Name", @@ -4160,6 +4164,10 @@ "title": "Usage", "description": "This determines how the share is intended to be used" }, + "version": { + "title": "Samba/Windows (CIFS) version", + "description": "This choses the version of the protocol to use" + }, "username": { "title": "Username", "description": "This is your username for the samba share" @@ -4174,6 +4182,9 @@ "errors": { "reload": "Could not reload mount {mount}", "invalid_name": "Invalid name, can only contain alphanumeric characters and underscores" + }, + "warnings": { + "not_recomeded_cifs_version": "The selected CIFS version is not recommended to use, you should only use this if you have problems with auto and your server does not support version 2.1 or newer" } } },