@managemint-solutions/sdk 0.49.0 → 0.50.0

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.
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@ export type { CreateFeatureRequestRow, CreatedFeatureRequest } from './feature-r
17
17
  export { CreateFeatureRequestDto } from './feature-requests';
18
18
  export { CreateConfigDto, UpdateConfigDto } from './configs';
19
19
  export { CreateSupportRequestDto } from './support';
20
- export { AddStatusDto, GetStatusesDto, StatusIdDto, UpdateStatusDto } from './statuses';
20
+ export { AddStatusDto, GetStatusesDto, ReorderStatusesDto, StatusIdDto, UpdateStatusDto } from './statuses';
21
21
  export { AddLabelDto, GetLabelsDto, LabelIdDto, UpdateLabelDto } from './labels';
22
22
  export { AddAdditionalDetailsDto, AdditionalDetailsIdDto, GetAdditionalDetailsDto, IsAdditionalDetailsValueByType, UpdateAdditionalDetailsDto, } from './additional-details';
23
23
  export { AddNoteDto, GetNotesDto, NoteIdDto } from './notes';
package/dist/index.js CHANGED
@@ -7,9 +7,9 @@
7
7
  // their classes are not exported: a consumer never constructs one, and every export is a contract
8
8
  // to keep. The row and input types they produce and accept are exported for annotations.
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.AddUserDto = exports.UpdatePermissionsDto = exports.PermissionsResource = exports.UpdateOrganizationDto = exports.CreateOrganizationDto = exports.NotificationIdDto = exports.GetNotificationsDto = exports.NoteIdDto = exports.GetNotesDto = exports.AddNoteDto = exports.UpdateAdditionalDetailsDto = exports.IsAdditionalDetailsValueByType = exports.GetAdditionalDetailsDto = exports.AdditionalDetailsIdDto = exports.AddAdditionalDetailsDto = exports.UpdateLabelDto = exports.LabelIdDto = exports.GetLabelsDto = exports.AddLabelDto = exports.UpdateStatusDto = exports.StatusIdDto = exports.GetStatusesDto = exports.AddStatusDto = exports.CreateSupportRequestDto = exports.UpdateConfigDto = exports.CreateConfigDto = exports.CreateFeatureRequestDto = exports.InvoiceIdDto = exports.GetInvoicesQueryDto = exports.ReinstateSubscriptionDto = exports.PurchaseModuleDto = exports.PaymentIdDto = exports.InitialPaymentDto = exports.GetPaymentsQueryDto = exports.CancelSubscriptionDto = exports.GetAuditTrailDto = exports.IsNullable = exports.EmptyToNull = exports.SupabaseClientError = exports.createSupabaseServiceClient = exports.SupabaseServiceClient = exports.SignInDto = exports.SendPasswordResetEmailDto = exports.ResetPasswordDto = exports.ExchangeTokenHashDto = exports.ExchangeRefreshTokenDto = exports.createSupabaseAuthClient = exports.SupabaseAuthClient = exports.createSupabaseClient = exports.SupabaseClient = void 0;
11
- exports.shiftDays = exports.proRataDays = exports.isWithinPeriod = exports.initialUntil = exports.cyclePeriodFor = exports.countWorkingDays = exports.completedMonths = exports.addMonths = exports.GetPublicHolidaysDto = exports.UpdateLeaveTypeDto = exports.UpdateLeaveRequestDto = exports.UpdateLeaveEntitlementDto = exports.ReviewLeaveRequestDto = exports.LeaveTypeIdDto = exports.LeaveRequestIdDto = exports.LeaveEntitlementIdDto = exports.GetLeaveTypesDto = exports.GetLeaveRequestsDto = exports.GetLeaveEntitlementsDto = exports.GetLeaveCalendarDto = exports.CreateLeaveTypeDto = exports.CreateLeaveRequestDto = exports.CreateLeaveEntitlementDto = exports.CreateLeaveAdjustmentDto = exports.BulkCreateLeaveEntitlementsDto = exports.UpdateTaskDto = exports.TaskLinkIdDto = exports.TaskIdDto = exports.GetTasksDto = exports.CreateTaskDto = exports.AddTaskLinkDto = exports.UpdateProjectDto = exports.ProjectIdDto = exports.GetProjectsDto = exports.CreateProjectDto = exports.UpdateLeadDto = exports.LeadIdDto = exports.GetLeadsDto = exports.CreateLeadDto = exports.ConvertLeadDto = exports.UpdateClientDto = exports.GetClientsDto = exports.CreateClientDto = exports.ClientIdDto = exports.SupportingFileIdDto = exports.GetSupportingFilesDto = exports.UserIdDto = exports.UpdateUserDto = exports.UpdateMyProfileDto = exports.GetUsersQueryDto = void 0;
12
- exports.monthlyTotalMinor = exports.weekStartOf = exports.minutesBetween = exports.UpdateTimesheetEntryDto = exports.TimesheetIdDto = exports.TimesheetEntryIdDto = exports.ReviewTimesheetDto = exports.GetTimesheetsDto = exports.GetTimesheetReportDto = exports.CreateTimesheetEntryDto = exports.todayInJohannesburg = void 0;
10
+ exports.UpdatePermissionsDto = exports.PermissionsResource = exports.UpdateOrganizationDto = exports.CreateOrganizationDto = exports.NotificationIdDto = exports.GetNotificationsDto = exports.NoteIdDto = exports.GetNotesDto = exports.AddNoteDto = exports.UpdateAdditionalDetailsDto = exports.IsAdditionalDetailsValueByType = exports.GetAdditionalDetailsDto = exports.AdditionalDetailsIdDto = exports.AddAdditionalDetailsDto = exports.UpdateLabelDto = exports.LabelIdDto = exports.GetLabelsDto = exports.AddLabelDto = exports.UpdateStatusDto = exports.StatusIdDto = exports.ReorderStatusesDto = exports.GetStatusesDto = exports.AddStatusDto = exports.CreateSupportRequestDto = exports.UpdateConfigDto = exports.CreateConfigDto = exports.CreateFeatureRequestDto = exports.InvoiceIdDto = exports.GetInvoicesQueryDto = exports.ReinstateSubscriptionDto = exports.PurchaseModuleDto = exports.PaymentIdDto = exports.InitialPaymentDto = exports.GetPaymentsQueryDto = exports.CancelSubscriptionDto = exports.GetAuditTrailDto = exports.IsNullable = exports.EmptyToNull = exports.SupabaseClientError = exports.createSupabaseServiceClient = exports.SupabaseServiceClient = exports.SignInDto = exports.SendPasswordResetEmailDto = exports.ResetPasswordDto = exports.ExchangeTokenHashDto = exports.ExchangeRefreshTokenDto = exports.createSupabaseAuthClient = exports.SupabaseAuthClient = exports.createSupabaseClient = exports.SupabaseClient = void 0;
11
+ exports.proRataDays = exports.isWithinPeriod = exports.initialUntil = exports.cyclePeriodFor = exports.countWorkingDays = exports.completedMonths = exports.addMonths = exports.GetPublicHolidaysDto = exports.UpdateLeaveTypeDto = exports.UpdateLeaveRequestDto = exports.UpdateLeaveEntitlementDto = exports.ReviewLeaveRequestDto = exports.LeaveTypeIdDto = exports.LeaveRequestIdDto = exports.LeaveEntitlementIdDto = exports.GetLeaveTypesDto = exports.GetLeaveRequestsDto = exports.GetLeaveEntitlementsDto = exports.GetLeaveCalendarDto = exports.CreateLeaveTypeDto = exports.CreateLeaveRequestDto = exports.CreateLeaveEntitlementDto = exports.CreateLeaveAdjustmentDto = exports.BulkCreateLeaveEntitlementsDto = exports.UpdateTaskDto = exports.TaskLinkIdDto = exports.TaskIdDto = exports.GetTasksDto = exports.CreateTaskDto = exports.AddTaskLinkDto = exports.UpdateProjectDto = exports.ProjectIdDto = exports.GetProjectsDto = exports.CreateProjectDto = exports.UpdateLeadDto = exports.LeadIdDto = exports.GetLeadsDto = exports.CreateLeadDto = exports.ConvertLeadDto = exports.UpdateClientDto = exports.GetClientsDto = exports.CreateClientDto = exports.ClientIdDto = exports.SupportingFileIdDto = exports.GetSupportingFilesDto = exports.UserIdDto = exports.UpdateUserDto = exports.UpdateMyProfileDto = exports.GetUsersQueryDto = exports.AddUserDto = void 0;
12
+ exports.monthlyTotalMinor = exports.weekStartOf = exports.minutesBetween = exports.UpdateTimesheetEntryDto = exports.TimesheetIdDto = exports.TimesheetEntryIdDto = exports.ReviewTimesheetDto = exports.GetTimesheetsDto = exports.GetTimesheetReportDto = exports.CreateTimesheetEntryDto = exports.todayInJohannesburg = exports.shiftDays = void 0;
13
13
  var client_1 = require("./client");
14
14
  Object.defineProperty(exports, "SupabaseClient", { enumerable: true, get: function () { return client_1.SupabaseClient; } });
15
15
  Object.defineProperty(exports, "createSupabaseClient", { enumerable: true, get: function () { return client_1.createSupabaseClient; } });
@@ -52,6 +52,7 @@ Object.defineProperty(exports, "CreateSupportRequestDto", { enumerable: true, ge
52
52
  var statuses_1 = require("./statuses");
53
53
  Object.defineProperty(exports, "AddStatusDto", { enumerable: true, get: function () { return statuses_1.AddStatusDto; } });
54
54
  Object.defineProperty(exports, "GetStatusesDto", { enumerable: true, get: function () { return statuses_1.GetStatusesDto; } });
55
+ Object.defineProperty(exports, "ReorderStatusesDto", { enumerable: true, get: function () { return statuses_1.ReorderStatusesDto; } });
55
56
  Object.defineProperty(exports, "StatusIdDto", { enumerable: true, get: function () { return statuses_1.StatusIdDto; } });
56
57
  Object.defineProperty(exports, "UpdateStatusDto", { enumerable: true, get: function () { return statuses_1.UpdateStatusDto; } });
57
58
  var labels_1 = require("./labels");
@@ -1,4 +1,4 @@
1
- import type { AddStatusDto as AddStatusDtoType, GetStatusesDto as GetStatusesDtoType, StatusIdDto as StatusIdDtoType, UpdateStatusDto as UpdateStatusDtoType } from '@managemint-solutions/entities/status/dto';
1
+ import type { AddStatusDto as AddStatusDtoType, GetStatusesDto as GetStatusesDtoType, ReorderStatusesDto as ReorderStatusesDtoType, StatusIdDto as StatusIdDtoType, UpdateStatusDto as UpdateStatusDtoType } from '@managemint-solutions/entities/status/dto';
2
2
  import { StatusEntityTypes } from '@managemint-solutions/entities/status/enum';
3
3
  export declare class StatusIdDto implements StatusIdDtoType {
4
4
  readonly statusId: string;
@@ -12,6 +12,9 @@ export declare class AddStatusDto implements AddStatusDtoType {
12
12
  readonly entity: StatusEntityTypes;
13
13
  readonly is_complete?: boolean;
14
14
  }
15
+ export declare class ReorderStatusesDto implements ReorderStatusesDtoType {
16
+ readonly status_ids: string[];
17
+ }
15
18
  export declare class UpdateStatusDto implements UpdateStatusDtoType {
16
19
  readonly label: string;
17
20
  readonly colour: string;
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.UpdateStatusDto = exports.AddStatusDto = exports.GetStatusesDto = exports.StatusIdDto = void 0;
12
+ exports.UpdateStatusDto = exports.ReorderStatusesDto = exports.AddStatusDto = exports.GetStatusesDto = exports.StatusIdDto = void 0;
13
13
  const class_validator_1 = require("class-validator");
14
14
  const enum_1 = require("@managemint-solutions/entities/status/enum");
15
15
  // class-validator versions of the shared DTO types from @managemint-solutions/entities.
@@ -62,6 +62,18 @@ __decorate([
62
62
  (0, class_validator_1.IsBoolean)({ message: 'is_complete must be true or false' }),
63
63
  __metadata("design:type", Boolean)
64
64
  ], AddStatusDto.prototype, "is_complete", void 0);
65
+ class ReorderStatusesDto {
66
+ // The whole catalogue of the entity type in its new order; the resource checks it is complete
67
+ // and has no repeats, which the decorators cannot (they do not know the organization).
68
+ status_ids;
69
+ }
70
+ exports.ReorderStatusesDto = ReorderStatusesDto;
71
+ __decorate([
72
+ (0, class_validator_1.IsArray)({ message: 'status_ids must be an array' }),
73
+ (0, class_validator_1.ArrayMinSize)(1, { message: 'status_ids cannot be empty' }),
74
+ (0, class_validator_1.IsUUID)('7', { each: true, message: 'Invalid status ID format' }),
75
+ __metadata("design:type", Array)
76
+ ], ReorderStatusesDto.prototype, "status_ids", void 0);
65
77
  class UpdateStatusDto {
66
78
  label;
67
79
  // Colour must be a valid hex code (e.g., #FFFFFF)
@@ -1,5 +1,5 @@
1
1
  import type { StatusEntity } from '@managemint-solutions/entities/status';
2
- import type { AddStatusDto, UpdateStatusDto } from '@managemint-solutions/entities/status/dto';
2
+ import type { AddStatusDto, ReorderStatusesDto, UpdateStatusDto } from '@managemint-solutions/entities/status/dto';
3
3
  import type { StatusEntityTypes } from '@managemint-solutions/entities/status/enum';
4
4
  import type { AuthContext } from '../auth';
5
5
  import { type AuditResource } from '../audit';
@@ -10,8 +10,17 @@ export declare class StatusesResource {
10
10
  private readonly auth;
11
11
  private readonly table;
12
12
  constructor(supabase: TypedSupabaseClient, auth: AuthContext, audit: AuditResource);
13
+ /** The catalogue in its order: `position` first, then insertion order for the seeded ties. */
13
14
  list(entity: StatusEntityTypes): Promise<StatusEntity[]>;
15
+ /** A new status goes last: one past the highest position its entity type has. */
14
16
  create(input: AddStatusDto): Promise<StatusEntity>;
17
+ /**
18
+ * Rewrites the whole catalogue's positions from the order given. The ids must be exactly the
19
+ * entity type's statuses, each once - a partial list would leave positions undefined, so it is
20
+ * refused with a 400 before anything is written. Only the rows that move are written (and
21
+ * audited); the answer is the catalogue in its new order.
22
+ */
23
+ reorder(entity: StatusEntityTypes, input: ReorderStatusesDto): Promise<StatusEntity[]>;
15
24
  update(statusId: string, input: UpdateStatusDto): Promise<StatusEntity>;
16
25
  /** The Won status cannot be deleted. Every other status can. */
17
26
  remove(statusId: string): Promise<void>;
@@ -23,7 +23,7 @@ const refuseWon = (message) => new errors_1.SupabaseClientError({ status: 400, e
23
23
  // The public contract is the shared StatusEntity from @managemint-solutions/entities; the
24
24
  // `as StatusEntity` casts declare the shape the select string below produces (the columns are
25
25
  // defined in the api's supabase/migrations).
26
- const STATUS_SELECT = 'mms_id, label, colour, is_complete, is_fail, is_triage, is_won';
26
+ const STATUS_SELECT = 'mms_id, label, colour, is_complete, is_fail, is_triage, is_won, position';
27
27
  // The audited write returns the whole row; the wire shape is the STATUS_SELECT columns.
28
28
  const toStatus = (row) => ({
29
29
  mms_id: row.mms_id,
@@ -33,6 +33,7 @@ const toStatus = (row) => ({
33
33
  is_fail: row.is_fail,
34
34
  is_triage: row.is_triage,
35
35
  is_won: row.is_won,
36
+ position: row.position,
36
37
  });
37
38
  class StatusesResource {
38
39
  supabase;
@@ -46,27 +47,75 @@ class StatusesResource {
46
47
  entityType: enum_1.AuditTrailEntityType.STATUS,
47
48
  });
48
49
  }
50
+ /** The catalogue in its order: `position` first, then insertion order for the seeded ties. */
49
51
  async list(entity) {
50
52
  const { data, error } = await this.supabase
51
53
  .from('statuses')
52
54
  .select(STATUS_SELECT)
53
55
  .eq('organization_id', this.auth.organization_id)
54
- .eq('entity_type', entity);
56
+ .eq('entity_type', entity)
57
+ .order('position')
58
+ .order('created_at')
59
+ .order('mms_id');
55
60
  if (error)
56
61
  throw (0, errors_1.mapPostgrestError)(error);
57
62
  return data;
58
63
  }
64
+ /** A new status goes last: one past the highest position its entity type has. */
59
65
  async create(input) {
66
+ const { data, error } = await this.supabase
67
+ .from('statuses')
68
+ .select('position')
69
+ .eq('organization_id', this.auth.organization_id)
70
+ .eq('entity_type', input.entity)
71
+ .order('position', { ascending: false })
72
+ .limit(1)
73
+ .maybeSingle();
74
+ if (error)
75
+ throw (0, errors_1.mapPostgrestError)(error);
76
+ const last = data?.position;
60
77
  const row = await this.table.insert({
61
78
  label: input.label,
62
79
  colour: input.colour,
63
80
  entity_type: input.entity,
64
81
  is_complete: input.is_complete ?? false,
82
+ position: last === undefined ? 0 : last + 1,
65
83
  organization_id: this.auth.organization_id,
66
84
  created_by: this.auth.mms_id,
67
85
  });
68
86
  return toStatus(row);
69
87
  }
88
+ /**
89
+ * Rewrites the whole catalogue's positions from the order given. The ids must be exactly the
90
+ * entity type's statuses, each once - a partial list would leave positions undefined, so it is
91
+ * refused with a 400 before anything is written. Only the rows that move are written (and
92
+ * audited); the answer is the catalogue in its new order.
93
+ */
94
+ async reorder(entity, input) {
95
+ const current = await this.list(entity);
96
+ const currentIds = new Set(current.map((status) => status.mms_id));
97
+ const given = new Set(input.status_ids);
98
+ if (given.size !== input.status_ids.length ||
99
+ given.size !== currentIds.size ||
100
+ input.status_ids.some((id) => !currentIds.has(id))) {
101
+ throw new errors_1.SupabaseClientError({
102
+ status: 400,
103
+ error: 'Database Error',
104
+ message: `status_ids must list every ${entity} status exactly once`,
105
+ });
106
+ }
107
+ const positionOf = new Map(current.map((status) => [status.mms_id, status.position]));
108
+ for (const [position, id] of input.status_ids.entries()) {
109
+ if (positionOf.get(id) === position)
110
+ continue;
111
+ await this.table.update(id, {
112
+ position,
113
+ updated_at: new Date().toISOString(),
114
+ last_updated_by: this.auth.mms_id,
115
+ });
116
+ }
117
+ return this.list(entity);
118
+ }
70
119
  async update(statusId, input) {
71
120
  if (await this.isWon(statusId)) {
72
121
  throw refuseWon('The Won status is fixed and cannot be changed');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@managemint-solutions/sdk",
3
- "version": "0.49.0",
3
+ "version": "0.50.0",
4
4
  "description": "Typed Supabase data-access SDK for ManageMint Solutions",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Scott Bebington <scottbebington@gmail.com>",
@@ -51,7 +51,7 @@
51
51
  "testEnvironment": "node"
52
52
  },
53
53
  "dependencies": {
54
- "@managemint-solutions/entities": "^1.32.0"
54
+ "@managemint-solutions/entities": "^1.33.0"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "@nestjs/common": "^11.0.0",