diff --git a/addons/core/translations/errors/en-us.yaml b/addons/core/translations/errors/en-us.yaml
index d8893de1a..7c5207a33 100644
--- a/addons/core/translations/errors/en-us.yaml
+++ b/addons/core/translations/errors/en-us.yaml
@@ -28,4 +28,4 @@ required-field: This is a required field.
client-agent-failed:
sessions: Unable to retrieve sessions from the client agent.
settings-cache:
- title: There is a problem with the cache daemon
+ title: There may be a problem with the cache daemon
diff --git a/ui/desktop/app/components/settings-card/application/index.hbs b/ui/desktop/app/components/settings-card/application/index.hbs
index fa20d0076..1e91984fe 100644
--- a/ui/desktop/app/components/settings-card/application/index.hbs
+++ b/ui/desktop/app/components/settings-card/application/index.hbs
@@ -25,7 +25,7 @@
{{t 'settings.cache-daemon'}}
-
+
{{#if @model.formattedCacheVersion}}
{{@model.formattedCacheVersion}}
- {{#if @model.error}}
+ {{#if @model.cacheDaemonErrors}}
{{t 'errors.settings-cache.title'}}
- {{#if @model.error.message}}
- {{@model.error.message}}
- {{/if}}
+
+ {{#each @model.cacheDaemonErrors as |error|}}
+
+ {{#if error.name}}
+ {{error.name}}:
+ {{/if}}
+ {{error.message}}
+
+ {{/each}}
+
{{/if}}
diff --git a/ui/desktop/app/routes/scopes/scope/projects/settings/index.js b/ui/desktop/app/routes/scopes/scope/projects/settings/index.js
index 1d0fc1c47..82c26d5dd 100644
--- a/ui/desktop/app/routes/scopes/scope/projects/settings/index.js
+++ b/ui/desktop/app/routes/scopes/scope/projects/settings/index.js
@@ -7,14 +7,17 @@ import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ScopesScopeProjectsSettingsIndexRoute extends Route {
+ // =services
@service ipc;
+ @service session;
+ // =methods
async model() {
let cacheDaemonStatus,
formattedCacheVersion,
formattedCliVersion,
formattedDesktopVersion,
- error;
+ cacheDaemonErrors = [];
const { versionNumber: cliVersion } =
await this.ipc.invoke('getCliVersion');
@@ -26,16 +29,28 @@ export default class ScopesScopeProjectsSettingsIndexRoute extends Route {
try {
cacheDaemonStatus = await this.ipc.invoke('cacheDaemonStatus');
} catch (e) {
- error = e;
+ cacheDaemonErrors.push(e);
}
- const { version } = cacheDaemonStatus ?? {};
+ const { version, users } = cacheDaemonStatus ?? {};
formattedCacheVersion = version?.match(/v\d+\.\d+\.\d+/)?.[0];
+ // Grab the errors from each resource
+ const userId = this.session.data.authenticated.user_id;
+ const resourceErrors =
+ users
+ ?.find((user) => user.id === userId)
+ ?.resources.filter((resource) => resource?.last_error?.error)
+ ?.map((resource) => ({
+ message: resource.last_error.error,
+ name: resource.name,
+ })) ?? [];
+ cacheDaemonErrors = [...cacheDaemonErrors, ...resourceErrors];
+
const logLevel = await this.ipc.invoke('getLogLevel');
const logPath = await this.ipc.invoke('getLogPath');
return {
- error,
+ cacheDaemonErrors,
formattedCliVersion,
formattedCacheVersion,
formattedDesktopVersion,
diff --git a/ui/desktop/electron-app/src/utils/generateErrorPromise.js b/ui/desktop/electron-app/src/utils/generateErrorPromise.js
index eb78864ad..341d60e4d 100644
--- a/ui/desktop/electron-app/src/utils/generateErrorPromise.js
+++ b/ui/desktop/electron-app/src/utils/generateErrorPromise.js
@@ -12,7 +12,7 @@ const generateErrorPromise = async (stderr) => {
if (parsedResponse?.status_code) {
return Promise.reject({
statusCode: parsedResponse?.status_code,
- message: parsedResponse?.api_error,
+ ...parsedResponse?.api_error,
});
}
diff --git a/ui/desktop/tests/integration/components/settings-card/application-test.js b/ui/desktop/tests/integration/components/settings-card/application-test.js
new file mode 100644
index 000000000..afed0dc8f
--- /dev/null
+++ b/ui/desktop/tests/integration/components/settings-card/application-test.js
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+import { setupIntl } from 'ember-intl/test-support';
+
+const CACHE_DAEMON_VERSION = '[data-test-cache-version]';
+const ERROR_MESSAGES = '.hds-alert__description > p';
+const FIRST_ERROR_MESSAGE = '.hds-alert__description > p:first-child';
+const LAST_ERROR_MESSAGE = '.hds-alert__description > p:last-child';
+
+module('Integration | Component | settings-card/application', function (hooks) {
+ setupRenderingTest(hooks);
+ setupIntl(hooks);
+
+ test('it renders', async function (assert) {
+ this.set('model', {
+ cacheDaemonErrors: [],
+ formattedDesktopVersion: 'v2.0.0',
+ formattedCliVersion: 'v3.0.0',
+ formattedCacheVersion: 'v4.0.0',
+ });
+ this.set('toggleTheme', () => {});
+
+ await render(
+ hbs``,
+ );
+
+ assert.dom(this.element).includesText('v2.0.0');
+ assert.dom(this.element).includesText('v3.0.0');
+ assert.dom(this.element).includesText('v4.0.0');
+ });
+
+ test('it renders errors', async function (assert) {
+ this.set('model', {
+ cacheDaemonErrors: [
+ {
+ message: `this is a resolvable alias error`,
+ name: 'resolvable-alias',
+ },
+ {
+ message: `this is a target error`,
+ name: 'target',
+ },
+ ],
+ formattedDesktopVersion: 'v2.0.0',
+ formattedCliVersion: 'v3.0.0',
+ formattedCacheVersion: 'v4.0.0',
+ });
+ this.set('toggleTheme', () => {});
+
+ await render(
+ hbs``,
+ );
+
+ assert.dom(ERROR_MESSAGES).isVisible({ count: 2 });
+ assert
+ .dom(FIRST_ERROR_MESSAGE)
+ .hasText('resolvable-alias: this is a resolvable alias error');
+ assert.dom(LAST_ERROR_MESSAGE).hasText('target: this is a target error');
+ });
+
+ test('it indicates when cache daemon is running', async function (assert) {
+ this.set('model', {
+ cacheDaemonErrors: [],
+ formattedDesktopVersion: 'v2.0.0',
+ formattedCliVersion: 'v3.0.0',
+ formattedCacheVersion: 'v4.0.0',
+ });
+ this.set('toggleTheme', () => {});
+
+ await render(
+ hbs``,
+ );
+
+ assert.dom(CACHE_DAEMON_VERSION).hasText('v4.0.0 Running');
+
+ this.set('model', {
+ cacheDaemonErrors: [],
+ formattedDesktopVersion: 'v2.0.0',
+ formattedCliVersion: 'v3.0.0',
+ formattedCacheVersion: '',
+ });
+ assert.dom(CACHE_DAEMON_VERSION).hasText('Not Running');
+ });
+});