Skip to content

Commit

Permalink
Implement a new version/pre-release selector (#762)
Browse files Browse the repository at this point in the history
* Implement a new version/pre-release selector

* cleanup
  • Loading branch information
ludeeus authored Jul 19, 2024
1 parent 7c69710 commit 2a3483d
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 32 deletions.
201 changes: 170 additions & 31 deletions src/components/dialogs/hacs-download-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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,
Expand All @@ -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 });
}

Expand All @@ -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
Expand All @@ -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>`,
Expand All @@ -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
Expand All @@ -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`)}
>
<p>${this._dialogParams!.hacs.localize("dialog_download.release_warning")}</p>
${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
Expand All @@ -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")}
Expand All @@ -152,6 +274,11 @@ export class HacsDonwloadDialog extends LitElement {
`;
}

private _computeLabel = (entry: any): string =>
entry.name === "release"
? this._dialogParams!.hacs.localize("dialog_download.release")
: entry.name;

private async _installRepository(): Promise<void> {
if (!this._repository) {
return;
Expand All @@ -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 || {
Expand Down Expand Up @@ -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;
}
`,
];
}
Expand All @@ -245,5 +383,6 @@ export class HacsDonwloadDialog extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"hacs-download-dialog": HacsDonwloadDialog;
"release-item": ReleaseItem;
}
}
8 changes: 8 additions & 0 deletions src/data/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
9 changes: 8 additions & 1 deletion src/localize/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@
"dialog_download": {
"type": "Type",
"url": "URL",
"will_download_version": "Version {ref} will be downloaded",
"will_download_commit": "Commit {ref} will be downloaded",
"different_version": "Need a different version?",
"fetching_releases": "Fetching releases...",
"no_releases": "No releases found",
"release": "Release",
"release_warning": "It is not advised to use this section to do a rollback, restore a backup instead.",
"restart": "Remember that you need to restart Home Assistant before changes to integrations (custom_components) are applied.",
"selector_note": "The version selector will be removed in a future release. If you need to install a specific version, you can do so by using the service call for update entities.",
"note_downloaded": "When downloaded, this will be located in {location}",
Expand Down Expand Up @@ -165,4 +172,4 @@
}
}
}
}
}

0 comments on commit 2a3483d

Please sign in to comment.