-
-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement a new version/pre-release selector #762
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -8,8 +8,13 @@ import { mainWindow } from "../../../homeassistant-frontend/src/common/dom/get_m | |||||||||||||||||
import { computeRTL } from "../../../homeassistant-frontend/src/common/util/compute_rtl"; | ||||||||||||||||||
import "../../../homeassistant-frontend/src/components/ha-alert"; | ||||||||||||||||||
import "../../../homeassistant-frontend/src/components/ha-button"; | ||||||||||||||||||
import "../../../homeassistant-frontend/src/components/ha-circular-progress"; | ||||||||||||||||||
import "../../../homeassistant-frontend/src/components/ha-dialog"; | ||||||||||||||||||
import "../../../homeassistant-frontend/src/components/ha-expansion-panel"; | ||||||||||||||||||
import "../../../homeassistant-frontend/src/components/ha-form/ha-form"; | ||||||||||||||||||
import "../../../homeassistant-frontend/src/components/ha-list-item"; | ||||||||||||||||||
|
||||||||||||||||||
import { relativeTime } from "../../../homeassistant-frontend/src/common/datetime/relative_time"; | ||||||||||||||||||
import { showConfirmationDialog } from "../../../homeassistant-frontend/src/dialogs/generic/show-dialog-box"; | ||||||||||||||||||
import type { HomeAssistant } from "../../../homeassistant-frontend/src/types"; | ||||||||||||||||||
import { HacsDispatchEvent } from "../../data/common"; | ||||||||||||||||||
|
@@ -18,12 +23,61 @@ import { | |||||||||||||||||
RepositoryBase, | ||||||||||||||||||
repositoryDownloadVersion, | ||||||||||||||||||
RepositoryInfo, | ||||||||||||||||||
repositoryReleases, | ||||||||||||||||||
} from "../../data/repository"; | ||||||||||||||||||
import { websocketSubscription } from "../../data/websocket"; | ||||||||||||||||||
import { HacsStyles } from "../../styles/hacs-common-style"; | ||||||||||||||||||
import { generateFrontendResourceURL } from "../../tools/frontend-resource"; | ||||||||||||||||||
import type { HacsDownloadDialogParams } from "./show-hacs-dialog"; | ||||||||||||||||||
|
||||||||||||||||||
@customElement("release-item") | ||||||||||||||||||
export class ReleaseItem extends LitElement { | ||||||||||||||||||
@property({ attribute: false }) public locale!: HomeAssistant["locale"]; | ||||||||||||||||||
@property({ attribute: false }) public release!: { | ||||||||||||||||||
tag: string; | ||||||||||||||||||
published_at: string; | ||||||||||||||||||
name: string; | ||||||||||||||||||
prerelease: boolean; | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
protected render() { | ||||||||||||||||||
return html` | ||||||||||||||||||
<span> | ||||||||||||||||||
${this.release.tag} | ||||||||||||||||||
${this.release.prerelease ? html`<span class="pre-release">pre-release</span>` : nothing} | ||||||||||||||||||
</span> | ||||||||||||||||||
<span class="secondary"> | ||||||||||||||||||
${relativeTime(new Date(this.release.published_at), this.locale)} | ||||||||||||||||||
${this.release.name && this.release.name !== this.release.tag | ||||||||||||||||||
? html` - ${this.release.name}` | ||||||||||||||||||
: nothing} | ||||||||||||||||||
</span> | ||||||||||||||||||
`; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
static get styles(): CSSResultGroup { | ||||||||||||||||||
return css` | ||||||||||||||||||
:host { | ||||||||||||||||||
display: flex; | ||||||||||||||||||
flex-direction: column; | ||||||||||||||||||
} | ||||||||||||||||||
.secondary { | ||||||||||||||||||
font-size: 0.8em; | ||||||||||||||||||
color: var(--secondary-text-color); | ||||||||||||||||||
font-style: italic; | ||||||||||||||||||
} | ||||||||||||||||||
.pre-release { | ||||||||||||||||||
background-color: var(--accent-color); | ||||||||||||||||||
padding: 2px 4px; | ||||||||||||||||||
font-size: 0.8em; | ||||||||||||||||||
font-weight: 600; | ||||||||||||||||||
border-radius: 12px; | ||||||||||||||||||
margin: 0 2px; | ||||||||||||||||||
color: var(--secondary-background-color); | ||||||||||||||||||
} | ||||||||||||||||||
`; | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
@customElement("hacs-download-dialog") | ||||||||||||||||||
export class HacsDonwloadDialog extends LitElement { | ||||||||||||||||||
@property({ attribute: false }) public hass!: HomeAssistant; | ||||||||||||||||||
|
@@ -34,6 +88,13 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
|
||||||||||||||||||
@state() private _error?: any; | ||||||||||||||||||
|
||||||||||||||||||
@state() private _releases?: { | ||||||||||||||||||
tag: string; | ||||||||||||||||||
name: string; | ||||||||||||||||||
published_at: string; | ||||||||||||||||||
prerelease: boolean; | ||||||||||||||||||
}[]; | ||||||||||||||||||
|
||||||||||||||||||
@state() public _repository?: RepositoryInfo; | ||||||||||||||||||
|
||||||||||||||||||
@state() _dialogParams?: HacsDownloadDialogParams; | ||||||||||||||||||
|
@@ -52,6 +113,7 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
if (this._repository && this._repository.version_or_commit !== "commit") { | ||||||||||||||||||
this._selectedVersion = this._repository.available_version; | ||||||||||||||||||
} | ||||||||||||||||||
this._releases = undefined; | ||||||||||||||||||
|
||||||||||||||||||
websocketSubscription( | ||||||||||||||||||
this.hass, | ||||||||||||||||||
|
@@ -70,6 +132,8 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
this._error = undefined; | ||||||||||||||||||
this._installing = false; | ||||||||||||||||||
this._waiting = false; | ||||||||||||||||||
this._releases = undefined; | ||||||||||||||||||
this._selectedVersion = undefined; | ||||||||||||||||||
fireEvent(this, "dialog-closed", { dialog: this.localName }); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
|
@@ -82,16 +146,35 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
private async _fetchRepository() { | ||||||||||||||||||
this._repository = await fetchRepositoryInformation( | ||||||||||||||||||
this.hass, | ||||||||||||||||||
this._dialogParams!.repositoryId, | ||||||||||||||||||
); | ||||||||||||||||||
try { | ||||||||||||||||||
this._repository = await fetchRepositoryInformation( | ||||||||||||||||||
this.hass, | ||||||||||||||||||
this._dialogParams!.repositoryId, | ||||||||||||||||||
); | ||||||||||||||||||
} catch (err: any) { | ||||||||||||||||||
this._error = err; | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
protected render() { | ||||||||||||||||||
if (!this._dialogParams || !this._repository) { | ||||||||||||||||||
if (!this._dialogParams) { | ||||||||||||||||||
return nothing; | ||||||||||||||||||
} | ||||||||||||||||||
if (!this._repository) { | ||||||||||||||||||
return html` | ||||||||||||||||||
<ha-dialog open scrimClickAction escapeKeyAction heading="Loading..."> | ||||||||||||||||||
<div class="loading"> | ||||||||||||||||||
<ha-circular-progress indeterminate></ha-circular-progress> | ||||||||||||||||||
${this._error | ||||||||||||||||||
? html`<ha-alert alert-type="error" .rtl=${computeRTL(this.hass)}> | ||||||||||||||||||
${this._error.message || this._error} | ||||||||||||||||||
</ha-alert>` | ||||||||||||||||||
: nothing} | ||||||||||||||||||
</div> | ||||||||||||||||||
</ha-dialog> | ||||||||||||||||||
`; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
const installPath = this._getInstallPath(this._repository); | ||||||||||||||||||
return html` | ||||||||||||||||||
<ha-dialog | ||||||||||||||||||
|
@@ -102,14 +185,18 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
@closed=${this.closeDialog} | ||||||||||||||||||
> | ||||||||||||||||||
<div class="content"> | ||||||||||||||||||
${!this._repository.can_download | ||||||||||||||||||
? html`<ha-alert alert-type="error" .rtl=${computeRTL(this.hass)}> | ||||||||||||||||||
${this._dialogParams.hacs.localize("confirm.home_assistant_version_not_correct", { | ||||||||||||||||||
haversion: this.hass.config.version, | ||||||||||||||||||
minversion: this._repository.homeassistant, | ||||||||||||||||||
})} | ||||||||||||||||||
</ha-alert>` | ||||||||||||||||||
: ""} | ||||||||||||||||||
<p> | ||||||||||||||||||
${this._dialogParams.hacs.localize( | ||||||||||||||||||
this._repository.version_or_commit === "commit" | ||||||||||||||||||
? "dialog_download.will_download_commit" | ||||||||||||||||||
: "dialog_download.will_download_version", | ||||||||||||||||||
{ | ||||||||||||||||||
ref: html` | ||||||||||||||||||
<code>${this._selectedVersion || this._repository.available_version}</code> | ||||||||||||||||||
`, | ||||||||||||||||||
}, | ||||||||||||||||||
)} | ||||||||||||||||||
</p> | ||||||||||||||||||
<div class="note"> | ||||||||||||||||||
${this._dialogParams.hacs.localize("dialog_download.note_downloaded", { | ||||||||||||||||||
location: html`<code>'${installPath}'</code>`, | ||||||||||||||||||
|
@@ -118,7 +205,7 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
this._dialogParams.hacs.info.lovelace_mode !== "storage" | ||||||||||||||||||
? html` | ||||||||||||||||||
<p>${this._dialogParams.hacs.localize(`dialog_download.lovelace_instruction`)}</p> | ||||||||||||||||||
<pre> | ||||||||||||||||||
<pre class="frontend-resource"> | ||||||||||||||||||
url: ${generateFrontendResourceURL({ repository: this._repository })} | ||||||||||||||||||
type: module | ||||||||||||||||||
</pre | ||||||||||||||||||
|
@@ -129,9 +216,44 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
? html`<p>${this._dialogParams.hacs.localize("dialog_download.restart")}</p>` | ||||||||||||||||||
: nothing} | ||||||||||||||||||
</div> | ||||||||||||||||||
${this._error?.message | ||||||||||||||||||
${this._selectedVersion | ||||||||||||||||||
? html`<ha-expansion-panel | ||||||||||||||||||
@expanded-changed=${this._fetchReleases} | ||||||||||||||||||
.header=${this._dialogParams.hacs.localize(`dialog_download.different_version`)} | ||||||||||||||||||
> | ||||||||||||||||||
Comment on lines
+221
to
+223
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Address forbidden non-null assertion. Replace the non-null assertion with the optional chain operator for safer runtime checks. - .header=${this._dialogParams.hacs.localize(`dialog_download.different_version`)}
+ .header=${this._dialogParams?.hacs.localize(`dialog_download.different_version`)}
|
||||||||||||||||||
<p>${this._dialogParams!.hacs.localize("dialog_download.release_warning")}</p> | ||||||||||||||||||
Comment on lines
+221
to
+224
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Address forbidden non-null assertion. Replace the non-null assertion with the optional chain operator for safer runtime checks. - .header=${this._dialogParams.hacs.localize(`dialog_download.different_version`)}
+ .header=${this._dialogParams?.hacs.localize(`dialog_download.different_version`)} Committable suggestion
Suggested change
ToolsBiome
|
||||||||||||||||||
${this._releases === undefined | ||||||||||||||||||
? this._dialogParams.hacs.localize("dialog_download.fetching_releases") | ||||||||||||||||||
: this._releases.length === 0 | ||||||||||||||||||
? this._dialogParams.hacs.localize("dialog_download.no_releases") | ||||||||||||||||||
: html`<ha-form | ||||||||||||||||||
@value-changed=${this._versionChanged} | ||||||||||||||||||
.computeLabel=${this._computeLabel} | ||||||||||||||||||
.schema=${[ | ||||||||||||||||||
{ | ||||||||||||||||||
name: "release", | ||||||||||||||||||
selector: { | ||||||||||||||||||
select: { | ||||||||||||||||||
mode: "dropdown", | ||||||||||||||||||
options: this._releases?.map((release) => ({ | ||||||||||||||||||
value: release.tag, | ||||||||||||||||||
label: html`<release-item | ||||||||||||||||||
.locale=${this.hass.locale} | ||||||||||||||||||
.release=${release} | ||||||||||||||||||
> | ||||||||||||||||||
${release.tag} | ||||||||||||||||||
</release-item>`, | ||||||||||||||||||
})), | ||||||||||||||||||
}, | ||||||||||||||||||
}, | ||||||||||||||||||
}, | ||||||||||||||||||
]} | ||||||||||||||||||
></ha-form>`} | ||||||||||||||||||
</ha-expansion-panel>` | ||||||||||||||||||
: nothing} | ||||||||||||||||||
${this._error | ||||||||||||||||||
? html`<ha-alert alert-type="error" .rtl=${computeRTL(this.hass)}> | ||||||||||||||||||
${this._error.message} | ||||||||||||||||||
${this._error.message || this._error} | ||||||||||||||||||
</ha-alert>` | ||||||||||||||||||
: nothing} | ||||||||||||||||||
${this._installing | ||||||||||||||||||
|
@@ -143,7 +265,7 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
</mwc-button> | ||||||||||||||||||
<mwc-button | ||||||||||||||||||
slot="primaryAction" | ||||||||||||||||||
?disabled=${!this._repository.can_download || this._waiting || this._installing} | ||||||||||||||||||
?disabled=${this._waiting || this._installing} | ||||||||||||||||||
@click=${this._installRepository} | ||||||||||||||||||
> | ||||||||||||||||||
${this._dialogParams.hacs.localize("common.download")} | ||||||||||||||||||
|
@@ -152,6 +274,11 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
`; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
private _computeLabel = (entry: any): string => | ||||||||||||||||||
entry.name === "release" | ||||||||||||||||||
? this._dialogParams!.hacs.localize("dialog_download.release") | ||||||||||||||||||
Comment on lines
+277
to
+279
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Address forbidden non-null assertion. Replace the non-null assertion with the optional chain operator for safer runtime checks. - ? this._dialogParams!.hacs.localize("dialog_download.release")
+ ? this._dialogParams?.hacs.localize("dialog_download.release") Committable suggestion
Suggested change
ToolsBiome
|
||||||||||||||||||
: entry.name; | ||||||||||||||||||
|
||||||||||||||||||
private async _installRepository(): Promise<void> { | ||||||||||||||||||
if (!this._repository) { | ||||||||||||||||||
return; | ||||||||||||||||||
|
@@ -167,21 +294,14 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
if (!this._repository.can_download) { | ||||||||||||||||||
this._error = "Can not download this repository."; | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
this._installing = true; | ||||||||||||||||||
this._error = undefined; | ||||||||||||||||||
|
||||||||||||||||||
try { | ||||||||||||||||||
await repositoryDownloadVersion( | ||||||||||||||||||
this.hass, | ||||||||||||||||||
String(this._repository.id), | ||||||||||||||||||
this._repository?.version_or_commit !== "commit" | ||||||||||||||||||
? this._repository.available_version | ||||||||||||||||||
: undefined, | ||||||||||||||||||
this._selectedVersion || this._repository.available_version, | ||||||||||||||||||
); | ||||||||||||||||||
} catch (err: any) { | ||||||||||||||||||
this._error = err || { | ||||||||||||||||||
|
@@ -216,27 +336,45 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
async _fetchReleases() { | ||||||||||||||||||
if (this._releases !== undefined) { | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
try { | ||||||||||||||||||
this._releases = await repositoryReleases(this.hass, this._repository!.id); | ||||||||||||||||||
} catch (error) { | ||||||||||||||||||
this._error = error; | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
private _versionChanged(ev: CustomEvent) { | ||||||||||||||||||
this._selectedVersion = ev.detail.value.release; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
static get styles(): CSSResultGroup { | ||||||||||||||||||
return [ | ||||||||||||||||||
HacsStyles, | ||||||||||||||||||
css` | ||||||||||||||||||
.note { | ||||||||||||||||||
margin-top: 12px; | ||||||||||||||||||
} | ||||||||||||||||||
.lovelace { | ||||||||||||||||||
margin-top: 8px; | ||||||||||||||||||
} | ||||||||||||||||||
.learn_more { | ||||||||||||||||||
color: var(--hcv-text-color-primary); | ||||||||||||||||||
} | ||||||||||||||||||
pre { | ||||||||||||||||||
white-space: pre-line; | ||||||||||||||||||
user-select: all; | ||||||||||||||||||
padding: 8px; | ||||||||||||||||||
} | ||||||||||||||||||
mwc-linear-progress { | ||||||||||||||||||
margin-bottom: -8px; | ||||||||||||||||||
margin-top: 4px; | ||||||||||||||||||
} | ||||||||||||||||||
ha-expansion-panel { | ||||||||||||||||||
background-color: var(--secondary-background-color); | ||||||||||||||||||
padding: 8px; | ||||||||||||||||||
} | ||||||||||||||||||
.loading { | ||||||||||||||||||
text-align: center; | ||||||||||||||||||
padding: 16px; | ||||||||||||||||||
} | ||||||||||||||||||
`, | ||||||||||||||||||
]; | ||||||||||||||||||
} | ||||||||||||||||||
|
@@ -245,5 +383,6 @@ export class HacsDonwloadDialog extends LitElement { | |||||||||||||||||
declare global { | ||||||||||||||||||
interface HTMLElementTagNameMap { | ||||||||||||||||||
"hacs-download-dialog": HacsDonwloadDialog; | ||||||||||||||||||
"release-item": ReleaseItem; | ||||||||||||||||||
} | ||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,3 +68,11 @@ export const repositoryDownloadVersion = async ( | |
repository: repository, | ||
version, | ||
}); | ||
|
||
export const repositoryReleases = async (hass: HomeAssistant, repositoryId: string) => | ||
hass.connection.sendMessagePromise< | ||
{ tag: string; name: string; published_at: string; prerelease: boolean }[] | ||
>({ | ||
type: "hacs/repository/releases", | ||
repository_id: repositoryId, | ||
}); | ||
Comment on lines
+72
to
+78
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tip Codebase Verification Add error handling for Currently, the
Example: async _fetchReleases() {
if (this._releases !== undefined) {
return;
}
try {
this._releases = await repositoryReleases(this.hass, this._repository!.id);
} catch (error) {
console.error("Failed to fetch releases:", error);
this._error = error;
}
} Remember, even code needs a safety net sometimes! 🐰✨ Analysis chainVerify error handling and function usage. The function Alright, it looks like our previous search came up empty. Let's widen our net and see if we can catch any fish this time. We'll search through both JavaScript and TypeScript files and grab a bit more context around each instance of Alright, it looks like we found where Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Verify all function calls to `repositoryReleases` handle errors and match the expected response structure.
# Test: Search for the function usage. Expect: Proper error handling and matching response structure.
rg --type js -A 5 $'repositoryReleases'
Length of output: 38 Script: #!/bin/bash
# Description: Verify all function calls to `repositoryReleases` handle errors and match the expected response structure.
# Test: Search for the function usage in both JavaScript and TypeScript files. Expect: Proper error handling and matching response structure.
rg --type-add 'ts:*.{ts,tsx}' --type-add 'js:*.{js,jsx}' -tjs -tts -A 10 'repositoryReleases'
Length of output: 2402 Script: #!/bin/bash
# Description: Extract more lines around the usage of `repositoryReleases` in `hacs-download-dialog.ts` to verify error handling.
# Test: Extract 20 lines before and after the usage of `repositoryReleases` in `hacs-download-dialog.ts`.
rg --type ts -A 20 -B 20 'repositoryReleases' src/components/dialogs/hacs-download-dialog.ts
Length of output: 3207 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Address forbidden non-null assertion.
Replace the non-null assertion with the optional chain operator for safer runtime checks.
Committable suggestion
Tools
Biome