Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
193 commits
Select commit Hold shift + click to select a range
a5b0246
fix(vue): give Layout the hostnames mixin so the footer links get an …
suculent Sep 25, 2026
3c906ff
fix(csrf): send X-XSRF-TOKEN from the classic dashboard (Phase 25 D-18)
suculent Sep 29, 2026
7c6f90c
fix(docker): run the Vue console nginx as the unprivileged nginx user
suculent Sep 30, 2026
5d3ab53
fix(csrf): re-prime the XSRF token on /oauth-return (Phase 25-06)
suculent Oct 1, 2026
c58dd09
fix(nginx): mirror the gluster console headers (Phase 25 SEC-CSP-04)
suculent Oct 1, 2026
fd16b2a
test(vue): add failing History audit paging unit test (phase 26)
suculent Oct 1, 2026
7200f1b
feat(vue): add History audit Load more with paged API (phase 26)
suculent Oct 1, 2026
9a362ac
test(vue): add failing build paging and table independence checks (ph…
suculent Oct 1, 2026
fb5a307
feat(vue): add History build Load more and first-page stores (phase 26)
suculent Oct 1, 2026
04e712f
test(vue): add failing History paging state and a11y checks (phase 26)
suculent Oct 1, 2026
1cc6897
feat(vue): add History paging states and a11y (phase 26)
suculent Oct 1, 2026
9b0cae8
test(vue): add Cypress session-token stub and in-app route entry (pha…
suculent Oct 1, 2026
3e77525
test(vue): add History paging Cypress coverage with two-page stubs (p…
suculent Oct 1, 2026
2c8ad4c
test(vue): add failing dark-theme table row contrast check (phase 26)
suculent Oct 2, 2026
3153cac
fix(vue): add readable dark-theme warning and danger table rows (phas…
suculent Oct 2, 2026
592f251
test(console): failing check for escaped notification toasts
suculent Oct 3, 2026
e43a94d
fix(console): escape device-supplied notification fields in toasts
suculent Oct 3, 2026
d1e5d5f
test(vue): failing check for the one-time API key dialog
suculent Oct 3, 2026
7d8098e
fix(vue): open the one-time API key dialog with the server's api_key …
suculent Oct 3, 2026
516d628
chore(vue): drop the apikey store's key column and sample key
suculent Oct 3, 2026
d5c09e7
chore: copyright 2018 - 2026 in classic and Vue console footers
suculent Oct 4, 2026
956a7a2
feat(console): implement v1.16 usability, build logs, transformers an…
suculent Oct 9, 2026
c03dac8
Merge pull request #32 from thinx-cloud/gsd/v1.16-console-usability
suculent Oct 9, 2026
b7b5b29
test(vue): add failing linked repository link checks (G-35-4)
suculent Oct 12, 2026
8815aa7
fix(vue): link http(s) repository urls in a new tab (G-35-4)
suculent Oct 12, 2026
4552901
test(vue): cover non-http repository url schemes (G-35-4)
suculent Oct 12, 2026
52bf1e5
fix(vue): refuse transformer saves after a failed load (35 CR-01)
suculent Oct 12, 2026
7d39da4
fix(vue): keep history build rows as table rows (35 WR-01)
suculent Oct 12, 2026
c372197
fix(vue): assign new transformers from the stored list (35 WR-02)
suculent Oct 12, 2026
fe6c111
fix(vue): keep an open environment draft on Environment (35 WR-03)
suculent Oct 12, 2026
e53f2e9
fix(console): send only changed info keys on profile saves (35 WR-04)
suculent Oct 12, 2026
295c83a
fix(vue): report failed deploy-key list loads (35 WR-05)
suculent Oct 12, 2026
c47cd21
fix(vue): confirm before deleting deploy keys (35 WR-06)
suculent Oct 12, 2026
d4b1b41
fix(vue): fix PROF-06 spec and run unit suites in CI (35 WR-07)
suculent Oct 12, 2026
e84ef46
test(vue): add failing device build history checks (G-36-3)
suculent Oct 12, 2026
6bf96eb
fix(vue): keep device build history summary-only (G-36-3)
suculent Oct 12, 2026
5e5783a
test(vue): cover summary-only device build history in e2e (G-36-3)
suculent Oct 12, 2026
38eb95b
fix(vue): readable build log column, View button and TIMEOUT colour
suculent Oct 12, 2026
5f0d73a
test(vue): add failing transformer checkbox checks (G-37-5)
suculent Oct 12, 2026
1f0626c
fix(vue): show device transformers as checkboxes (G-37-5)
suculent Oct 12, 2026
4cbf1da
test(vue): cover transformer checkboxes in e2e (G-37-5)
suculent Oct 12, 2026
ff6e809
fix(vue): show orphaned transformer assignments as checkboxes (37 WR-01)
suculent Oct 12, 2026
b85993b
test(vue): add failing build footer checks (UI-05)
suculent Oct 12, 2026
ee79ca6
feat(vue): shared build footer with build year and commit id on login…
suculent Oct 12, 2026
ec1ff5b
test(vue): expect the build footer on every page with AA colours (UI-05)
suculent Oct 12, 2026
f71219f
feat(vue): build footer on password reset and the app layout, readabl…
suculent Oct 12, 2026
cf65b79
test(vue): add failing welcome login checks (LOGIN-01..03)
suculent Oct 12, 2026
cfff199
feat(vue): branded welcome login with social logins under a green Log…
suculent Oct 12, 2026
89c8068
test(vue): add failing platform bullet checks (DEV-04)
suculent Oct 13, 2026
b74d361
feat(vue): shared platform module and bullet in the device table (DEV…
suculent Oct 13, 2026
cde2738
test(vue): expect platform colours and the repository bullet (DEV-04,…
suculent Oct 13, 2026
e67d54f
feat(vue): platform palette and repository platform bullet (DEV-04, R…
suculent Oct 13, 2026
b5967db
test(vue): expect device icon tiles and the platform filter (DEV-01)
suculent Oct 13, 2026
96957a6
feat(vue): device icons on platform tiles, platform filter and sort (…
suculent Oct 13, 2026
fff5f31
test(vue): add failing icon button and actions cell checks (DEV-03)
suculent Oct 13, 2026
8d993f4
feat(vue): shared IconButton and a one-line actions cell with the Edi…
suculent Oct 13, 2026
f108f1c
test(vue): expect the hammer build action and the view-log action (DE…
suculent Oct 13, 2026
ad0fab6
feat(vue): hammer build action with in-flight guard, view-log and rev…
suculent Oct 13, 2026
03e307b
test(vue): expect Legacy status, firmware and the API-key warning (DE…
suculent Oct 13, 2026
6a34102
feat(vue): heartbeat status, firmware cogs and missing API-key warnin…
suculent Oct 13, 2026
ab67550
test(vue): make the History hint check locale-independent (44 IN-05)
suculent Oct 13, 2026
6ba1757
test(vue): check the repositories platform column, not a git diff (44…
suculent Oct 13, 2026
d9e3161
fix(vue): use Legacy's No API Key assigned tip for the API-key warnin…
suculent Oct 13, 2026
50c7d2e
fix(vue): read only strings in the platform, status and icon helpers …
suculent Oct 13, 2026
fb39b45
fix(vue): show the backend platform python as Micropython (44 WR-01)
suculent Oct 13, 2026
077ec7d
fix(vue): show an error and clear Loading... when the device list fai…
suculent Oct 13, 2026
755086d
fix(vue): open the newest build of the device in View log, failed one…
suculent Oct 13, 2026
4392a3e
fix(vue): bulk actions act only on visible devices; stale platform fi…
suculent Oct 13, 2026
18e843f
fix(vue): grid last-seen line in the body colour, not text-muted (44 UI)
suculent Oct 13, 2026
e10f539
fix(vue): 4px toolbar and pill spacing instead of the Bootstrap 5 gap…
suculent Oct 13, 2026
69eaeb7
fix(vue): ellipsise table firmware at 240px on a block inside the cel…
suculent Oct 13, 2026
f565857
fix(vue): show the API reason of a failed build, else Build failed. (…
suculent Oct 13, 2026
604258c
fix(vue): device text fields never throw, mongooseos maps to MongooseOS
suculent Oct 13, 2026
a90ca60
test(vue): add failing deploy-key row delete checks (KEY-05, POL-04)
suculent Oct 13, 2026
9cddd11
feat(vue): deploy-key row delete icon with confirm and in-flight guar…
suculent Oct 13, 2026
36b0278
test(vue): expect deploy-key icon actions and readable columns (KEY-0…
suculent Oct 13, 2026
cd349fe
feat(vue): deploy-key show and copy icons, ellipsised names, fingerpr…
suculent Oct 13, 2026
c77f997
test(vue): expect the deploy-key bulk toolbar, form spacing and load …
suculent Oct 13, 2026
5b1eb95
feat(vue): deploy-key bulk toolbar, form spacing and one load error (…
suculent Oct 13, 2026
686a113
test(vue): add failing deploy-key rename checks (KEY-04)
suculent Oct 13, 2026
3d7eb9b
feat(vue): rename a deploy key from its row (KEY-04, D-09, D-10)
suculent Oct 13, 2026
34ed39d
test(vue): expect readable deploy-key name errors on the generate for…
suculent Oct 13, 2026
31ed738
feat(vue): name the refused character on the deploy-key generate form…
suculent Oct 13, 2026
6558cab
fix(vue): refuse ALM, invisible characters and lone surrogates in key…
suculent Oct 13, 2026
a7cf868
fix(vue): refuse a key's own default name in the rename dialog (IN-02)
suculent Oct 13, 2026
258c5c5
fix(vue): reload and say so when a deploy key is gone or cannot be re…
suculent Oct 13, 2026
9b0ea53
fix(vue): keep the Generate feedback line 4px under its field (45 UI …
suculent Oct 13, 2026
eaf9cc2
fix(vue): do not resend a deploy-key name the server refused (45 UI r…
suculent Oct 13, 2026
c267340
fix(vue): refresh deploy keys in place and return focus after rename …
suculent Oct 13, 2026
53f7192
fix(vue): set the rename help line to the Label weight 400 (45 UI rev…
suculent Oct 13, 2026
0fd8dab
fix(vue): fetch the deploy-key list once after a delete or generate (…
suculent Oct 13, 2026
6f8902b
style(vue): drop the no-op gap on the deploy-key toolbar (45 UI review)
suculent Oct 13, 2026
29cdcfb
fix(vue): bring the created-key modal in line with Phase 45 (45 UI re…
suculent Oct 13, 2026
efc8cd2
fix(vue): allow ZWNJ and ZWJ inside deploy-key names (D-06)
suculent Oct 13, 2026
a31c0e2
feat(vue): name the required scopes on the GitHub token panel
suculent Oct 13, 2026
316c5f9
feat(vue): explain deploy keys skipped as in use elsewhere
suculent Oct 13, 2026
29727e8
test(vue): add failing transformer typed-confirm delete checks (TRANS…
suculent Oct 13, 2026
ed429ec
feat(vue): transformer row icons and typed-confirm delete (TRANS-04, …
suculent Oct 13, 2026
64d69bd
test(vue): expect transformer bulk delete, usage warning and load sta…
suculent Oct 13, 2026
94ba8ef
feat(vue): bulk transformer delete with the device usage warning (TRA…
suculent Oct 13, 2026
32533dc
test(vue): expect transformer add and create copy and the phase 46 st…
suculent Oct 13, 2026
c31a9c5
feat(vue): plus and white wrench on transformers, name copy, shared s…
suculent Oct 13, 2026
8e898de
test(vue): add failing environment edit checks (ENV-01, D-03)
suculent Oct 13, 2026
8b26ad6
feat(vue): edit an environment variable value in place (ENV-01, D-01,…
suculent Oct 13, 2026
aef5a22
fix(vue): keep a stored environment write a success when the list ref…
suculent Oct 13, 2026
3e8ab8d
test(vue): expect the guarded environment bulk delete and load states…
suculent Oct 13, 2026
11b8552
feat(vue): guarded environment bulk delete and one load error (D-16)
suculent Oct 13, 2026
cbe7076
test(vue): expect environment add copy, duplicate refusal and styles …
suculent Oct 13, 2026
f2d26f8
feat(vue): add variable without silent overwrite, environment styles …
suculent Oct 13, 2026
25c20d4
test(vue): add failing unsaved transformer leave checks (37 IN-02, D-10)
suculent Oct 13, 2026
dac2c5e
feat(vue): warn before leaving unsaved transformer ticks (37 IN-02, D…
suculent Oct 13, 2026
1a604bf
test(vue): expect the transformer card dirty, saving and result state…
suculent Oct 13, 2026
d526ff7
feat(vue): saving and unsaved states on the transformer card (POL-03,…
suculent Oct 13, 2026
75624ce
test(vue): expect the transformer editor name copy (D-14)
suculent Oct 13, 2026
8c354de
feat(vue): transformer editor says name, keeps the shared leave guard…
suculent Oct 13, 2026
a16307a
test(vue): name the theme source and assert transformers saved in cyp…
suculent Oct 13, 2026
f418ce5
test(vue): expect device detail saves to keep unsaved drafts (CR-01, …
suculent Oct 13, 2026
31bce2b
fix(vue): keep unsaved device detail drafts across saves and a failed…
suculent Oct 13, 2026
58660dc
test(vue): add failing build log search checks (BUILD-03)
suculent Oct 15, 2026
e48608b
feat(vue): live search with highlighted matches in the build log (BUI…
suculent Oct 15, 2026
4078f46
test(vue): expect build log match stepping and scroll (BUILD-03, D-03…
suculent Oct 15, 2026
47aace4
feat(vue): step through build log matches with wrap and scroll (D-03,…
suculent Oct 15, 2026
a1b475a
test(vue): expect id-only build log open, states and log styles (D-15…
suculent Oct 15, 2026
002e051
fix(vue): open build logs by build id only, reset on close, search st…
suculent Oct 15, 2026
e0e224d
test(vue): expect the dashboard recent builds card to open the build …
suculent Oct 15, 2026
772e928
feat(vue): open the build log from the dashboard recent builds card (…
suculent Oct 15, 2026
e10de49
test(vue): expect static navbar rows, span markup and one status mapp…
suculent Oct 15, 2026
f64a153
fix(vue): static navbar rows without a build id and list markup (D-14…
suculent Oct 15, 2026
3bc6a4d
test(vue): guard every build history cell and collect construction wa…
suculent Oct 15, 2026
591033e
test(vue): click every build history cell before view and expect no r…
suculent Oct 15, 2026
b1edab2
test(vue): expect one build log predicate for the dialog and dashboar…
suculent Oct 15, 2026
83cc7cc
fix(vue): one build log predicate and view build log label on the das…
suculent Oct 15, 2026
102929b
test(vue): expect history and navbar rows to follow the build log pre…
suculent Oct 15, 2026
9daa778
fix(vue): history and navbar rows follow the build log predicate (WR-…
suculent Oct 15, 2026
389a5d0
test(vue): expect device build history on the build log predicate and…
suculent Oct 15, 2026
54734af
fix(vue): device build history follows the build log predicate (WR-01)
suculent Oct 15, 2026
bc9f2a6
test(vue): add failing deep-link reload checks (NOTIF-04, D-07)
suculent Oct 15, 2026
d80d148
fix(vue): keep a reloaded deep link on its page (NOTIF-04, D-07)
suculent Oct 15, 2026
af06362
test(vue): expect undefined for an empty api envelope (35 IN-01, D-12)
suculent Oct 15, 2026
056ef3c
fix(vue): return undefined for an empty api envelope (35 IN-01, D-12)
suculent Oct 15, 2026
824687f
test(vue): behavioural cases for header, notifications and history (3…
suculent Oct 15, 2026
794f357
test(vue): cover the create and assign failure path (35 IN-08)
suculent Oct 15, 2026
c84c5d5
test(vue): expect an in-flight build firmware button and a capped col…
suculent Oct 15, 2026
8a7d0ab
feat(vue): build firmware in-flight state and a capped detail column …
suculent Oct 15, 2026
cc2c1cf
test(vue): expect an accessible account menu and readable danger aler…
suculent Oct 15, 2026
2c75b9e
feat(vue): account menu icon and name, readable danger alerts (POL-01…
suculent Oct 15, 2026
dcde0ae
test(vue): expect accessible toggles, focusable markers and a label s…
suculent Oct 15, 2026
e1197b3
feat(vue): accessible device list toggles, markers, label sort and ud…
suculent Oct 15, 2026
852fef5
test(vue): cite the device list parity harness as L7 (D-14)
suculent Oct 15, 2026
efc66f6
test(console): expect readable legacy deploy-key errors and a reset o…
suculent Oct 15, 2026
2105310
fix(console): readable legacy deploy-key errors and a reset on every …
suculent Oct 15, 2026
72caa31
test(console): expect legacy build toasts, frame history and init on …
suculent Oct 15, 2026
bff9552
fix(console): build toast copy, frame history, init on first open, go…
suculent Oct 15, 2026
a076889
ci(vue): same-origin cypress runs with junit results (CI-07, D-01, D-04)
suculent Oct 15, 2026
16198ef
test(vue): stub the ci login and gate the live login on cypress_live_…
suculent Oct 15, 2026
4b867f6
test(vue): device specs for the phase 44 and 48 ui (CI-07, D-06)
suculent Oct 15, 2026
44a9db6
chore(console): stop tracking the legacy cypress env file (D-05)
suculent Oct 15, 2026
1d68915
fix(vue): render device toggle and pill aria-pressed through the bv p…
suculent Oct 15, 2026
4358845
test(vue): reproduce the junit reporter crash on a repeated end (CI-07)
suculent Oct 16, 2026
16bb611
ci(vue): crash-proof junit reporter for cypress ci runs (CI-07)
suculent Oct 16, 2026
0692f0f
ci(vue): hermetic cypress ci runs without video (CI-07)
suculent Oct 16, 2026
9a0e1cd
test(vue): reproduce the api client rejecting on a failed fetch (CI-0…
suculent Oct 16, 2026
09fbde1
fix(vue): resolve a failed fetch in the api client instead of rejecti…
suculent Oct 16, 2026
512ddb5
test(vue): settle the dashboard reads before the logged-out deep-link…
suculent Oct 16, 2026
bd1e0a1
fix(48): mark network failures in the api client so pages show their …
suculent Oct 16, 2026
64f773e
fix(48): read the response body inside the api client's network guard…
suculent Oct 16, 2026
bb0e5ef
fix(48): drop the sonarcloud context from the test_vue job (48-REVIEW…
suculent Oct 16, 2026
355e868
fix(48): show Build failed. on a refused Legacy build instead of an e…
suculent Oct 16, 2026
13b71be
chore(console): drop sonarcloud context from vue publish job, remove …
suculent Oct 17, 2026
cd016ec
chore(console): remove remaining "+++ update*" debug logs from Legacy…
suculent Oct 17, 2026
7b195ad
test(vue): reproduce the admin deep link redirect (NOTIF-04)
suculent Oct 17, 2026
f18ce35
fix(vue): load the profile before the admin route check (NOTIF-04)
suculent Oct 17, 2026
d60bbcc
test(vue): cover admin reload, non-admin and logged-out deep links (N…
suculent Oct 17, 2026
b6d2039
test(vue): reproduce the silent API key load failure (audit W2)
suculent Oct 17, 2026
b1ef8be
test(vue): add a tap reporter mode to the audit-gaps harness
suculent Oct 17, 2026
dafc8a5
fix(vue): show one error when the API key list cannot be reached (aud…
suculent Oct 17, 2026
9f77118
test(vue): reproduce the silent channel and repository load failures …
suculent Oct 17, 2026
2e8c1f3
fix(vue): show one error when channels or repositories cannot be reac…
suculent Oct 17, 2026
b746560
test(vue): reproduce the unguarded profile read (audit W2)
suculent Oct 17, 2026
bc7c5de
fix(vue): absorb a failed profile read and show one load error (audit…
suculent Oct 17, 2026
86dc2ff
test(vue): cover deploy-key rename and delete in the gating suite (CI…
suculent Oct 17, 2026
187ea0b
test(vue): cover transformer bulk delete and variable edit in the gat…
suculent Oct 17, 2026
4fef60d
test(vue): cover the repositories bullet and build-log search in the …
suculent Oct 17, 2026
9cb9ba2
fix(vue): reset the profile on sign-out and before the sign-in read (…
suculent Oct 18, 2026
47fffe7
fix(vue): reset the profile on both ends of admin impersonation (48.1…
suculent Oct 18, 2026
ec63c74
fix(vue): bind the header name and avatar to the profile store (48.1-…
suculent Oct 18, 2026
da79c31
feat(40-03): show the D-03 sentence on the Deploy Keys page for key_s…
suculent Oct 19, 2026
fe6a1c1
test(40-03): add failing check for the D-03 sentence in the Profile G…
suculent Oct 19, 2026
4724d20
feat(40-03): show the D-03 sentence for key_service_unavailable in th…
suculent Oct 19, 2026
62414c3
test(40-03): add failing legacy deploy-key checks for key_service_una…
suculent Oct 19, 2026
7e3d1fe
feat(40-03): show the D-03 sentence for key_service_unavailable in th…
suculent Oct 19, 2026
ec5b7f1
chore(vue): remove the unused Google Maps plugin and its API key wiring
suculent Oct 21, 2026
3a372a5
chore(release): bump vue console version to 2.2.0
suculent Oct 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,21 @@ jobs:
- run:
name: Install dependencies and build
command: |
export ENV NODE_OPTIONS=--openssl-legacy-provider
export NODE_OPTIONS=--openssl-legacy-provider
cd vue
yarn
# Node unit suites, no browser (35 WR-07). LC_ALL=C pins
# toLocaleString, which log-paging-store.cjs compares against.
LC_ALL=C yarn test:unit
LC_ALL=C node ../src/test/deploykey.cjs
LC_ALL=C node ../src/test/legacy-close-out.cjs
yarn build:perf
yarn test
yarn test:ci

- store_test_results:
name: Collect test results
path: ./vue/coverage

# The `path` key is an absolute or relative path to your working_directory containing
# subdirectories of JUnit XML or Cucumber JSON test metadata files,
# or the path of a single file containing all test results.
# Make sure that your path value is not a hidden folder (example: .my_hidden_directory would be an invalid format).
# The Cypress JUnit files written by cy:test:ci (one per spec file).
path: ./vue/cypress/results

- store_artifacts:
name: Collect screenshots
Expand Down Expand Up @@ -179,9 +180,11 @@ workflows:
# only:
# - thinx-staging

# No context (48-REVIEW WR-03): this job runs yarn with no lockfile, so unpinned
# dependencies' lifecycle scripts run here, and no step needs a credential. The
# Cypress suites stub the API; the parent repo's test-vue-console runs them the same way.
- test_vue:
name: Test Vue console
context: sonarcloud

# - ggshield/scan:
# name: Scan using Gitguardian shield
Expand Down Expand Up @@ -212,7 +215,6 @@ workflows:
context:
- dockerhub
- thinx-docker-repo
- sonarcloud
- console
requires:
- Test Vue console
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ html
src/.nyc_output
src/cypress/screenshots
src/cypress/videos
src/cypress/.env.test
yarn.lock
.dccache
settings.json
Expand Down
3 changes: 0 additions & 3 deletions src/app/js/controllers/ChannelController.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ angular.module( "RTM" ).controller( "ChannelController", [ "$rootScope", "$scope

Thinx.channelList()
.done( function( data ) {
console.log( "+++ updateChannels " );
$scope.$emit( "updateChannels", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
Expand All @@ -33,7 +32,6 @@ angular.module( "RTM" ).controller( "ChannelController", [ "$rootScope", "$scope
console.log( response );
Thinx.channelList()
.done( function( data ) {
console.log( "+++ updateChannels " );
$scope.$emit( "updateChannels", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
Expand Down Expand Up @@ -69,7 +67,6 @@ angular.module( "RTM" ).controller( "ChannelController", [ "$rootScope", "$scope

Thinx.channelList()
.done( function( data ) {
console.log( "+++ updateChannels " );
$scope.$emit( "updateChannels", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
Expand Down
135 changes: 104 additions & 31 deletions src/app/js/controllers/DeploykeyController.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ angular.module( "RTM" ).controller( "DeploykeyController", [ "$rootScope", "$sco

Thinx.deploykeyList()
.done( function( data ) {
console.log( "+++ updateDeploykeys " );
$scope.$emit( "updateDeploykeys", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
Expand All @@ -24,45 +23,118 @@ angular.module( "RTM" ).controller( "DeploykeyController", [ "$rootScope", "$sco

$scope.searchText = "";

$scope.createDeploykey = function() {

console.log( "--creating deploy key--" );

Thinx.createDeploykey()
.done( function( response ) {
// Deploy key names (v1.18 Phase 48, D-09, UI-C18, 35 IN-03/IN-04). The sentences mirror
// vue/src/utils/keyNames.js word for word (src/test/deploykey.cjs D10 compares them); the
// server (RSAKey.validateKeyName) stays the authority, this check only saves a round trip.
var KEY_NAME_MAX = 120;
var KEY_NAME_MESSAGES = {
empty: "Enter a name for the key.",
too_long: "The name is longer than 120 characters.",
control_chars: "The name contains a control character, such as a tab or a line break.",
line_separator: "The name contains a hidden line or paragraph separator.",
bidi: "The name contains a hidden direction-override character.",
invisible: "The name contains an invisible character, such as a zero-width space.",
reserved: "This name is reserved for the key's default label. Choose a different name."
};
var KEY_NAME_FALLBACK = "This name is not allowed. Choose a different name.";
var CREATE_FAILED = "Could not generate the deploy key. Try again.";
// Phase 40 D-03: OpenBao unavailable or key generation switched off (503). The fixed
// sentence only; the code and any OpenBao detail are never shown.
var KEY_SERVICE_UNAVAILABLE = "Deploy keys can't be created right now, try again later.";

// The reason the trimmed name is refused before sending, or null.
// Code units are compared as numbers on purpose: a regular expression with a
// control-character class trips Codacy no-control-regex (quick 261012-r9z).
function keyNameProblem( name ) {
for ( var i = 0; i < name.length; i++ ) {
var c = name.charCodeAt( i );
if ( c < 0x20 || c === 0x7F ) {
return "control_chars";
}
}
if ( name.length > KEY_NAME_MAX ) {
return "too_long";
}
return null;
}

response = JSON.parse( response );
// The fixed sentence for a refusal reason; never the reason code itself.
function keyNameSentence( reason ) {
if ( typeof reason === "string" && Object.prototype.hasOwnProperty.call( KEY_NAME_MESSAGES, reason ) ) {
return KEY_NAME_MESSAGES[ reason ];
}
return KEY_NAME_FALLBACK;
}

if ( typeof( response ) !== "undefined" ) {
if ( response.success ) {
console.log( response );
toastr.success( "Key created.", "<ENV::loginPageTitle>", { timeOut: 5000 } );
// One fixed sentence, written as text (toastr renders HTML, so no reply field goes in).
function showCreateError( sentence ) {
$( ".msg-warning" ).text( sentence );
$( ".msg-warning" ).show();
toastr.error( sentence, "<ENV::loginPageTitle>", { timeOut: 5000 } );
}

$scope.deploykeyCreated = response.status.name;
$scope.deploykeyValue = response.status.pubkey;
$scope.createDeploykey = function() {

Thinx.deploykeyList()
.done( function( data ) {
console.log( "+++ updateDeploykeys " );
$scope.$emit( "updateDeploykeys", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
console.log( "--creating deploy key--" );

if ($scope.creatingDeploykey || !$scope.deploykeyName || !$scope.deploykeyName.trim()) return;
var name = $scope.deploykeyName.trim();
var problem = keyNameProblem( name );
if ( problem !== null ) {
showCreateError( keyNameSentence( problem ) );
return;
}
$scope.creatingDeploykey = true;
Thinx.createDeploykey( name )
.done( function( response ) {
// jQuery does not wrap .done callbacks: a throw here would skip .always, so the
// reset lives in finally as well (35 IN-03).
try {
if ( response && response.success ) {
var key = response.response || response.status;
if ( !key || typeof key !== "object" || !key.pubkey ) {
showCreateError( CREATE_FAILED );
} else {
toastr.success( "Key created.", "<ENV::loginPageTitle>", { timeOut: 5000 } );

$scope.deploykeyCreated = key.date || key.name;
$scope.deploykeyValue = key.pubkey;

Thinx.deploykeyList()
.done( function( data ) {
$scope.$emit( "updateDeploykeys", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
}
} else if ( response && response.response === "invalid_key_name" ) {
showCreateError( keyNameSentence( response.reason ) );
} else if ( response && response.response === "key_service_unavailable" ) {
showCreateError( KEY_SERVICE_UNAVAILABLE );
} else {
console.log( response.status );
toastr.error( "Error.", "<ENV::loginPageTitle>", { timeOut: 5000 } );
showCreateError( CREATE_FAILED );
}
} catch ( e ) {
showCreateError( CREATE_FAILED );
} finally {
$scope.creatingDeploykey = false;
$scope.$applyAsync();
}
} )
.fail( function( jqXHR ) {
var body = jqXHR && jqXHR.responseJSON;
if ( body && body.response === "invalid_key_name" ) {
showCreateError( keyNameSentence( body.reason ) );
} else if ( body && body.response === "key_service_unavailable" ) {
showCreateError( KEY_SERVICE_UNAVAILABLE );
} else {
console.log( "error" );
console.log( response );
showCreateError( CREATE_FAILED );
}
$scope.$emit( "xhrFailed", jqXHR );
} )
.fail( function( error ) {
$( ".msg-warning" ).text( error );
$( ".msg-warning" ).show();
$scope.$emit( "xhrFailed", error );
toastr.error( "Error.", "<ENV::loginPageTitle>", { timeOut: 5000 } );
} );
.always(function() {
$scope.creatingDeploykey = false;
$scope.$applyAsync();
});

};

Expand All @@ -80,7 +152,6 @@ angular.module( "RTM" ).controller( "DeploykeyController", [ "$rootScope", "$sco

Thinx.deploykeyList()
.done( function( data ) {
console.log( "+++ updateDeploykeys " );
$scope.$emit( "updateDeploykeys", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
Expand Down Expand Up @@ -116,6 +187,8 @@ angular.module( "RTM" ).controller( "DeploykeyController", [ "$rootScope", "$sco
};

$scope.resetModal = function() {
$scope.deploykeyName = "";
$scope.creatingDeploykey = false;
$scope.deploykeyCreated = null;
$scope.deploykeyValue = null;
$scope.selectedItems = [];
Expand Down
4 changes: 0 additions & 4 deletions src/app/js/controllers/DeviceController.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,18 @@ angular.module( "RTM" ).controller( "DeviceController", [ "$rootScope", "$scope"

Thinx.sourceList()
.done( function( data ) {
console.log( "+++ updateSources " );
$scope.$emit( "updateSources", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );

Thinx.apikeyList()
.done( function( data ) {
console.log( "+++ updateApikeys " );
$scope.$emit( "updateApikeys", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );

Thinx.channelList()
.done( function( data ) {
console.log( "+++ updateChannels " );
$scope.$emit( "updateChannels", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
Expand Down Expand Up @@ -722,7 +719,6 @@ angular.module( "RTM" ).controller( "DeviceController", [ "$rootScope", "$scope"
// refresh latest firmware envelope
Thinx.getLatestFirmwareEnvelope( $scope.deviceForm.udid )
.done( function( data ) {
console.log( "+++ updateLatestFirmwareEnvelope " );
$scope.$emit( "updateLatestFirmwareEnvelope", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
Expand Down
10 changes: 6 additions & 4 deletions src/app/js/controllers/DevicesController.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ angular.module( "RTM" ).controller( "DevicesController", [ "$rootScope", "$scope

Thinx.sourceList()
.done( function( data ) {
console.log( "+++ updateSources " );
$scope.$emit( "updateSources", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );

Thinx.apikeyList()
.done( function( data ) {
console.log( "+++ updateApikeys " );
$scope.$emit( "updateApikeys", data );
} )
.fail( error => $scope.$emit( "xhrFailed", error ) );
Expand Down Expand Up @@ -114,8 +112,10 @@ angular.module( "RTM" ).controller( "DevicesController", [ "$rootScope", "$scope
}
}

// The build reply carries no status field (Phase 43 carry, D-09, UI-C19): fixed copy only,
// no reply value reaches toastr (it renders HTML).
toastr.info(
response.status + "<br><br>Click to show build log...",
( response.response === "queued" ? "Build queued." : "Build started." ) + "<br><br>Click to show build log...",
"THiNX Builder",
{
timeOut: 3000,
Expand All @@ -132,7 +132,9 @@ angular.module( "RTM" ).controller( "DevicesController", [ "$rootScope", "$scope
$scope.$apply();
} else {
console.log( response );
toastr.error( response.status, "<ENV::loginPageTitle>", { timeOut: 5000 } );
// A refused build replies { success: false, response: "<reason>" } with no status
// field: one fixed sentence, no reply value reaches toastr (48-REVIEW WR-04).
toastr.error( "Build failed.", "<ENV::loginPageTitle>", { timeOut: 5000 } );
}
} else {
console.log( "error" );
Expand Down
Loading