Skip to content
3 changes: 3 additions & 0 deletions public/assets/locale/en-AU.json
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,7 @@
"GROUPS_BULK_ERROR": "Failed to add {{ count }} groups to user.",
"GROUP_PERMISSIONS": "Group permissions",
"GROUP_ADD_SUCCESS": "Successfully added user to group.",
"GROUPS_LOAD_ERROR": "Failed to load user groups. Error: {{ error }}",
"GROUP_ADD_ERROR": "Failed to add user to group. Error: {{ error }}",
"GROUP_SAVE_SUCCESS": "Successfully updated group permissions.",
"GROUP_SAVE_ERROR": "Failed to update group permissions. Error: {{ error }}",
Expand Down Expand Up @@ -791,6 +792,7 @@
"USERS_EMPTY": "No users associated with this group",
"ZONES_EMPTY": "No zones associated with this group",
"USER_ADD_SUCCESS": "Successfully added user to group.",
"USERS_LOAD_ERROR": "Failed to load group users. Error: {{ error }}",
"USER_ADD_ERROR": "Failed to add user to group. Error: {{ error }}",
"USER_SAVE_SUCCESS": "Successfully updated user permissions.",
"USER_SAVE_ERROR": "Failed to update user permissions. Error: {{ error }}",
Expand All @@ -800,6 +802,7 @@
"USER_REMOVE_SUCCESS": "Successfully removed user from group.",
"USER_REMOVE_ERROR": "Failed to remove user from group. Error: {{ error }}",
"ZONE_ADD_SUCCESS": "Successfully added zone to group.",
"ZONES_LOAD_ERROR": "Failed to load group zones. Error: {{ error }}",
"ZONE_ADD_ERROR": "Failed to add zone to group. Error: {{ error }}",
"ZONE_SAVE_SUCCESS": "Successfully updated zone permissions.",
"ZONE_SAVE_ERROR": "Failed to update zone permissions. Error: {{ error }}",
Expand Down
54 changes: 31 additions & 23 deletions src/app/admin/api-keys/api-keys.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
update,
} from '@placeos/ts-client';
import { addDays, getUnixTime } from 'date-fns';
import { describeError } from '../../common/errors';
import { notifyError, notifySuccess } from '../../common/notifications';
import { waitForEvent } from '../../common/signals';
import { DialogEvent } from '../../common/types';
Expand Down Expand Up @@ -53,8 +54,8 @@ export class APIKeyService {
loader: async () => (await get('/api/engine/v2/scopes')) as string[],
});

public readonly available_scopes = computed(
() => this._available_scopes.value() || [],
public readonly available_scopes = computed(() =>
this._available_scopes.hasValue() ? this._available_scopes.value() : [],
);

private readonly _available_keys = resource({
Expand All @@ -79,8 +80,8 @@ export class APIKeyService {
},
});

public readonly available_keys = computed(
() => this._available_keys.value() || [],
public readonly available_keys = computed(() =>
this._available_keys.hasValue() ? this._available_keys.value() : [],
);

private readonly _users = resource({
Expand All @@ -96,7 +97,9 @@ export class APIKeyService {
},
});

public readonly users = computed(() => this._users.value() || []);
public readonly users = computed(() =>
this._users.hasValue() ? this._users.value() : [],
);

public setDomain(domain: PlaceDomain) {
this._admin_data.setDomain('api-keys', domain);
Expand Down Expand Up @@ -136,9 +139,10 @@ export class APIKeyService {
},
}).catch((_) => {
ref.close();
notifyError(_);
throw _;
notifyError(describeError(_));
return null;
});
if (!key) return;
this._last_key.set(key as PlaceAPIKeyDetails);
this._change.set(Date.now());
notifySuccess('Successfully created new API key.');
Expand Down Expand Up @@ -174,9 +178,10 @@ export class APIKeyService {
expires_at: getUnixTime(addDays(Date.now(), 1)), // expire 1 day from creation
},
}).catch((_) => {
notifyError(_);
throw _;
notifyError(describeError(_));
return null;
});
if (!key) return;
this._last_key.set(key as PlaceAPIKeyDetails);
this._change.set(Date.now());
notifySuccess('Successfully created new API key.');
Expand All @@ -199,21 +204,22 @@ export class APIKeyService {
if (details?.reason !== 'done') return;
ref.componentInstance.loading.set('Updating API key...');
const domain = this._domain();
await update({
id: key.id,
query_params: {},
fn: (d) => new PlaceAPIKeyDetails(d),
path: 'api_keys',
method: 'patch',
form_data: {
...details.metadata,
authority_id: domain.id,
},
}).catch((_) => {
try {
await update({
id: key.id,
query_params: {},
fn: (d) => new PlaceAPIKeyDetails(d),
path: 'api_keys',
method: 'patch',
form_data: {
...details.metadata,
authority_id: domain.id,
},
});
} catch (_) {
ref.close();
notifyError(_);
throw _;
});
return notifyError(describeError(_));
}
this._change.set(Date.now());
notifySuccess('Successfully updated API key.');
ref.close();
Expand All @@ -237,6 +243,8 @@ export class APIKeyService {
query_params: {},
path: 'api_keys',
});
} catch (error) {
return notifyError(describeError(error));
} finally {
details.close();
}
Expand Down
5 changes: 2 additions & 3 deletions src/app/admin/broker-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
updateBroker,
} from '@placeos/ts-client';
import { AsyncHandler } from '../common/async-handler.class';
import { readError } from '../common/errors';
import { addSignalChipItem, getInvalidSignalFields } from '../common/forms';
import { HotkeysService } from '../common/hotkeys.service';
import { i18n } from '../common/locale.service';
Expand Down Expand Up @@ -429,9 +430,7 @@ export class BrokerFormComponent extends AsyncHandler implements OnInit {
this._dialog_ref.disableClose = false;
notifyError(
i18n(`${this._name}.SAVE_ERROR`, {
error: JSON.stringify(
(await err.text?.()) || err.message || err,
),
error: await readError(err),
}),
);
return null;
Expand Down
16 changes: 10 additions & 6 deletions src/app/admin/brokers.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '@placeos/ts-client';

import { AsyncHandler } from '../common/async-handler.class';
import { describeError } from '../common/errors';
import { notifyError, notifySuccess } from '../common/notifications';
import { FormModalComponent } from '../common/types';
import { openConfirmModal } from '../overlays/confirm-modal.component';
Expand Down Expand Up @@ -257,9 +258,7 @@ export class AdminBrokersComponent extends AsyncHandler implements OnInit {
details.close();
if (err)
return notifyError(
`Error deleting broker. Error: ${JSON.stringify(
err.response || err.message || err,
)}`,
`Error deleting broker. Error: ${describeError(err)}`,
);
notifySuccess(`Successfully deleted broker "${item.name}".`);
this.loadBrokers();
Expand All @@ -268,8 +267,13 @@ export class AdminBrokersComponent extends AsyncHandler implements OnInit {

public async loadBrokers() {
this.loading.set(true);
const brokers = await queryBrokers().then((r) => r.data);
this.brokers.set(brokers);
this.loading.set(false);
try {
const brokers = await queryBrokers().then((r) => r.data);
this.brokers.set(brokers);
} catch (err) {
notifyError(`Failed to load brokers. Error: ${describeError(err)}`);
} finally {
this.loading.set(false);
}
}
}
8 changes: 2 additions & 6 deletions src/app/admin/build-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { del, get } from '@placeos/ts-client';
import { toQueryString } from '../common/api';
import { describeError } from '../common/errors';
import { escapeHtml } from '../common/general';
import { i18n } from '../common/locale.service';
import { notifyError, notifySuccess } from '../common/notifications';
Expand Down Expand Up @@ -170,12 +171,7 @@ export class PlaceBuildListComponent implements OnInit {
if (err)
return notifyError(
i18n('ADMIN.BUILD_LIST_REMOVE_ERROR', {
error:
(err as { statusText?: string; message?: string })
.statusText ||
(err as { statusText?: string; message?: string })
.message ||
err,
error: describeError(err),
}),
);
this.last_change.set(null);
Expand Down
14 changes: 10 additions & 4 deletions src/app/admin/cluster-details/cluster-task-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { AsyncHandler } from '../../common/async-handler.class';
import { describeError } from '../../common/errors';
import { i18n } from '../../common/locale.service';
import { notifyError } from '../../common/notifications';
import { signalFromSubscribable } from '../../common/signals';
Expand Down Expand Up @@ -274,9 +275,7 @@ export class PlaceClusterTaskListComponent
this.killing.set(null);
notifyError(
i18n('ADMIN.CLUSTER_PROCESS_KILL_ERROR', {
error: JSON.stringify(
err.response || err.message || err,
),
error: describeError(err),
}),
);
ref.close();
Expand All @@ -294,7 +293,14 @@ export class PlaceClusterTaskListComponent
public async loadCluster(id: string) {
const clusters = await queryClusters({
q: id,
} as Record<string, string>).then((_) => _.data);
} as Record<string, string>)
.then((_) => _.data)
.catch((err) => {
notifyError(
`Failed to load cluster. Error: ${describeError(err)}`,
);
return [];
});
// The search may return other clusters, so only accept an exact id
const match = clusters.find((_) => _.id === id) || null;
this.cluster.set(match);
Expand Down
20 changes: 4 additions & 16 deletions src/app/admin/database-details.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { addZone, PlaceZone, queryZones, showZone } from '@placeos/ts-client';
import { MatRippleModule } from '@angular/material/core';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { readError } from '../common/errors';
import { csvToJson, downloadFile, jsonToCsv } from '../common/general';
import {
notifyError,
notifySuccess,
notifyWarn,
} from '../common/notifications';
import { describeError } from '../overlays/confirm-modal.component';
import { ZoneTreeExportModalComponent } from './zone-tree-export-modal.component';

type ZoneTreeExportItem = Record<string, unknown> & {
Expand Down Expand Up @@ -200,13 +200,7 @@ export class PlaceDatabaseDetailsComponent {
await this.importZoneTree(zones);
} catch (err) {
notifyError(
`Error importing zone tree. Error: ${JSON.stringify(
(err as { response?: unknown; message?: unknown })
.response ||
(err as { response?: unknown; message?: unknown })
.message ||
err,
)}`,
`Error importing zone tree. Error: ${await readError(err)}`,
);
}
this.importing_zones.set(false);
Expand All @@ -227,13 +221,7 @@ export class PlaceDatabaseDetailsComponent {
notifySuccess(`Exported ${zones.length} zones.`);
} catch (err) {
notifyError(
`Error exporting zone tree. Error: ${JSON.stringify(
(err as { response?: unknown; message?: unknown })
.response ||
(err as { response?: unknown; message?: unknown })
.message ||
err,
)}`,
`Error exporting zone tree. Error: ${await readError(err)}`,
);
}
this.exporting_zones.set(false);
Expand Down Expand Up @@ -276,7 +264,7 @@ export class PlaceDatabaseDetailsComponent {
notifyError(
`Error importing zone tree. Created ${id_map.size} of ${
zones.length
} zones before the error. Error: ${describeError(err)}`,
} zones before the error. Error: ${await readError(err)}`,
);
return;
}
Expand Down
36 changes: 20 additions & 16 deletions src/app/admin/details.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { BackofficeUsersService } from '../users/users.service';

import { DatePipe, SlicePipe } from '@angular/common';
import { format } from 'date-fns';
import { describeError } from '../common/errors';
import { copyToClipboard } from '../common/general';
import { i18n } from '../common/locale.service';
import { TranslatePipe } from '../ui/translate.pipe';
Expand Down Expand Up @@ -253,34 +254,37 @@ export class PlaceDetailsComponent extends AsyncHandler implements OnInit {
(err) =>
notifyError(
i18n('ADMIN.BACKEND_SERVICES_ERROR', {
error: JSON.stringify(
err.response || err.message || err,
),
error: describeError(err),
}),
),
);
this.api_details.set((details as PlaceServiceDetails[]) || []);
}

public async loadPlatformDetails() {
const { changelog, version } = await get(
`${apiEndpoint()}/platform`,
).catch((err) => {
void this.loadBackofficeChangelog();
const platform = await get(`${apiEndpoint()}/platform`).catch((err) => {
notifyError(
i18n('ADMIN.BACKEND_SERVICES_ERROR', {
error: JSON.stringify(err.response || err.message || err),
error: describeError(err),
}),
);
throw err;
return null;
});
this.changelog_data.set(changelog.replace('# Changelog\n\n', ''));
this.backend_version.set(version);
this.backoffice_logs.set(
await (
await fetch(
'https://raw.githubusercontent.com/PlaceOS/backoffice/develop/CHANGELOG.md',
)
).text(),
if (!platform) return;
const { changelog, version } = platform;
this.changelog_data.set(
(changelog ?? '').replace('# Changelog\n\n', ''),
);
this.backend_version.set(version);
}

/** Loads the backoffice changelog from GitHub. Failure only hides the link. */
private async loadBackofficeChangelog() {
const response = await fetch(
'https://raw.githubusercontent.com/PlaceOS/backoffice/develop/CHANGELOG.md',
).catch(() => null);
if (!response?.ok) return;
this.backoffice_logs.set(await response.text().catch(() => ''));
}
}
Loading
Loading