@pb33f/cowboy-components 0.7.7 → 0.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/components/auth/login-button.d.ts +4 -2
  2. package/dist/components/auth/login-button.js +25 -7
  3. package/dist/components/auth/login-panel.d.ts +1 -1
  4. package/dist/components/auth/login-panel.js +1 -1
  5. package/dist/components/auth/oauth-login.d.ts +1 -1
  6. package/dist/components/auth/oauth-login.js +3 -3
  7. package/dist/components/the-doctor/status-bar.js +3 -3
  8. package/dist/components/the-doctor/the-doctor.css.js +16 -0
  9. package/dist/components/the-doctor/the-doctor.d.ts +3 -0
  10. package/dist/components/the-doctor/the-doctor.js +50 -3
  11. package/dist/components/time-vortex/tardis-control.css.js +0 -16
  12. package/dist/components/workspaces/workspace-destroy-dialog.d.ts +17 -0
  13. package/dist/components/workspaces/workspace-destroy-dialog.js +85 -0
  14. package/dist/components/workspaces/workspace-form.d.ts +22 -0
  15. package/dist/components/workspaces/workspace-form.js +194 -0
  16. package/dist/components/workspaces/workspace-view.css.d.ts +2 -0
  17. package/dist/components/workspaces/workspace-view.css.js +40 -0
  18. package/dist/components/workspaces/workspace-view.d.ts +30 -0
  19. package/dist/components/workspaces/workspace-view.js +196 -0
  20. package/dist/controllers/auth-controller.d.ts +1 -0
  21. package/dist/controllers/auth-controller.js +26 -8
  22. package/dist/controllers/diagnostic-controller.d.ts +1 -0
  23. package/dist/controllers/diagnostic-controller.js +15 -10
  24. package/dist/controllers/docs-controller.js +9 -33
  25. package/dist/controllers/workspace-controller.d.ts +15 -0
  26. package/dist/controllers/workspace-controller.js +156 -0
  27. package/dist/cowboy-components.umd.cjs +1559 -1095
  28. package/dist/css/badges.css.d.ts +2 -0
  29. package/dist/css/badges.css.js +12 -0
  30. package/dist/css/button.css.js +1 -1
  31. package/dist/css/forms.css.js +127 -1
  32. package/dist/css/lists.css.js +8 -0
  33. package/dist/css/pb33f-theme.css +1 -0
  34. package/dist/css/spinner.css.js +29 -0
  35. package/dist/events/doctor.d.ts +15 -0
  36. package/dist/events/doctor.js +10 -0
  37. package/dist/model/form-types.d.ts +32 -0
  38. package/dist/model/form-types.js +19 -0
  39. package/dist/model/formable.d.ts +51 -0
  40. package/dist/model/formable.js +542 -0
  41. package/dist/model/workspace.d.ts +6 -0
  42. package/dist/model/workspace.js +1 -0
  43. package/dist/monacoeditorwork/yaml.worker..bundle.js +14801 -14800
  44. package/dist/services/workspace-service.d.ts +10 -0
  45. package/dist/services/workspace-service.js +132 -0
  46. package/dist/style.css +1 -1
  47. package/package.json +7 -2
@@ -0,0 +1,194 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { html } from "lit";
8
+ import { customElement, state, query, property } from "lit/decorators.js";
9
+ import { Formable } from "../../model/formable.js";
10
+ import { RenderType } from "../../model/form-types.js";
11
+ import { FormDirtyEvent, FormSubmitComplete, CreateWorkspace, UpdateWorkspace } from "../../events/doctor.js";
12
+ import dialogCss from "../../css/dialog.css.js";
13
+ let WorkspaceForm = class WorkspaceForm extends Formable {
14
+ constructor() {
15
+ super();
16
+ this.isEditMode = false;
17
+ this.open = false;
18
+ this.autoFocus = true; // Enable autofocus for workspace form
19
+ this.workspaceModel = {
20
+ name: '',
21
+ active: false
22
+ };
23
+ this.model = this.workspaceModel;
24
+ // Set up hints including hidden field for ID
25
+ this.setHints([
26
+ {
27
+ key: 'name',
28
+ renderType: RenderType.Text,
29
+ placeholder: 'workspace name',
30
+ helpText: 'Choose a unique name for your workspace',
31
+ required: true
32
+ },
33
+ {
34
+ key: 'workspaceId',
35
+ renderType: RenderType.Hidden
36
+ },
37
+ {
38
+ key: 'active',
39
+ renderType: RenderType.Ignored
40
+ },
41
+ {
42
+ key: 'default',
43
+ renderType: RenderType.Ignored
44
+ }
45
+ ]);
46
+ this.addEventListener(FormDirtyEvent, this.handleFormDirty.bind(this));
47
+ // Set up form submission callback for Enter key handling
48
+ this.onFormSubmit = this.handleSubmit.bind(this);
49
+ }
50
+ handleFormDirty(_) {
51
+ // do nothing
52
+ }
53
+ setEditMode(workspace) {
54
+ this.isEditMode = true;
55
+ this.wipeModel(workspace);
56
+ this.workspaceModel = { ...workspace };
57
+ this.model = this.workspaceModel;
58
+ }
59
+ setCreateMode() {
60
+ this.isEditMode = false;
61
+ this.wipeModel({
62
+ name: '',
63
+ active: false
64
+ });
65
+ }
66
+ close() {
67
+ this.setCreateMode();
68
+ this.open = false;
69
+ }
70
+ completed(ws) {
71
+ this.dispatchEvent(new CustomEvent(FormSubmitComplete, {
72
+ bubbles: true,
73
+ composed: true,
74
+ detail: ws
75
+ }));
76
+ this.close();
77
+ }
78
+ async handleSubmit() {
79
+ const formData = this.renderForm();
80
+ // Clear any previous errors
81
+ this.clearErrors();
82
+ this.clearTopError();
83
+ // Validation example
84
+ if (!formData.name || formData.name.trim() === '') {
85
+ // Show field-specific error
86
+ this.renderErrors([{
87
+ key: 'name',
88
+ message: 'A name is required'
89
+ }]);
90
+ return;
91
+ }
92
+ if (this.isEditMode) {
93
+ this.setLoading('Updating workspace...');
94
+ this.dispatchEvent(new CustomEvent(UpdateWorkspace, {
95
+ bubbles: true,
96
+ composed: true,
97
+ detail: formData
98
+ }));
99
+ }
100
+ else {
101
+ this.setLoading('Creating workspace...');
102
+ this.dispatchEvent(new CustomEvent(CreateWorkspace, {
103
+ bubbles: true,
104
+ composed: true,
105
+ detail: formData.name
106
+ }));
107
+ }
108
+ }
109
+ handleError(err) {
110
+ this.notLoading();
111
+ switch (err.status) {
112
+ case 400:
113
+ case 401:
114
+ this.setTopError({
115
+ key: 'server',
116
+ message: err.detail,
117
+ });
118
+ break;
119
+ case 402:
120
+ this.setTopError({
121
+ key: 'server',
122
+ message: "You don't have enough credit! A new workspace costs five credits.",
123
+ });
124
+ this.renderErrors([{
125
+ key: 'name',
126
+ message: 'More credit required.'
127
+ }]);
128
+ break;
129
+ case 403:
130
+ this.setTopError({
131
+ key: 'server',
132
+ message: err.detail,
133
+ });
134
+ this.renderErrors([{
135
+ key: 'name',
136
+ message: 'All maxed out, delete a workspace before creating new ones.'
137
+ }]);
138
+ break;
139
+ case 409:
140
+ this.setTopError({
141
+ key: 'server',
142
+ message: err.detail
143
+ });
144
+ this.renderErrors([{
145
+ key: 'name',
146
+ message: "There is a conflict",
147
+ }]);
148
+ break;
149
+ }
150
+ }
151
+ handleSuccess(workspace) {
152
+ this.notLoading();
153
+ this.completed(workspace);
154
+ }
155
+ render() {
156
+ const dialogLabel = this.isEditMode ? 'Edit workspace' : 'Create workspace';
157
+ const submitButtonText = this.isEditMode ? 'Update' : 'Create';
158
+ return html `
159
+ <sl-dialog .open=${this.open}
160
+ @sl-hide="${() => {
161
+ this.close();
162
+ }}"
163
+ label="${dialogLabel}">
164
+
165
+ ${this.renderModel()}
166
+
167
+ <section class="form-controls">
168
+ ${this.renderCancelButton(() => this.close())}
169
+ ${this.renderActionButton(submitButtonText, this.handleSubmit)}
170
+ </section>
171
+ </sl-dialog>
172
+ `;
173
+ }
174
+ };
175
+ WorkspaceForm.styles = [...Formable.styles, dialogCss];
176
+ __decorate([
177
+ query('sl-dialog')
178
+ ], WorkspaceForm.prototype, "workspaceDialog", void 0);
179
+ __decorate([
180
+ state()
181
+ ], WorkspaceForm.prototype, "active", void 0);
182
+ __decorate([
183
+ state()
184
+ ], WorkspaceForm.prototype, "open", void 0);
185
+ __decorate([
186
+ property({ type: Object })
187
+ ], WorkspaceForm.prototype, "workspaceModel", void 0);
188
+ __decorate([
189
+ state()
190
+ ], WorkspaceForm.prototype, "isEditMode", void 0);
191
+ WorkspaceForm = __decorate([
192
+ customElement("pb33f-doctor-workspace-form")
193
+ ], WorkspaceForm);
194
+ export { WorkspaceForm };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("lit").CSSResult;
2
+ export default _default;
@@ -0,0 +1,40 @@
1
+ import { css } from "lit";
2
+ export default css `
3
+
4
+ h2 {
5
+ margin-top: 10px;
6
+ }
7
+
8
+ .workspace-area {
9
+ padding-left: 20px;
10
+ padding-right: 20px;
11
+ }
12
+
13
+ p {
14
+ font-size: 0.8rem;
15
+ }
16
+
17
+ hr.main-break {
18
+ margin-top: 20px;
19
+ margin-bottom: 10px;
20
+ }
21
+
22
+ sl-icon-button.delete-workspace::part(base),sl-icon-button.edit-workspace::part(base) {
23
+ padding: 5px 10px 0 0;
24
+ display:none;
25
+ }
26
+
27
+ .active {
28
+ background-color: var(--primary-color-verylowalpha);
29
+ color: var(--font-color);
30
+ }
31
+
32
+ .active sl-icon-button.delete-workspace::part(base) {
33
+ display: inline-block;
34
+ }
35
+ .active sl-icon-button.edit-workspace::part(base) {
36
+ display: inline-block;
37
+ }
38
+
39
+
40
+ `;
@@ -0,0 +1,30 @@
1
+ import { TheDoctor } from "../the-doctor/the-doctor.js";
2
+ import { WorkspaceController } from "../../controllers/workspace-controller.js";
3
+ import { Workspace } from "../../model/workspace.js";
4
+ import { Formable } from "../../model/formable.js";
5
+ import { WorkspaceForm } from "./workspace-form.js";
6
+ import { WorkspaceDestroyView } from "./workspace-destroy-dialog.js";
7
+ import { PlatformError } from "../../model/errors.js";
8
+ export declare class WorkspacesView extends Formable {
9
+ static styles: import("lit").CSSResult[];
10
+ active: boolean;
11
+ mutateWorkspaceActive: boolean;
12
+ workspaces: Workspace[];
13
+ wsController: WorkspaceController;
14
+ workspaceForm: WorkspaceForm;
15
+ destroyDialog: WorkspaceDestroyView;
16
+ constructor(doc: TheDoctor, wsController: WorkspaceController);
17
+ private setupDestroyDialogEvents;
18
+ private setupWorkspaceFormEvents;
19
+ private handleWorkspaceFormComplete;
20
+ openCreateWorkspaceDialog(): void;
21
+ selectWorkspace(workspace: Workspace): void;
22
+ lightWorkspace(id: string | undefined): void;
23
+ dimWorkspace(id: string | undefined): void;
24
+ showDestroyDialog(w: Workspace): void;
25
+ showEditDialog(w: Workspace): void;
26
+ private handleDestroyCancel;
27
+ private handleDestroyConfirm;
28
+ deleteWorkspaceError(error: PlatformError): void;
29
+ render(): import("lit-html").TemplateResult<1>;
30
+ }
@@ -0,0 +1,196 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { html } from "lit";
8
+ import { customElement, state } from "lit/decorators.js";
9
+ import { Formable } from "../../model/formable.js";
10
+ import { WorkspaceForm } from "./workspace-form.js";
11
+ import { WorkspaceDestroyView } from "./workspace-destroy-dialog.js";
12
+ import { DeleteWorkspace, SwitchWorkspace, FormSubmitComplete, RefreshWorkspaces, CreateWorkspace, UpdateWorkspace } from "../../events/doctor.js";
13
+ import { AttentionType } from "../attention-box/attention-box.js";
14
+ import listsCss from "../../css/lists.css.js";
15
+ import workspaceViewCss from "./workspace-view.css.js";
16
+ import badgesCss from "../../css/badges.css.js";
17
+ import linksCss from "../../css/links.css.js";
18
+ import tooltipCss from "../../css/tooltip.css.js";
19
+ let WorkspacesView = class WorkspacesView extends Formable {
20
+ constructor(doc, wsController) {
21
+ super(doc);
22
+ this.doc = doc;
23
+ this.wsController = wsController;
24
+ this.active = false;
25
+ this.mutateWorkspaceActive = false;
26
+ this.workspaceForm = new WorkspaceForm();
27
+ this.destroyDialog = new WorkspaceDestroyView();
28
+ this.setupDestroyDialogEvents();
29
+ this.setupWorkspaceFormEvents();
30
+ }
31
+ setupDestroyDialogEvents() {
32
+ this.destroyDialog.addEventListener('cancel', () => this.handleDestroyCancel());
33
+ this.destroyDialog.addEventListener('destroy', (event) => this.handleDestroyConfirm(event));
34
+ }
35
+ setupWorkspaceFormEvents() {
36
+ this.workspaceForm.addEventListener(FormSubmitComplete, (event) => {
37
+ this.handleWorkspaceFormComplete(event);
38
+ });
39
+ this.workspaceForm.addEventListener(CreateWorkspace, (event) => {
40
+ this.wsController.dispatchEvent(new CustomEvent(CreateWorkspace, {
41
+ bubbles: true,
42
+ composed: true,
43
+ detail: event.detail
44
+ }));
45
+ });
46
+ this.workspaceForm.addEventListener(UpdateWorkspace, (event) => {
47
+ this.wsController.dispatchEvent(new CustomEvent(UpdateWorkspace, {
48
+ bubbles: true,
49
+ composed: true,
50
+ detail: event.detail
51
+ }));
52
+ });
53
+ }
54
+ handleWorkspaceFormComplete(_) {
55
+ // Refresh the workspace list after create/update
56
+ this.wsController.dispatchEvent(new CustomEvent(RefreshWorkspaces, {
57
+ bubbles: true,
58
+ composed: true
59
+ }));
60
+ }
61
+ openCreateWorkspaceDialog() {
62
+ this.workspaceForm.setCreateMode();
63
+ this.workspaceForm.open = true;
64
+ }
65
+ selectWorkspace(workspace) {
66
+ this.wsController.dispatchEvent(new CustomEvent(SwitchWorkspace, {
67
+ bubbles: true,
68
+ composed: true,
69
+ detail: workspace
70
+ }));
71
+ }
72
+ lightWorkspace(id) {
73
+ if (id) {
74
+ let li = this.shadowRoot?.querySelector('li#workspace-' + id);
75
+ if (li) {
76
+ li.classList.add('active');
77
+ }
78
+ }
79
+ }
80
+ dimWorkspace(id) {
81
+ if (id) {
82
+ let li = this.shadowRoot?.querySelector('li#workspace-' + id);
83
+ if (li) {
84
+ li.classList.remove('active');
85
+ }
86
+ }
87
+ }
88
+ showDestroyDialog(w) {
89
+ this.destroyDialog.workspace = w;
90
+ this.destroyDialog.show();
91
+ this.lightWorkspace(w.workspaceId);
92
+ }
93
+ showEditDialog(w) {
94
+ this.workspaceForm.setEditMode(w);
95
+ this.workspaceForm.open = true;
96
+ }
97
+ handleDestroyCancel() {
98
+ this.destroyDialog.hide().then(() => {
99
+ this.dimWorkspace(this.destroyDialog.workspace?.workspaceId);
100
+ });
101
+ }
102
+ handleDestroyConfirm(event) {
103
+ this.wsController.dispatchEvent(new CustomEvent(DeleteWorkspace, {
104
+ bubbles: true,
105
+ composed: true,
106
+ detail: event.detail
107
+ }));
108
+ this.destroyDialog.clearError();
109
+ }
110
+ deleteWorkspaceError(error) {
111
+ this.destroyDialog.setError(error);
112
+ }
113
+ render() {
114
+ if (!this.workspaces || this.workspaces.length === 0) {
115
+ return html ``;
116
+ }
117
+ return html `
118
+ <div class="workspace-area">
119
+ ${this.destroyDialog}
120
+
121
+ ${this.workspaceForm}
122
+
123
+ <h2>workspaces</h2>
124
+
125
+ <p>The best way to think of a workspace is like a project. Keep all your stuff in one place, and
126
+ switch between workspaces when you need to flip to a different spec or project.</p>
127
+
128
+ ${this.workspaces.length >= 5 ? html `
129
+ <sl-tooltip content="maximum limit reached, cannot create any more">
130
+ <sl-button disabled>
131
+ Add workspace
132
+ </sl-button>
133
+ </sl-tooltip>
134
+ ` : html `
135
+ <sl-button @click="${() => {
136
+ this.openCreateWorkspaceDialog();
137
+ }}">
138
+ Add workspace
139
+ </sl-button>
140
+ `}
141
+
142
+ ${this.workspaces.length >= 5 ? html `
143
+ <pb33f-attention-box type="${AttentionType.Info}"
144
+ headerText="maximum workspace count reached">
145
+ In order to create more workspaces, you will need to upgrade to pro (coming soon).
146
+ </pb33f-attention-box>
147
+ ` : ''}
148
+
149
+ <hr class="main-break"/>
150
+ <ul>
151
+
152
+ ${this.workspaces.map((w) => {
153
+ // Determine workspace content based on active status
154
+ const workspaceContent = w.active
155
+ ? html `<strong>${w.name}</strong> &nbsp;<sl-badge pulse>active</sl-badge>`
156
+ : html `<a href="#" class="workspace-link" @click=${() => this.selectWorkspace(w)}>${w.name}</a>`;
157
+ // Determine CSS classes and styling
158
+ const liClasses = w.active ? 'secondary' : '';
159
+ const liStyles = w.active ? 'color: var(--secondary-color)' : '';
160
+ return html `
161
+ <li id="workspace-${w.workspaceId}"
162
+ class="${liClasses}"
163
+ style="${liStyles}"
164
+ @mouseover="${() => this.lightWorkspace(w.workspaceId)}"
165
+ @mouseout="${() => this.dimWorkspace(w.workspaceId)}">
166
+
167
+ ${workspaceContent}
168
+
169
+ <div style="display: inline-block; float: right">
170
+ <sl-icon-button class="edit-workspace" name="pencil-square"
171
+ @click="${() => { this.showEditDialog(w); }}"></sl-icon-button>
172
+ ${!w.default && !w.active ? html `
173
+ <sl-icon-button class="delete-workspace" name="trash3"
174
+ @click="${() => { this.showDestroyDialog(w); }}"></sl-icon-button>
175
+ ` : ''}
176
+ </div>
177
+ </li>
178
+ `;
179
+ })}
180
+ </ul>
181
+ </div>
182
+
183
+ `;
184
+ }
185
+ };
186
+ WorkspacesView.styles = [...Formable.styles, workspaceViewCss, badgesCss, linksCss, listsCss, tooltipCss];
187
+ __decorate([
188
+ state()
189
+ ], WorkspacesView.prototype, "active", void 0);
190
+ __decorate([
191
+ state()
192
+ ], WorkspacesView.prototype, "mutateWorkspaceActive", void 0);
193
+ WorkspacesView = __decorate([
194
+ customElement("pb33f-doctor-workspaces")
195
+ ], WorkspacesView);
196
+ export { WorkspacesView };
@@ -14,6 +14,7 @@ export declare class AuthController extends EventTarget {
14
14
  brokerStarted: boolean;
15
15
  hosts: any[];
16
16
  callbackIdx: number;
17
+ checkingState: boolean;
17
18
  constructor(host: any, sessionCallback?: Function, autoStart?: boolean);
18
19
  start(): void;
19
20
  private startSession;
@@ -1,6 +1,6 @@
1
1
  import { AuthenticationGithubRequested, AuthenticationStateChange, CreditEmpty, LogoutRequested, NukeWorkspaceEvent, StartSessionFailed } from "../events/doctor.js";
2
2
  import { AuthService } from "../services/auth-service.js";
3
- import { HeaderService } from "../services/header-service";
3
+ import { HeaderService } from "../services/header-service.js";
4
4
  export class AuthController extends EventTarget {
5
5
  static getInstance() {
6
6
  const t = AuthController._instance;
@@ -20,9 +20,10 @@ export class AuthController extends EventTarget {
20
20
  }
21
21
  t.startSessionAutomatically = autoStart;
22
22
  t.brokerStarted = false;
23
- t.start();
23
+ // t.start()
24
24
  return t;
25
25
  }
26
+ this.checkingState = false;
26
27
  this.doctorEndpoint = 'https://doctor.pb33f.io';
27
28
  const sessionEndpoint = sessionStorage.getItem("doctor-endpoint");
28
29
  if (sessionEndpoint) {
@@ -138,7 +139,6 @@ export class AuthController extends EventTarget {
138
139
  }
139
140
  logout() {
140
141
  AuthService.logout().then(() => {
141
- //if (e.detail.redirectURL != '') {
142
142
  this.dispatchEvent(new CustomEvent(NukeWorkspaceEvent, {
143
143
  bubbles: true,
144
144
  composed: true,
@@ -146,20 +146,38 @@ export class AuthController extends EventTarget {
146
146
  resetFiles: true
147
147
  }
148
148
  }));
149
- // }
150
149
  });
151
150
  }
152
151
  notifyStateChange(state) {
152
+ this.checkingState = false;
153
153
  const event = new CustomEvent(AuthenticationStateChange, {
154
154
  detail: { state }
155
155
  });
156
156
  this.dispatchEvent(event);
157
157
  }
158
158
  async checkState() {
159
- return AuthService.checkAuth().then(state => {
160
- this.notifyStateChange(state);
161
- return state;
162
- });
159
+ if (!this.checkingState) {
160
+ this.checkingState = true;
161
+ return AuthService.checkAuth()
162
+ .then(state => {
163
+ this.state = state;
164
+ this.authenticated = true;
165
+ this.notifyStateChange(state);
166
+ return state;
167
+ })
168
+ .catch(error => {
169
+ this.notifyStateChange();
170
+ this.checkingState = false;
171
+ throw error;
172
+ });
173
+ }
174
+ else {
175
+ return new Promise((resolve) => {
176
+ this.addEventListener(AuthenticationStateChange, ((event) => {
177
+ resolve(event.detail.state);
178
+ }), { once: true });
179
+ });
180
+ }
163
181
  }
164
182
  }
165
183
  AuthController._instance = null;
@@ -1,6 +1,7 @@
1
1
  import { TheDoctor } from "../components/the-doctor/the-doctor.js";
2
2
  export declare class DiagnosticController extends EventTarget {
3
3
  doc: TheDoctor;
4
+ oldScore: number;
4
5
  constructor(doc: TheDoctor);
5
6
  lintSpec(value: string, url?: string): void;
6
7
  }
@@ -6,8 +6,13 @@ export class DiagnosticController extends EventTarget {
6
6
  constructor(doc) {
7
7
  super();
8
8
  this.doc = doc;
9
+ this.oldScore = 0;
9
10
  }
10
11
  lintSpec(value, url) {
12
+ // capture old score before any operations
13
+ if (this.doc.problemsOverview.statistics?.statistics.overallScore > 0) {
14
+ this.oldScore = this.doc.problemsOverview.statistics.statistics.overallScore;
15
+ }
11
16
  this.doc.activitySpinner.show();
12
17
  this.doc.editor.breadcumb.isInvalid = false;
13
18
  if (url) {
@@ -177,10 +182,6 @@ export class DiagnosticController extends EventTarget {
177
182
  }
178
183
  // update the overview statistics
179
184
  LintingService.fetchStatistics().then((result) => {
180
- let oldScore = 0;
181
- if (this.doc.problemsOverview.statistics) {
182
- oldScore = this.doc.problemsOverview.statistics.statistics.overallScore;
183
- }
184
185
  this.doc.diagnosticBag?.set(DiagnosticBag, result);
185
186
  this.doc.activitySpinner.hide();
186
187
  if (result?.remainingCredit <= 10) {
@@ -196,20 +197,20 @@ export class DiagnosticController extends EventTarget {
196
197
  if (!settings?.autoDiagnose) {
197
198
  if (this.doc.problemsOverview.statistics) {
198
199
  const newScore = result.statistics.overallScore;
199
- if (oldScore > newScore) {
200
+ if (this.oldScore > newScore) {
200
201
  this.doc.sendToast({
201
202
  id: crypto.randomUUID(),
202
203
  type: ToastType.SCOREDOWN,
203
204
  body: "Your score has decreased. It is now " + newScore + "%",
204
- title: "Score went down by " + (oldScore - newScore) + "%"
205
+ title: "Score went down by " + (this.oldScore - newScore) + "%"
205
206
  });
206
207
  }
207
- if (oldScore < newScore) {
208
+ if (this.oldScore < newScore) {
208
209
  this.doc.sendToast({
209
210
  id: crypto.randomUUID(),
210
211
  type: ToastType.SCOREUP,
211
212
  body: "Your score has increased to " + newScore + "%",
212
- title: "Score went up by " + (newScore - oldScore) + "%"
213
+ title: "Score went up by " + (newScore - this.oldScore) + "%"
213
214
  });
214
215
  }
215
216
  }
@@ -237,11 +238,15 @@ export class DiagnosticController extends EventTarget {
237
238
  if (e.instance === 'https://pb33f.io/errors/no-credit-remaining') {
238
239
  this.doc.statusBar.callsRemaining = 0;
239
240
  this.doc.statusBar.visible = true;
241
+ let text = "Run out of credit, please authenticate for more or wait 24 hours.";
242
+ if (this.doc.authController.authenticated) {
243
+ text = "Run out of credit, please purchase more, or come back tomorrow for more free credits.";
244
+ }
240
245
  this.doc.sendToast({
241
246
  id: crypto.randomUUID(),
242
247
  type: ToastType.ERROR,
243
- body: "Run out of credit, please authenticate for more or wait 24 hours.",
244
- title: "Credit exhausted!",
248
+ body: text,
249
+ title: "💰 Credit Exhausted!",
245
250
  });
246
251
  }
247
252
  else {