1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Start handling errors when accessing helm repositories

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen 2022-06-07 12:41:01 +03:00
parent 13e3b16bf5
commit 88fd267988
No known key found for this signature in database
GPG Key ID: 8C6CFB2FFFE8F68A
26 changed files with 5646 additions and 3320 deletions

View File

@ -306,118 +306,122 @@ exports[`deactivate helm repository from list of active repositories in preferen
</h2> </h2>
<div> <div>
<div <div
class="flex gaps" data-testid="helm-controls"
> >
<div <div
class="Select theme-lens box grow Select--is-disabled css-3iigni-container" class="flex gaps"
> >
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-selection-of-active-public-helm-repository-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div <div
class="Select__control Select__control--is-disabled css-1insrsq-control" class="Select theme-lens box grow Select--is-disabled css-3iigni-container"
> >
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-selection-of-active-public-helm-repository-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div <div
class="Select__value-container css-319lph-ValueContainer" class="Select__control Select__control--is-disabled css-1insrsq-control"
> >
<div <div
class="Select__placeholder css-14el2xx-placeholder" class="Select__value-container css-319lph-ValueContainer"
id="react-select-selection-of-active-public-helm-repository-placeholder"
> >
Repositories <div
</div> class="Select__placeholder css-14el2xx-placeholder"
<div id="react-select-selection-of-active-public-helm-repository-placeholder"
class="Select__input-container css-jzldcf-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-selection-of-active-public-helm-repository-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
disabled=""
id="selection-of-active-public-helm-repository"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<div
aria-hidden="true"
class="Select__indicator Select__loading-indicator css-at12u2-loadingIndicator"
>
<span
class="css-1xtdfmb-LoadingDot"
/>
<span
class="css-zoievk-LoadingDot"
/>
<span
class="css-x748d8-LoadingDot"
/>
</div>
<span
class="Select__indicator-separator css-109onse-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
> >
<path Repositories
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z" </div>
<div
class="Select__input-container css-jzldcf-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-selection-of-active-public-helm-repository-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
disabled=""
id="selection-of-active-public-helm-repository"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/> />
</svg> </div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<div
aria-hidden="true"
class="Select__indicator Select__loading-indicator css-at12u2-loadingIndicator"
>
<span
class="css-1xtdfmb-LoadingDot"
/>
<span
class="css-zoievk-LoadingDot"
/>
<span
class="css-x748d8-LoadingDot"
/>
</div>
<span
class="Select__indicator-separator css-109onse-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div> </div>
</div> </div>
</div> </div>
<button
class="Button primary"
data-testid="add-custom-helm-repo-button"
type="button"
>
Add Custom Helm Repo
</button>
</div> </div>
<button
class="Button primary"
data-testid="add-custom-helm-repo-button"
type="button"
>
Add Custom Helm Repo
</button>
</div>
<div
class="repos"
>
<div <div
class="pt-5 relative" class="repos"
> >
<div <div
class="Spinner singleColor center" class="pt-5 relative"
data-testid="helm-repositories-are-loading" >
/> <div
class="Spinner singleColor center"
data-testid="helm-repositories-are-loading"
/>
</div>
</div> </div>
<div />
</div> </div>
<div />
</div> </div>
</section> </section>
</section> </section>
@ -771,123 +775,127 @@ exports[`deactivate helm repository from list of active repositories in preferen
</h2> </h2>
<div> <div>
<div <div
class="flex gaps" data-testid="helm-controls"
> >
<div <div
class="Select theme-lens box grow css-b62m3t-container" class="flex gaps"
>
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-selection-of-active-public-helm-repository-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
>
<div
class="Select__value-container css-319lph-ValueContainer"
>
<div
class="Select__placeholder css-14el2xx-placeholder"
id="react-select-selection-of-active-public-helm-repository-placeholder"
>
Repositories
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-selection-of-active-public-helm-repository-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="selection-of-active-public-helm-repository"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
<button
class="Button primary"
data-testid="add-custom-helm-repo-button"
type="button"
>
Add Custom Helm Repo
</button>
</div>
<div
class="repos"
>
<div
class="item flex gaps align-center justify-space-between mt-3"
> >
<div <div
class="repoName" class="Select theme-lens box grow css-b62m3t-container"
data-testid="helm-repository-some-active-repository"
>
some-active-repository
</div>
<div
class="repoUrl"
>
some-url
</div>
<i
class="Icon material interactive focusable"
data-testid="deactivate-helm-repository-some-active-repository"
tabindex="0"
tooltip="Remove"
> >
<span <span
class="icon" class="css-1f43avz-a11yText-A11yText"
data-icon-name="delete" id="react-select-selection-of-active-public-helm-repository-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
> >
delete <div
</span> class="Select__value-container css-319lph-ValueContainer"
</i> >
<div
class="Select__placeholder css-14el2xx-placeholder"
id="react-select-selection-of-active-public-helm-repository-placeholder"
>
Repositories
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-selection-of-active-public-helm-repository-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="selection-of-active-public-helm-repository"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
<button
class="Button primary"
data-testid="add-custom-helm-repo-button"
type="button"
>
Add Custom Helm Repo
</button>
</div> </div>
<div
class="repos"
>
<div
class="item flex gaps align-center justify-space-between mt-3"
>
<div
class="repoName"
data-testid="helm-repository-some-active-repository"
>
some-active-repository
</div>
<div
class="repoUrl"
>
some-url
</div>
<i
class="Icon material interactive focusable"
data-testid="deactivate-helm-repository-some-active-repository"
tabindex="0"
tooltip="Remove"
>
<span
class="icon"
data-icon-name="delete"
>
delete
</span>
</i>
</div>
</div>
<div />
</div> </div>
<div />
</div> </div>
</section> </section>
</section> </section>
@ -1241,123 +1249,127 @@ exports[`deactivate helm repository from list of active repositories in preferen
</h2> </h2>
<div> <div>
<div <div
class="flex gaps" data-testid="helm-controls"
> >
<div <div
class="Select theme-lens box grow css-b62m3t-container" class="flex gaps"
>
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-selection-of-active-public-helm-repository-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
>
<div
class="Select__value-container css-319lph-ValueContainer"
>
<div
class="Select__placeholder css-14el2xx-placeholder"
id="react-select-selection-of-active-public-helm-repository-placeholder"
>
Repositories
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-selection-of-active-public-helm-repository-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="selection-of-active-public-helm-repository"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
<button
class="Button primary"
data-testid="add-custom-helm-repo-button"
type="button"
>
Add Custom Helm Repo
</button>
</div>
<div
class="repos"
>
<div
class="item flex gaps align-center justify-space-between mt-3"
> >
<div <div
class="repoName" class="Select theme-lens box grow css-b62m3t-container"
data-testid="helm-repository-some-active-repository"
>
some-active-repository
</div>
<div
class="repoUrl"
>
some-url
</div>
<i
class="Icon material interactive focusable"
data-testid="deactivate-helm-repository-some-active-repository"
tabindex="0"
tooltip="Remove"
> >
<span <span
class="icon" class="css-1f43avz-a11yText-A11yText"
data-icon-name="delete" id="react-select-selection-of-active-public-helm-repository-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
> >
delete <div
</span> class="Select__value-container css-319lph-ValueContainer"
</i> >
<div
class="Select__placeholder css-14el2xx-placeholder"
id="react-select-selection-of-active-public-helm-repository-placeholder"
>
Repositories
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-selection-of-active-public-helm-repository-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="selection-of-active-public-helm-repository"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
<button
class="Button primary"
data-testid="add-custom-helm-repo-button"
type="button"
>
Add Custom Helm Repo
</button>
</div> </div>
<div
class="repos"
>
<div
class="item flex gaps align-center justify-space-between mt-3"
>
<div
class="repoName"
data-testid="helm-repository-some-active-repository"
>
some-active-repository
</div>
<div
class="repoUrl"
>
some-url
</div>
<i
class="Icon material interactive focusable"
data-testid="deactivate-helm-repository-some-active-repository"
tabindex="0"
tooltip="Remove"
>
<span
class="icon"
data-icon-name="delete"
>
delete
</span>
</i>
</div>
</div>
<div />
</div> </div>
<div />
</div> </div>
</section> </section>
</section> </section>
@ -1711,118 +1723,122 @@ exports[`deactivate helm repository from list of active repositories in preferen
</h2> </h2>
<div> <div>
<div <div
class="flex gaps" data-testid="helm-controls"
> >
<div <div
class="Select theme-lens box grow Select--is-disabled css-3iigni-container" class="flex gaps"
> >
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-selection-of-active-public-helm-repository-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div <div
class="Select__control Select__control--is-disabled css-1insrsq-control" class="Select theme-lens box grow Select--is-disabled css-3iigni-container"
> >
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-selection-of-active-public-helm-repository-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div <div
class="Select__value-container css-319lph-ValueContainer" class="Select__control Select__control--is-disabled css-1insrsq-control"
> >
<div <div
class="Select__placeholder css-14el2xx-placeholder" class="Select__value-container css-319lph-ValueContainer"
id="react-select-selection-of-active-public-helm-repository-placeholder"
> >
Repositories <div
</div> class="Select__placeholder css-14el2xx-placeholder"
<div id="react-select-selection-of-active-public-helm-repository-placeholder"
class="Select__input-container css-jzldcf-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-selection-of-active-public-helm-repository-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
disabled=""
id="selection-of-active-public-helm-repository"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<div
aria-hidden="true"
class="Select__indicator Select__loading-indicator css-at12u2-loadingIndicator"
>
<span
class="css-1xtdfmb-LoadingDot"
/>
<span
class="css-zoievk-LoadingDot"
/>
<span
class="css-x748d8-LoadingDot"
/>
</div>
<span
class="Select__indicator-separator css-109onse-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
> >
<path Repositories
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z" </div>
<div
class="Select__input-container css-jzldcf-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-selection-of-active-public-helm-repository-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
disabled=""
id="selection-of-active-public-helm-repository"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/> />
</svg> </div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<div
aria-hidden="true"
class="Select__indicator Select__loading-indicator css-at12u2-loadingIndicator"
>
<span
class="css-1xtdfmb-LoadingDot"
/>
<span
class="css-zoievk-LoadingDot"
/>
<span
class="css-x748d8-LoadingDot"
/>
</div>
<span
class="Select__indicator-separator css-109onse-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div> </div>
</div> </div>
</div> </div>
<button
class="Button primary"
data-testid="add-custom-helm-repo-button"
type="button"
>
Add Custom Helm Repo
</button>
</div> </div>
<button
class="Button primary"
data-testid="add-custom-helm-repo-button"
type="button"
>
Add Custom Helm Repo
</button>
</div>
<div
class="repos"
>
<div <div
class="pt-5 relative" class="repos"
> >
<div <div
class="Spinner singleColor center" class="pt-5 relative"
data-testid="helm-repositories-are-loading" >
/> <div
class="Spinner singleColor center"
data-testid="helm-repositories-are-loading"
/>
</div>
</div> </div>
<div />
</div> </div>
<div />
</div> </div>
</section> </section>
</section> </section>

View File

@ -14,8 +14,9 @@ import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/ge
import type { HelmRepo } from "../../common/helm-repo"; import type { HelmRepo } from "../../common/helm-repo";
import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+preferences/kubernetes/helm-charts/activation-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable"; import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+preferences/kubernetes/helm-charts/activation-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable";
import isPathInjectable from "../../renderer/components/input/validators/is-path.injectable"; import isPathInjectable from "../../renderer/components/input/validators/is-path.injectable";
import showSuccessNotificationInjectable import showSuccessNotificationInjectable from "../../renderer/components/notifications/show-success-notification.injectable";
from "../../renderer/components/notifications/show-success-notification.injectable"; import showErrorNotificationInjectable from "../../renderer/components/notifications/show-error-notification.injectable";
import type { AsyncResult } from "../../common/utils/async-result";
// TODO: Make tooltips free of side effects by making it deterministic // TODO: Make tooltips free of side effects by making it deterministic
jest.mock("../../renderer/components/tooltip/withTooltip", () => ({ jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
@ -25,11 +26,12 @@ jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
describe("activate custom helm repository in preferences", () => { describe("activate custom helm repository in preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
let showSuccessNotificationMock: jest.Mock; let showSuccessNotificationMock: jest.Mock;
let showErrorNotificationMock: jest.Mock;
let rendered: RenderResult; let rendered: RenderResult;
let execFileMock: AsyncFnMock< let execFileMock: AsyncFnMock<
ReturnType<typeof execFileInjectable["instantiate"]> ReturnType<typeof execFileInjectable["instantiate"]>
>; >;
let getActiveHelmRepositoriesMock: AsyncFnMock<() => Promise<HelmRepo[]>>; let getActiveHelmRepositoriesMock: AsyncFnMock<() => AsyncResult<HelmRepo[]>>;
beforeEach(async () => { beforeEach(async () => {
jest.useFakeTimers("modern"); jest.useFakeTimers("modern");
@ -46,6 +48,10 @@ describe("activate custom helm repository in preferences", () => {
rendererDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock); rendererDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
showErrorNotificationMock = jest.fn();
rendererDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
// TODO: Figure out how to make async validators unit testable // TODO: Figure out how to make async validators unit testable
rendererDi.override(isPathInjectable, () => ({ debounce: 0, validate: async () => {} })); rendererDi.override(isPathInjectable, () => ({ debounce: 0, validate: async () => {} }));
@ -74,9 +80,12 @@ describe("activate custom helm repository in preferences", () => {
describe("when active repositories resolve", () => { describe("when active repositories resolve", () => {
beforeEach(async () => { beforeEach(async () => {
await Promise.all([ await Promise.all([
getActiveHelmRepositoriesMock.resolve([ getActiveHelmRepositoriesMock.resolve({
{ name: "Some active repository", url: "some-url" }, callWasSuccessful: true,
]), response: [
{ name: "Some active repository", url: "some-url" },
],
}),
]); ]);
}); });
@ -180,7 +189,37 @@ describe("activate custom helm repository in preferences", () => {
expect(showSuccessNotificationMock).not.toHaveBeenCalled(); expect(showSuccessNotificationMock).not.toHaveBeenCalled();
}); });
describe("when activating resolves", () => { describe("when activation rejects", () => {
beforeEach(async () => {
await execFileMock.reject(
"Some error",
);
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("shows error notification", () => {
expect(showErrorNotificationMock).toHaveBeenCalledWith(
"Some error",
);
});
it("does not show success notification", () => {
expect(showSuccessNotificationMock).not.toHaveBeenCalled();
});
it("does not show dialog anymore", () => {
expect(rendered.queryByTestId("activate-custom-helm-repository-dialog")).not.toBeInTheDocument();
});
it("does not reload active repositories", () => {
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
});
});
describe("when activation resolves with success", () => {
beforeEach(async () => { beforeEach(async () => {
await execFileMock.resolveSpecific( await execFileMock.resolveSpecific(
[ [
@ -204,7 +243,7 @@ describe("activate custom helm repository in preferences", () => {
expect(getActiveHelmRepositoriesMock).toHaveBeenCalled(); expect(getActiveHelmRepositoriesMock).toHaveBeenCalled();
}); });
it("shows the notification", () => { it("shows success notification", () => {
expect(showSuccessNotificationMock).toHaveBeenCalledWith( expect(showSuccessNotificationMock).toHaveBeenCalledWith(
"Helm repository some-custom-repository has been added.", "Helm repository some-custom-repository has been added.",
); );

View File

@ -12,6 +12,11 @@ import helmBinaryPathInjectable from "../../main/helm/helm-binary-path.injectabl
import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable"; import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable";
import type { HelmRepo } from "../../common/helm-repo"; import type { HelmRepo } from "../../common/helm-repo";
import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+preferences/kubernetes/helm-charts/activation-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable"; import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+preferences/kubernetes/helm-charts/activation-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable";
import showSuccessNotificationInjectable
from "../../renderer/components/notifications/show-success-notification.injectable";
import showErrorNotificationInjectable
from "../../renderer/components/notifications/show-error-notification.injectable";
import type { AsyncResult } from "../../common/utils/async-result";
// TODO: Make tooltips free of side effects by making it deterministic // TODO: Make tooltips free of side effects by making it deterministic
jest.mock("../../renderer/components/tooltip/withTooltip", () => ({ jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
@ -21,11 +26,13 @@ jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
describe("activate helm repository from list in preferences", () => { describe("activate helm repository from list in preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
let showSuccessNotificationMock: jest.Mock;
let showErrorNotificationMock: jest.Mock;
let rendered: RenderResult; let rendered: RenderResult;
let execFileMock: AsyncFnMock< let execFileMock: AsyncFnMock<
ReturnType<typeof execFileInjectable["instantiate"]> ReturnType<typeof execFileInjectable["instantiate"]>
>; >;
let getActiveHelmRepositoriesMock: AsyncFnMock<() => Promise<HelmRepo[]>>; let getActiveHelmRepositoriesMock: AsyncFnMock<() => AsyncResult<HelmRepo[]>>;
let callForPublicHelmRepositoriesMock: AsyncFnMock<() => Promise<HelmRepo[]>>; let callForPublicHelmRepositoriesMock: AsyncFnMock<() => Promise<HelmRepo[]>>;
beforeEach(async () => { beforeEach(async () => {
@ -36,6 +43,14 @@ describe("activate helm repository from list in preferences", () => {
callForPublicHelmRepositoriesMock = asyncFn(); callForPublicHelmRepositoriesMock = asyncFn();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
showSuccessNotificationMock = jest.fn();
rendererDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
showErrorNotificationMock = jest.fn();
rendererDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
rendererDi.override( rendererDi.override(
callForPublicHelmRepositoriesInjectable, callForPublicHelmRepositoriesInjectable,
() => callForPublicHelmRepositoriesMock, () => callForPublicHelmRepositoriesMock,
@ -78,9 +93,12 @@ describe("activate helm repository from list in preferences", () => {
{ name: "Some to be activated repository", url: "some-other-url" }, { name: "Some to be activated repository", url: "some-other-url" },
]), ]),
getActiveHelmRepositoriesMock.resolve([ getActiveHelmRepositoriesMock.resolve({
{ name: "Some already active repository", url: "some-url" }, callWasSuccessful: true,
]), response: [
{ name: "Some already active repository", url: "some-url" },
],
}),
]); ]);
}); });
@ -124,6 +142,36 @@ describe("activate helm repository from list in preferences", () => {
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled(); expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
}); });
describe("when activation rejects", () => {
beforeEach(async () => {
await execFileMock.reject(
"Some error",
);
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("shows error notification", () => {
expect(showErrorNotificationMock).toHaveBeenCalledWith(
"Some error",
);
});
it("does not show success notification", () => {
expect(showSuccessNotificationMock).not.toHaveBeenCalled();
});
it("does not show dialog anymore", () => {
expect(rendered.queryByTestId("activate-custom-helm-repository-dialog")).not.toBeInTheDocument();
});
it("does not reload active repositories", () => {
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
});
});
describe("when activating resolves", () => { describe("when activating resolves", () => {
beforeEach(async () => { beforeEach(async () => {
await execFileMock.resolveSpecific( await execFileMock.resolveSpecific(
@ -144,12 +192,21 @@ describe("activate helm repository from list in preferences", () => {
expect(getActiveHelmRepositoriesMock).toHaveBeenCalled(); expect(getActiveHelmRepositoriesMock).toHaveBeenCalled();
}); });
it("shows success notification", () => {
expect(showSuccessNotificationMock).toHaveBeenCalledWith(
"Helm repository Some to be activated repository has been added.",
);
});
describe("when active repositories resolve again", () => { describe("when active repositories resolve again", () => {
beforeEach(async () => { beforeEach(async () => {
await getActiveHelmRepositoriesMock.resolve([ await getActiveHelmRepositoriesMock.resolve({
{ name: "Some already active repository", url: "some-url" }, callWasSuccessful: true,
{ name: "Some to be activated repository", url: "some-other-url" }, response: [
]); { name: "Some already active repository", url: "some-url" },
{ name: "Some to be activated repository", url: "some-other-url" },
],
});
}); });
it("renders", () => { it("renders", () => {

View File

@ -13,6 +13,7 @@ import helmBinaryPathInjectable from "../../main/helm/helm-binary-path.injectabl
import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable"; import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable";
import type { HelmRepo } from "../../common/helm-repo"; import type { HelmRepo } from "../../common/helm-repo";
import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+preferences/kubernetes/helm-charts/activation-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable"; import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+preferences/kubernetes/helm-charts/activation-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable";
import type { AsyncResult } from "../../common/utils/async-result";
// TODO: Make tooltips free of side effects by making it deterministic // TODO: Make tooltips free of side effects by making it deterministic
jest.mock("../../renderer/components/tooltip/withTooltip", () => ({ jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
@ -22,7 +23,7 @@ jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
describe("deactivate helm repository from list of active repositories in preferences", () => { describe("deactivate helm repository from list of active repositories in preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
let rendered: RenderResult; let rendered: RenderResult;
let getActiveHelmRepositoriesMock: AsyncFnMock<() => Promise<HelmRepo[]>>; let getActiveHelmRepositoriesMock: AsyncFnMock<() => AsyncResult<HelmRepo[]>>;
let execFileMock: AsyncFnMock< let execFileMock: AsyncFnMock<
ReturnType<typeof execFileInjectable["instantiate"]> ReturnType<typeof execFileInjectable["instantiate"]>
>; >;
@ -60,9 +61,12 @@ describe("deactivate helm repository from list of active repositories in prefere
describe("when active repositories resolve", () => { describe("when active repositories resolve", () => {
beforeEach(async () => { beforeEach(async () => {
getActiveHelmRepositoriesMock.resolve([ getActiveHelmRepositoriesMock.resolve({
{ name: "some-active-repository", url: "some-url" }, callWasSuccessful: true,
]); response: [
{ name: "some-active-repository", url: "some-url" },
],
});
}); });
it("renders", () => { it("renders", () => {

View File

@ -15,6 +15,8 @@ import helmBinaryPathInjectable from "../../main/helm/helm-binary-path.injectabl
import loggerInjectable from "../../common/logger.injectable"; import loggerInjectable from "../../common/logger.injectable";
import type { Logger } from "../../common/logger"; import type { Logger } from "../../common/logger";
import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+preferences/kubernetes/helm-charts/activation-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable"; import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+preferences/kubernetes/helm-charts/activation-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable";
import showErrorNotificationInjectable
from "../../renderer/components/notifications/show-error-notification.injectable";
// TODO: Make tooltips free of side effects by making it deterministic // TODO: Make tooltips free of side effects by making it deterministic
jest.mock("../../renderer/components/tooltip/withTooltip", () => ({ jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
@ -27,6 +29,7 @@ describe("listing active helm repositories in preferences", () => {
let readYamlFileMock: AsyncFnMock<ReadYamlFile>; let readYamlFileMock: AsyncFnMock<ReadYamlFile>;
let execFileMock: AsyncFnMock<ReturnType<typeof execFileInjectable["instantiate"]>>; let execFileMock: AsyncFnMock<ReturnType<typeof execFileInjectable["instantiate"]>>;
let loggerStub: Logger; let loggerStub: Logger;
let showErrorNotificationMock: jest.Mock;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
@ -34,9 +37,12 @@ describe("listing active helm repositories in preferences", () => {
readYamlFileMock = asyncFn(); readYamlFileMock = asyncFn();
execFileMock = asyncFn(); execFileMock = asyncFn();
loggerStub = { warn: jest.fn() } as unknown as Logger; loggerStub = { error: jest.fn() } as unknown as Logger;
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
showErrorNotificationMock = jest.fn();
rendererDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
rendererDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []); rendererDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []);
mainDi.override(readYamlFileInjectable, () => readYamlFileMock); mainDi.override(readYamlFileInjectable, () => readYamlFileMock);
mainDi.override(execFileInjectable, () => execFileMock); mainDi.override(execFileInjectable, () => execFileMock);
@ -77,6 +83,34 @@ describe("listing active helm repositories in preferences", () => {
); );
}); });
describe("when getting configuration rejects", () => {
beforeEach(async () => {
await execFileMock.reject("some-error");
});
it("shows error notification", () => {
expect(showErrorNotificationMock).toHaveBeenCalledWith(
"Error getting Helm configuration: some-error",
);
});
it("removes all helm controls", () => {
expect(
rendered.queryByTestId("helm-controls"),
).not.toBeInTheDocument();
});
it("does not show loader for repositories anymore", () => {
expect(
rendered.queryByTestId("helm-repositories-are-loading"),
).not.toBeInTheDocument();
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
});
describe("when configuration resolves without path to repository config file", () => { describe("when configuration resolves without path to repository config file", () => {
beforeEach(async () => { beforeEach(async () => {
execFileMock.mockClear(); execFileMock.mockClear();
@ -87,20 +121,22 @@ describe("listing active helm repositories in preferences", () => {
); );
}); });
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("logs error", () => { it("logs error", () => {
expect(loggerStub.warn).toHaveBeenCalledWith( expect(loggerStub.error).toHaveBeenCalledWith(
"Tried to get Helm repositories, but HELM_REPOSITORY_CONFIG was not present in `$ helm env`. Behaving as if there were no repositories.", "Tried to get Helm repositories, but HELM_REPOSITORY_CONFIG was not present in `$ helm env`.",
); );
}); });
it("shows message about no repositories found", () => { it("shows error notification", () => {
expect(showErrorNotificationMock).toHaveBeenCalledWith(
"Error getting Helm configuration: Tried to get Helm repositories, but HELM_REPOSITORY_CONFIG was not present in `$ helm env`.",
);
});
it("removes all helm controls", () => {
expect( expect(
rendered.getByTestId("no-helm-repositories"), rendered.queryByTestId("helm-controls"),
).toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
it("does not show loader for repositories anymore", () => { it("does not show loader for repositories anymore", () => {
@ -109,11 +145,8 @@ describe("listing active helm repositories in preferences", () => {
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
it("does not call for updating of repositories", () => { it("renders", () => {
expect(execFileMock).not.toHaveBeenCalledWith( expect(rendered.baseElement).toMatchSnapshot();
"some-helm-binary-path",
["repo", "update"],
);
}); });
}); });
@ -127,20 +160,22 @@ describe("listing active helm repositories in preferences", () => {
); );
}); });
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("logs error", () => { it("logs error", () => {
expect(loggerStub.warn).toHaveBeenCalledWith( expect(loggerStub.error).toHaveBeenCalledWith(
"Tried to get Helm repositories, but HELM_REPOSITORY_CACHE was not present in `$ helm env`. Behaving as if there were no repositories.", "Tried to get Helm repositories, but HELM_REPOSITORY_CACHE was not present in `$ helm env`.",
); );
}); });
it("shows message about no repositories found", () => { it("shows error notification", () => {
expect(showErrorNotificationMock).toHaveBeenCalledWith(
"Error getting Helm configuration: Tried to get Helm repositories, but HELM_REPOSITORY_CACHE was not present in `$ helm env`.",
);
});
it("removes all helm controls", () => {
expect( expect(
rendered.getByTestId("no-helm-repositories"), rendered.queryByTestId("helm-controls"),
).toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
it("does not show loader for repositories anymore", () => { it("does not show loader for repositories anymore", () => {
@ -149,11 +184,8 @@ describe("listing active helm repositories in preferences", () => {
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
it("does not call for updating of repositories", () => { it("renders", () => {
expect(execFileMock).not.toHaveBeenCalledWith( expect(rendered.baseElement).toMatchSnapshot();
"some-helm-binary-path",
["repo", "update"],
);
}); });
}); });
@ -186,6 +218,34 @@ describe("listing active helm repositories in preferences", () => {
expect(readYamlFileMock).not.toHaveBeenCalled(); expect(readYamlFileMock).not.toHaveBeenCalled();
}); });
describe("when updating repositories reject", () => {
beforeEach(async () => {
await execFileMock.reject("Some error");
});
it("shows error notification", () => {
expect(showErrorNotificationMock).toHaveBeenCalledWith(
"Error updating Helm repositories: Some error",
);
});
it("removes all helm controls", () => {
expect(
rendered.queryByTestId("helm-controls"),
).not.toBeInTheDocument();
});
it("does not show loader for repositories anymore", () => {
expect(
rendered.queryByTestId("helm-repositories-are-loading"),
).not.toBeInTheDocument();
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
});
describe("when updating repositories resolve", () => { describe("when updating repositories resolve", () => {
beforeEach(async () => { beforeEach(async () => {
execFileMock.mockClear(); execFileMock.mockClear();
@ -196,6 +256,12 @@ describe("listing active helm repositories in preferences", () => {
); );
}); });
it("loads repositories from file system", () => {
expect(readYamlFileMock).toHaveBeenCalledWith(
"some-helm-repository-config-file.yaml",
);
});
describe("when loading repositories resolves with existing repositories", () => { describe("when loading repositories resolves with existing repositories", () => {
beforeEach(async () => { beforeEach(async () => {
execFileMock.mockClear(); execFileMock.mockClear();
@ -252,12 +318,6 @@ describe("listing active helm repositories in preferences", () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it("does not show message about no repositories", () => {
expect(
rendered.queryByTestId("no-helm-repositories"),
).not.toBeInTheDocument();
});
it('adds "bitnami" as default repository', () => { it('adds "bitnami" as default repository', () => {
expect(execFileMock).toHaveBeenCalledWith( expect(execFileMock).toHaveBeenCalledWith(
"some-helm-binary-path", "some-helm-binary-path",
@ -265,6 +325,34 @@ describe("listing active helm repositories in preferences", () => {
); );
}); });
describe("when adding default repository reject", () => {
beforeEach(async () => {
await execFileMock.reject("Some error");
});
it("shows error notification", () => {
expect(showErrorNotificationMock).toHaveBeenCalledWith(
"Error when adding default Helm repository: Some error",
);
});
it("removes all helm controls", () => {
expect(
rendered.queryByTestId("helm-controls"),
).not.toBeInTheDocument();
});
it("does not show loader for repositories anymore", () => {
expect(
rendered.queryByTestId("helm-repositories-are-loading"),
).not.toBeInTheDocument();
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
});
describe("when adding of default repository resolves", () => { describe("when adding of default repository resolves", () => {
beforeEach(async () => { beforeEach(async () => {
readYamlFileMock.mockClear(); readYamlFileMock.mockClear();
@ -295,13 +383,6 @@ describe("listing active helm repositories in preferences", () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it("does not show message about no repositories", () => {
expect(
rendered.queryByTestId("no-helm-repositories"),
).not.toBeInTheDocument();
});
it("calls for repositories again", () => { it("calls for repositories again", () => {
expect(readYamlFileMock).toHaveBeenCalledWith( expect(readYamlFileMock).toHaveBeenCalledWith(
"some-helm-repository-config-file.yaml", "some-helm-repository-config-file.yaml",
@ -342,12 +423,6 @@ describe("listing active helm repositories in preferences", () => {
expect(actual).toBeInTheDocument(); expect(actual).toBeInTheDocument();
}); });
it("does not show message about no repositories", () => {
expect(
rendered.queryByTestId("no-helm-repositories"),
).not.toBeInTheDocument();
});
}); });
}); });
}); });

View File

@ -4,18 +4,20 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { execFile } from "child_process"; import { execFile } from "child_process";
import { promisify } from "util";
export type ExecFile = (filePath: string, args: string[]) => Promise<string>; export type ExecFile = (filePath: string, args: string[]) => Promise<string>;
const execFileInjectable = getInjectable({ const execFileInjectable = getInjectable({
id: "exec-file", id: "exec-file",
instantiate: (): ExecFile => async (filePath, args) => instantiate: (): ExecFile => async (filePath, args) => {
new Promise((resolve) => { const asyncExecFile = promisify(execFile);
execFile(filePath, args, (error, stdout) => {
resolve(stdout); const result = await asyncExecFile(filePath, args);
});
}), return result.stdout;
},
causesSideEffects: true, causesSideEffects: true,
}); });

View File

@ -6,8 +6,9 @@ import { getInjectable } from "@ogre-tools/injectable";
import type { HelmRepo } from "../helm-repo"; import type { HelmRepo } from "../helm-repo";
import type { RequestChannel } from "../utils/channel/request-channel-injection-token"; import type { RequestChannel } from "../utils/channel/request-channel-injection-token";
import { requestChannelInjectionToken } from "../utils/channel/request-channel-injection-token"; import { requestChannelInjectionToken } from "../utils/channel/request-channel-injection-token";
import type { AsyncResult } from "../utils/async-result";
export type ActivateHelmRepositoryChannel = RequestChannel<HelmRepo>; export type ActivateHelmRepositoryChannel = RequestChannel<HelmRepo, AsyncResult<string>>;
const activateHelmRepositoryChannelInjectable = getInjectable({ const activateHelmRepositoryChannelInjectable = getInjectable({
id: "activate-helm-repository-channel", id: "activate-helm-repository-channel",

View File

@ -6,8 +6,9 @@ import { getInjectable } from "@ogre-tools/injectable";
import type { RequestChannel } from "../utils/channel/request-channel-injection-token"; import type { RequestChannel } from "../utils/channel/request-channel-injection-token";
import type { HelmRepo } from "../helm-repo"; import type { HelmRepo } from "../helm-repo";
import { requestChannelInjectionToken } from "../utils/channel/request-channel-injection-token"; import { requestChannelInjectionToken } from "../utils/channel/request-channel-injection-token";
import type { AsyncResult } from "../utils/async-result";
export type GetHelmRepositoriesChannel = RequestChannel<void, HelmRepo[]>; export type GetHelmRepositoriesChannel = RequestChannel<void, AsyncResult<HelmRepo[]>>;
const getActiveHelmRepositoriesChannelInjectable = getInjectable({ const getActiveHelmRepositoriesChannelInjectable = getInjectable({
id: "get-active-helm-repositories-channel", id: "get-active-helm-repositories-channel",

View File

@ -0,0 +1,7 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export type AsyncResult<Response, Error = string> =
| { callWasSuccessful: true; response: Response }
| { callWasSuccessful: false; error: Error };

View File

@ -0,0 +1,15 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export const getErrorMessage = (error: unknown): string => {
if (typeof error === "string") {
return error;
}
if (error instanceof Error) {
return error.message;
}
return JSON.stringify(error);
};

View File

@ -5,6 +5,8 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import execFileInjectable from "../../../common/fs/exec-file.injectable"; import execFileInjectable from "../../../common/fs/exec-file.injectable";
import helmBinaryPathInjectable from "../helm-binary-path.injectable"; import helmBinaryPathInjectable from "../helm-binary-path.injectable";
import type { AsyncResult } from "../../../common/utils/async-result";
import { getErrorMessage } from "../../../common/utils/get-error-message";
const execHelmInjectable = getInjectable({ const execHelmInjectable = getInjectable({
id: "exec-helm", id: "exec-helm",
@ -13,8 +15,17 @@ const execHelmInjectable = getInjectable({
const execFile = di.inject(execFileInjectable); const execFile = di.inject(execFileInjectable);
const helmBinaryPath = di.inject(helmBinaryPathInjectable); const helmBinaryPath = di.inject(helmBinaryPathInjectable);
return (...args: string[]) => execFile(helmBinaryPath, args); return async (...args: string[]): Promise<AsyncResult<string>> => {
try {
const response = await execFile(helmBinaryPath, args);
return { callWasSuccessful: true, response };
} catch (error) {
return { callWasSuccessful: false, error: getErrorMessage(error) };
}
};
}, },
}); });
export default execHelmInjectable; export default execHelmInjectable;

View File

@ -4,6 +4,7 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import execHelmInjectable from "../exec-helm/exec-helm.injectable"; import execHelmInjectable from "../exec-helm/exec-helm.injectable";
import type { AsyncResult } from "../../../common/utils/async-result";
export type HelmEnv = Record<string, string> & { export type HelmEnv = Record<string, string> & {
HELM_REPOSITORY_CACHE?: string; HELM_REPOSITORY_CACHE?: string;
@ -16,10 +17,14 @@ const getHelmEnvInjectable = getInjectable({
instantiate: (di) => { instantiate: (di) => {
const execHelm = di.inject(execHelmInjectable); const execHelm = di.inject(execHelmInjectable);
return async () => { return async (): Promise<AsyncResult<HelmEnv>> => {
const output = await execHelm("env"); const result = await execHelm("env");
const lines = output.split(/\r?\n/); // split by new line feed if (!result.callWasSuccessful) {
return { callWasSuccessful: false, error: result.error };
}
const lines = result.response.split(/\r?\n/); // split by new line feed
const env: HelmEnv = {}; const env: HelmEnv = {};
lines.forEach((line: string) => { lines.forEach((line: string) => {
@ -30,7 +35,7 @@ const getHelmEnvInjectable = getInjectable({
} }
}); });
return env; return { callWasSuccessful: true, response: env };
}; };
}, },
}); });

View File

@ -3,6 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert";
import { object } from "../../../common/utils"; import { object } from "../../../common/utils";
import { HelmChartManager } from "../helm-chart-manager"; import { HelmChartManager } from "../helm-chart-manager";
import getActiveHelmRepositoriesInjectable from "../repositories/get-active-helm-repositories/get-active-helm-repositories.injectable"; import getActiveHelmRepositoriesInjectable from "../repositories/get-active-helm-repositories/get-active-helm-repositories.injectable";
@ -14,7 +15,11 @@ const listHelmChartsInjectable = getInjectable({
const getActiveHelmRepositories = di.inject(getActiveHelmRepositoriesInjectable); const getActiveHelmRepositories = di.inject(getActiveHelmRepositoriesInjectable);
return async () => { return async () => {
const repositories = await getActiveHelmRepositories(); const result = await getActiveHelmRepositories();
assert(result.callWasSuccessful);
const repositories = result.response;
return object.fromEntries( return object.fromEntries(
await Promise.all( await Promise.all(

View File

@ -54,7 +54,7 @@ const activateHelmRepositoryInjectable = getInjectable({
args.push("--cert-file", certFile); args.push("--cert-file", certFile);
} }
await execHelm(...args); return await execHelm(...args);
}; };
}, },
}); });

View File

@ -10,6 +10,7 @@ import getHelmEnvInjectable from "../../get-helm-env/get-helm-env.injectable";
import execHelmInjectable from "../../exec-helm/exec-helm.injectable"; import execHelmInjectable from "../../exec-helm/exec-helm.injectable";
import { isEmpty } from "lodash/fp"; import { isEmpty } from "lodash/fp";
import loggerInjectable from "../../../../common/logger.injectable"; import loggerInjectable from "../../../../common/logger.injectable";
import type { AsyncResult } from "../../../../common/utils/async-result";
interface HelmRepositoryFromYaml { interface HelmRepositoryFromYaml {
name: string; name: string;
@ -38,23 +39,41 @@ const getActiveHelmRepositoriesInjectable = getInjectable({
const getRepositoriesFor = getRepositoriesForFor(readYamlFile); const getRepositoriesFor = getRepositoriesForFor(readYamlFile);
return async (): Promise<HelmRepo[]> => { return async (): Promise<AsyncResult<HelmRepo[]>> => {
const { HELM_REPOSITORY_CONFIG: repositoryConfigFilePath, HELM_REPOSITORY_CACHE: helmRepositoryCacheDirPath } = await getHelmEnv(); const envResult = await getHelmEnv();
if (!envResult.callWasSuccessful) {
return {
callWasSuccessful: false,
error: `Error getting Helm configuration: ${envResult.error}`,
};
}
const {
HELM_REPOSITORY_CONFIG: repositoryConfigFilePath,
HELM_REPOSITORY_CACHE: helmRepositoryCacheDirPath,
} = envResult.response;
if (!repositoryConfigFilePath) { if (!repositoryConfigFilePath) {
logger.warn("Tried to get Helm repositories, but HELM_REPOSITORY_CONFIG was not present in `$ helm env`. Behaving as if there were no repositories."); const errorMessage = "Tried to get Helm repositories, but HELM_REPOSITORY_CONFIG was not present in `$ helm env`.";
return []; logger.error(errorMessage);
return {
callWasSuccessful: false,
error: `Error getting Helm configuration: ${errorMessage}`,
};
} }
if (!helmRepositoryCacheDirPath) { if (!helmRepositoryCacheDirPath) {
logger.warn("Tried to get Helm repositories, but HELM_REPOSITORY_CACHE was not present in `$ helm env`. Behaving as if there were no repositories."); const errorMessage = "Tried to get Helm repositories, but HELM_REPOSITORY_CACHE was not present in `$ helm env`.";
return []; logger.error(errorMessage);
}
if (!repositoryConfigFilePath || !helmRepositoryCacheDirPath) { return {
return []; callWasSuccessful: false,
error: `Error getting Helm configuration: ${errorMessage}`,
};
} }
const getRepositories = getRepositoriesFor( const getRepositories = getRepositoriesFor(
@ -62,17 +81,31 @@ const getActiveHelmRepositoriesInjectable = getInjectable({
helmRepositoryCacheDirPath, helmRepositoryCacheDirPath,
); );
await execHelm("repo", "update"); const updateResult = await execHelm("repo", "update");
if (!updateResult.callWasSuccessful) {
return {
callWasSuccessful: false,
error: `Error updating Helm repositories: ${updateResult.error}`,
};
}
const repositories = await getRepositories(); const repositories = await getRepositories();
if (isEmpty(repositories)) { if (isEmpty(repositories)) {
await execHelm("repo", "add", "bitnami", "https://charts.bitnami.com/bitnami"); const resultOfAddingDefaultRepository = await execHelm("repo", "add", "bitnami", "https://charts.bitnami.com/bitnami");
return await getRepositories(); if (!resultOfAddingDefaultRepository.callWasSuccessful) {
return {
callWasSuccessful: false,
error: `Error when adding default Helm repository: ${resultOfAddingDefaultRepository.error}`,
};
}
return { callWasSuccessful: true, response: await getRepositories() };
} }
return repositories; return { callWasSuccessful: true, response: repositories };
}; };
}, },
}); });
@ -82,7 +115,7 @@ export default getActiveHelmRepositoriesInjectable;
const getRepositoriesForFor = const getRepositoriesForFor =
(readYamlFile: ReadYamlFile) => (readYamlFile: ReadYamlFile) =>
(repositoryConfigFilePath: string, helmRepositoryCacheDirPath: string) => (repositoryConfigFilePath: string, helmRepositoryCacheDirPath: string) =>
async () => { async (): Promise<HelmRepo[]> => {
const { repositories } = (await readYamlFile( const { repositories } = (await readYamlFile(
repositoryConfigFilePath, repositoryConfigFilePath,
)) as HelmRepositoriesFromYaml; )) as HelmRepositoriesFromYaml;

View File

@ -3,6 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert";
import getActiveHelmRepositoriesInjectable from "./get-active-helm-repositories/get-active-helm-repositories.injectable"; import getActiveHelmRepositoriesInjectable from "./get-active-helm-repositories/get-active-helm-repositories.injectable";
const getActiveHelmRepositoryInjectable = getInjectable({ const getActiveHelmRepositoryInjectable = getInjectable({
@ -14,7 +15,9 @@ const getActiveHelmRepositoryInjectable = getInjectable({
return async (name: string) => { return async (name: string) => {
const activeHelmRepositories = await getActiveHelmRepositories(); const activeHelmRepositories = await getActiveHelmRepositories();
return activeHelmRepositories.find( assert(activeHelmRepositories.callWasSuccessful);
return activeHelmRepositories.response.find(
(repository) => repository.name === name, (repository) => repository.name === name,
); );
}; };

View File

@ -6,7 +6,6 @@ import { getInjectable } from "@ogre-tools/injectable";
import type { HelmRepo } from "../../../../../../common/helm-repo"; import type { HelmRepo } from "../../../../../../common/helm-repo";
import activateHelmRepositoryInjectable from "../activation-of-public-helm-repository/select-helm-repository/activate-helm-repository.injectable"; import activateHelmRepositoryInjectable from "../activation-of-public-helm-repository/select-helm-repository/activate-helm-repository.injectable";
import hideDialogForActivatingCustomHelmRepositoryInjectable from "./dialog-visibility/hide-dialog-for-activating-custom-helm-repository.injectable"; import hideDialogForActivatingCustomHelmRepositoryInjectable from "./dialog-visibility/hide-dialog-for-activating-custom-helm-repository.injectable";
import showSuccessNotificationInjectable from "../../../../notifications/show-success-notification.injectable";
const submitCustomHelmRepositoryInjectable = getInjectable({ const submitCustomHelmRepositoryInjectable = getInjectable({
id: "submit-custom-helm-repository", id: "submit-custom-helm-repository",
@ -14,13 +13,10 @@ const submitCustomHelmRepositoryInjectable = getInjectable({
instantiate: (di) => { instantiate: (di) => {
const activateHelmRepository = di.inject(activateHelmRepositoryInjectable); const activateHelmRepository = di.inject(activateHelmRepositoryInjectable);
const hideDialog = di.inject(hideDialogForActivatingCustomHelmRepositoryInjectable); const hideDialog = di.inject(hideDialogForActivatingCustomHelmRepositoryInjectable);
const showSuccessNotification = di.inject(showSuccessNotificationInjectable);
return async (repository: HelmRepo) => { return async (repository: HelmRepo) => {
await activateHelmRepository(repository); await activateHelmRepository(repository);
showSuccessNotification(`Helm repository ${repository.name} has been added.`);
hideDialog(); hideDialog();
}; };
}, },

View File

@ -7,6 +7,8 @@ import activateHelmRepositoryChannelInjectable from "../../../../../../../common
import type { HelmRepo } from "../../../../../../../common/helm-repo"; import type { HelmRepo } from "../../../../../../../common/helm-repo";
import { requestFromChannelInjectionToken } from "../../../../../../../common/utils/channel/request-from-channel-injection-token"; import { requestFromChannelInjectionToken } from "../../../../../../../common/utils/channel/request-from-channel-injection-token";
import activeHelmRepositoriesInjectable from "../../active-helm-repositories.injectable"; import activeHelmRepositoriesInjectable from "../../active-helm-repositories.injectable";
import showErrorNotificationInjectable from "../../../../../notifications/show-error-notification.injectable";
import showSuccessNotificationInjectable from "../../../../../notifications/show-success-notification.injectable";
const activateHelmRepositoryInjectable = getInjectable({ const activateHelmRepositoryInjectable = getInjectable({
id: "activate-public-helm-repository", id: "activate-public-helm-repository",
@ -15,11 +17,24 @@ const activateHelmRepositoryInjectable = getInjectable({
const requestFromChannel = di.inject(requestFromChannelInjectionToken); const requestFromChannel = di.inject(requestFromChannelInjectionToken);
const activateHelmRepositoryChannel = di.inject(activateHelmRepositoryChannelInjectable); const activateHelmRepositoryChannel = di.inject(activateHelmRepositoryChannelInjectable);
const activeHelmRepositories = di.inject(activeHelmRepositoriesInjectable); const activeHelmRepositories = di.inject(activeHelmRepositoriesInjectable);
const showErrorNotification = di.inject(showErrorNotificationInjectable);
const showSuccessNotification = di.inject(showSuccessNotificationInjectable);
return async (repository: HelmRepo) => { return async (repository: HelmRepo) => {
await requestFromChannel(activateHelmRepositoryChannel, repository); const result = await requestFromChannel(
activateHelmRepositoryChannel,
repository,
);
activeHelmRepositories.invalidate(); if (result.callWasSuccessful) {
showSuccessNotification(
`Helm repository ${repository.name} has been added.`,
);
activeHelmRepositories.invalidate();
} else {
showErrorNotification(result.error);
}
}; };
}, },
}); });

View File

@ -4,20 +4,39 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { asyncComputed } from "@ogre-tools/injectable-react"; import { asyncComputed } from "@ogre-tools/injectable-react";
import requestFromChannelInjectable from "../../../../utils/channel/request-from-channel.injectable";
import getActiveHelmRepositoriesChannelInjectable from "../../../../../common/helm/get-active-helm-repositories-channel.injectable"; import getActiveHelmRepositoriesChannelInjectable from "../../../../../common/helm/get-active-helm-repositories-channel.injectable";
import { requestFromChannelInjectionToken } from "../../../../../common/utils/channel/request-from-channel-injection-token";
import showErrorNotificationInjectable from "../../../notifications/show-error-notification.injectable";
import helmRepositoriesErrorStateInjectable from "./helm-repositories-error-state.injectable";
import { runInAction } from "mobx";
const activeHelmRepositoriesInjectable = getInjectable({ const activeHelmRepositoriesInjectable = getInjectable({
id: "active-helm-repositories", id: "active-helm-repositories",
instantiate: (di) => { instantiate: (di) => {
const requestFromChannel = di.inject(requestFromChannelInjectable); const requestFromChannel = di.inject(requestFromChannelInjectionToken);
const getHelmRepositoriesChannel = di.inject(getActiveHelmRepositoriesChannelInjectable); const getHelmRepositoriesChannel = di.inject(getActiveHelmRepositoriesChannelInjectable);
const showErrorNotification = di.inject(showErrorNotificationInjectable);
const helmRepositoriesErrorState = di.inject(helmRepositoriesErrorStateInjectable);
return asyncComputed( return asyncComputed(async () => {
async () => await requestFromChannel(getHelmRepositoriesChannel), const result = await requestFromChannel(getHelmRepositoriesChannel);
[],
); if (result.callWasSuccessful) {
return result.response;
} else {
showErrorNotification(result.error);
runInAction(() =>
helmRepositoriesErrorState.set({
controlsAreShown: false,
errorMessage: result.error,
}),
);
return [];
}
}, []);
}, },
}); });

View File

@ -3,25 +3,59 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import React from "react"; import React from "react";
import { HelmRepositories } from "./helm-repositories"; import { HelmRepositories } from "./helm-repositories";
import { ActivationOfPublicHelmRepository } from "./activation-of-public-helm-repository/activation-of-public-helm-repository"; import { ActivationOfPublicHelmRepository } from "./activation-of-public-helm-repository/activation-of-public-helm-repository";
import { ActivationOfCustomHelmRepositoryOpenButton } from "./activation-of-custom-helm-repository/activation-of-custom-helm-repository-open-button"; import { ActivationOfCustomHelmRepositoryOpenButton } from "./activation-of-custom-helm-repository/activation-of-custom-helm-repository-open-button";
import { ActivationOfCustomHelmRepositoryDialog } from "./activation-of-custom-helm-repository/activation-of-custom-helm-repository-dialog"; import { ActivationOfCustomHelmRepositoryDialog } from "./activation-of-custom-helm-repository/activation-of-custom-helm-repository-dialog";
import { withInjectables } from "@ogre-tools/injectable-react";
import type { HelmRepositoriesErrorState } from "./helm-repositories-error-state.injectable";
import helmRepositoriesErrorStateInjectable from "./helm-repositories-error-state.injectable";
import type { IObservableValue } from "mobx";
import { observer } from "mobx-react";
import { Notice } from "../../../+extensions/notice";
export const HelmCharts = () => ( interface Dependencies {
<div> helmRepositoriesErrorState: IObservableValue<HelmRepositoriesErrorState>;
<div className="flex gaps"> }
<ActivationOfPublicHelmRepository />
<ActivationOfCustomHelmRepositoryOpenButton /> const NonInjectedHelmCharts = observer(
</div> ({ helmRepositoriesErrorState }: Dependencies) => {
const state = helmRepositoriesErrorState.get();
<HelmRepositories /> return (
<div>
{!state.controlsAreShown && (
<Notice>
<div className="flex-grow text-center">{state.errorMessage}</div>
</Notice>
)}
<ActivationOfCustomHelmRepositoryDialog /> {state.controlsAreShown && (
</div> <div data-testid="helm-controls">
<div className="flex gaps">
<ActivationOfPublicHelmRepository />
<ActivationOfCustomHelmRepositoryOpenButton />
</div>
<HelmRepositories />
<ActivationOfCustomHelmRepositoryDialog />
</div>
)}
</div>
);
},
); );
export const HelmCharts = withInjectables<Dependencies>(
NonInjectedHelmCharts,
{
getProps: (di) => ({
helmRepositoriesErrorState: di.inject(helmRepositoriesErrorStateInjectable),
}),
},
);

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { observable } from "mobx";
export type HelmRepositoriesErrorState =
| { controlsAreShown: true }
| { controlsAreShown: false; errorMessage: string };
const helmRepositoriesErrorStateInjectable = getInjectable({
id: "helm-repositories-error-state",
instantiate: () =>
observable.box<HelmRepositoriesErrorState>({ controlsAreShown: true }),
});
export default helmRepositoriesErrorStateInjectable;

View File

@ -13,8 +13,6 @@ import type { IAsyncComputed } from "@ogre-tools/injectable-react";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import { Spinner } from "../../../spinner"; import { Spinner } from "../../../spinner";
import type { HelmRepo } from "../../../../../common/helm-repo"; import type { HelmRepo } from "../../../../../common/helm-repo";
import { Notice } from "../../../+extensions/notice";
import { isEmpty } from "lodash/fp";
import { RemovableItem } from "../../removable-item"; import { RemovableItem } from "../../removable-item";
import deactivateHelmRepositoryInjectable from "./deactivate-helm-repository.injectable"; import deactivateHelmRepositoryInjectable from "./deactivate-helm-repository.injectable";
@ -36,18 +34,6 @@ const NonInjectedActiveHelmRepositories = observer(({ activeHelmRepositories, de
const repositories = activeHelmRepositories.value.get(); const repositories = activeHelmRepositories.value.get();
if (isEmpty(repositories)) {
return (
<div className={styles.repos}>
<Notice>
<div className="flex-grow text-center" data-testid="no-helm-repositories">
The repositories have not been added yet
</div>
</Notice>
</div>
);
}
return ( return (
<div className={styles.repos}> <div className={styles.repos}>
{repositories.map((repository) => ( {repositories.map((repository) => (

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import type { NotificationMessage, Notification } from "./notifications.store";
import { NotificationStatus } from "./notifications.store";
import notificationsStoreInjectable from "./notifications-store.injectable";
const showErrorNotificationInjectable = getInjectable({
id: "show-error-notification",
instantiate: (di) => {
const notificationsStore = di.inject(notificationsStoreInjectable);
return (message: NotificationMessage, customOpts: Partial<Omit<Notification, "message">> = {}) =>
notificationsStore.add({
status: NotificationStatus.ERROR,
timeout: 5000,
message,
...customOpts,
});
},
});
export default showErrorNotificationInjectable;