@overmap-ai/core 1.0.22 → 1.0.23-organization-management.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.
@@ -617,15 +617,15 @@ const wrapMigration = (migrator) => (state) => {
617
617
  };
618
618
  const migrations = [initialVersioning, signOut, signOut, createOutboxState];
619
619
  const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
620
- const initialState$k = {
620
+ const initialState$l = {
621
621
  accessToken: "",
622
622
  refreshToken: "",
623
623
  isLoggedIn: false
624
624
  };
625
625
  const authSlice = createSlice({
626
626
  name: "auth",
627
- initialState: initialState$k,
628
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
627
+ initialState: initialState$l,
628
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
629
629
  reducers: {
630
630
  setTokens: (state, action) => {
631
631
  state.accessToken = action.payload.accessToken;
@@ -1328,7 +1328,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
1328
1328
  return getLocalDateString(date);
1329
1329
  return relative.format(days, "days");
1330
1330
  });
1331
- const initialState$j = {
1331
+ const initialState$k = {
1332
1332
  categories: {},
1333
1333
  usedCategoryColors: [],
1334
1334
  categoryVisibility: {
@@ -1338,8 +1338,8 @@ const initialState$j = {
1338
1338
  };
1339
1339
  const categorySlice = createSlice({
1340
1340
  name: "categories",
1341
- initialState: initialState$j,
1342
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1341
+ initialState: initialState$k,
1342
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1343
1343
  reducers: {
1344
1344
  setCategories: (state, action) => {
1345
1345
  if (!Array.isArray(action.payload))
@@ -1472,13 +1472,13 @@ const selectHiddenCategoryCount = (state) => {
1472
1472
  return hiddenCategoryCount;
1473
1473
  };
1474
1474
  const categoryReducer = categorySlice.reducer;
1475
- const initialState$i = {
1475
+ const initialState$j = {
1476
1476
  components: {}
1477
1477
  };
1478
1478
  const componentSlice = createSlice({
1479
1479
  name: "components",
1480
- initialState: initialState$i,
1481
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1480
+ initialState: initialState$j,
1481
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1482
1482
  reducers: {
1483
1483
  addComponent: (state, action) => {
1484
1484
  state.components[action.payload.offline_id] = action.payload;
@@ -1590,13 +1590,13 @@ const {
1590
1590
  removeAllComponentsOfType
1591
1591
  } = componentSlice.actions;
1592
1592
  const componentReducer = componentSlice.reducer;
1593
- const initialState$h = {
1593
+ const initialState$i = {
1594
1594
  completionsByComponentId: {}
1595
1595
  };
1596
1596
  const componentStageCompletionSlice = createSlice({
1597
1597
  name: "componentStageCompletions",
1598
- initialState: initialState$h,
1599
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
1598
+ initialState: initialState$i,
1599
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1600
1600
  reducers: {
1601
1601
  addStageCompletion: (state, action) => {
1602
1602
  let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
@@ -1647,13 +1647,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
1647
1647
  return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
1648
1648
  };
1649
1649
  const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
1650
- const initialState$g = {
1650
+ const initialState$h = {
1651
1651
  stages: {}
1652
1652
  };
1653
1653
  const componentStageSlice = createSlice({
1654
1654
  name: "componentStages",
1655
- initialState: initialState$g,
1656
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
1655
+ initialState: initialState$h,
1656
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
1657
1657
  reducers: {
1658
1658
  addStages: (state, action) => {
1659
1659
  Object.assign(state.stages, toOfflineIdRecord(action.payload));
@@ -1713,14 +1713,14 @@ const selectStagesFromStageIds = restructureCreateSelectorWithArgs(
1713
1713
  );
1714
1714
  const { addStages, updateStages, removeStages } = componentStageSlice.actions;
1715
1715
  const componentStageReducer = componentStageSlice.reducer;
1716
- const initialState$f = {
1716
+ const initialState$g = {
1717
1717
  componentTypes: {},
1718
1718
  hiddenComponentTypeIds: {}
1719
1719
  };
1720
1720
  const componentTypeSlice = createSlice({
1721
1721
  name: "componentTypes",
1722
- initialState: initialState$f,
1723
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
1722
+ initialState: initialState$g,
1723
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
1724
1724
  reducers: {
1725
1725
  addComponentType: (state, action) => {
1726
1726
  state.componentTypes[action.payload.offline_id] = action.payload;
@@ -1779,13 +1779,13 @@ const selectComponentTypesByName = restructureCreateSelectorWithArgs(
1779
1779
  const selectHiddenComponentTypeIds = (state) => state.componentTypeReducer.hiddenComponentTypeIds;
1780
1780
  const { addComponentType, setComponentTypes, toggleComponentTypeVisibility, deleteComponentType } = componentTypeSlice.actions;
1781
1781
  const componentTypeReducer = componentTypeSlice.reducer;
1782
- const initialState$e = {
1782
+ const initialState$f = {
1783
1783
  workspaces: {},
1784
1784
  activeWorkspaceId: null
1785
1785
  };
1786
1786
  const workspaceSlice = createSlice({
1787
1787
  name: "workspace",
1788
- initialState: initialState$e,
1788
+ initialState: initialState$f,
1789
1789
  // The `reducers` field lets us define reducers and generate associated actions
1790
1790
  reducers: {
1791
1791
  setWorkspaces: (state, action) => {
@@ -1842,7 +1842,7 @@ const selectPermittedWorkspaceIds = createSelector(
1842
1842
  );
1843
1843
  const workspaceReducer = workspaceSlice.reducer;
1844
1844
  const maxRecentIssues = 10;
1845
- const initialState$d = {
1845
+ const initialState$e = {
1846
1846
  issues: {},
1847
1847
  attachments: {},
1848
1848
  comments: {},
@@ -1854,9 +1854,9 @@ const initialState$d = {
1854
1854
  };
1855
1855
  const issueSlice = createSlice({
1856
1856
  name: "issues",
1857
- initialState: initialState$d,
1857
+ initialState: initialState$e,
1858
1858
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
1859
- Object.assign(state, initialState$d);
1859
+ Object.assign(state, initialState$e);
1860
1860
  }),
1861
1861
  reducers: {
1862
1862
  setIssues: (state, action) => {
@@ -2187,15 +2187,15 @@ const selectRecentIssuesAsSearchResults = createSelector(
2187
2187
  }
2188
2188
  );
2189
2189
  const issueReducer = issueSlice.reducer;
2190
- const initialState$c = {
2190
+ const initialState$d = {
2191
2191
  s3Urls: {}
2192
2192
  };
2193
2193
  const msPerHour = 1e3 * 60 * 60;
2194
2194
  const msPerWeek = msPerHour * 24 * 7;
2195
2195
  const fileSlice = createSlice({
2196
2196
  name: "file",
2197
- initialState: initialState$c,
2198
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2197
+ initialState: initialState$d,
2198
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2199
2199
  reducers: {
2200
2200
  setUploadUrl: (state, action) => {
2201
2201
  const { url, fields, sha1 } = action.payload;
@@ -2222,7 +2222,7 @@ const selectUploadUrl = (sha1) => (state) => {
2222
2222
  return url;
2223
2223
  };
2224
2224
  const fileReducer = fileSlice.reducer;
2225
- const initialState$b = {
2225
+ const initialState$c = {
2226
2226
  // TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
2227
2227
  mapStyle: MapStyle.SATELLITE,
2228
2228
  showTooltips: false,
@@ -2230,8 +2230,8 @@ const initialState$b = {
2230
2230
  };
2231
2231
  const mapSlice = createSlice({
2232
2232
  name: "map",
2233
- initialState: initialState$b,
2234
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2233
+ initialState: initialState$c,
2234
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2235
2235
  reducers: {
2236
2236
  setMapStyle: (state, action) => {
2237
2237
  state.mapStyle = action.payload;
@@ -2249,109 +2249,113 @@ const selectMapStyle = (state) => state.mapReducer.mapStyle;
2249
2249
  const selectShowTooltips = (state) => state.mapReducer.showTooltips;
2250
2250
  const selectCenterMapToProject = (state) => state.mapReducer.centerMapToProject;
2251
2251
  const mapReducer = mapSlice.reducer;
2252
- const initialState$a = {
2253
- organizations: {},
2254
- activeOrganizationId: null
2252
+ const initialState$b = {
2253
+ organizationAccesses: {},
2254
+ activeOrganizationAccessId: null
2255
2255
  };
2256
- const organizationSlice = createSlice({
2257
- name: "organizations",
2258
- initialState: initialState$a,
2259
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2256
+ const organizationAccessSlice = createSlice({
2257
+ name: "organizationAccess",
2258
+ initialState: initialState$b,
2259
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2260
2260
  reducers: {
2261
- setOrganizations: (state, action) => {
2262
- for (const org of action.payload) {
2263
- state.organizations[org.id] = org;
2261
+ setOrganizationAccesses: (state, action) => {
2262
+ if (!Array.isArray(action.payload))
2263
+ throw new Error("Expected an array of OrganizationAccess");
2264
+ if (action.payload.filter(onlyUniqueOfflineIds).length !== action.payload.length) {
2265
+ throw new Error("Tried to use setOrganizationAccesses reducer with duplicate ID's");
2264
2266
  }
2267
+ const organizationAccesses = {};
2268
+ for (const organizationAccess of action.payload) {
2269
+ organizationAccesses[organizationAccess.offline_id] = organizationAccess;
2270
+ }
2271
+ state.organizationAccesses = organizationAccesses;
2265
2272
  },
2266
- setActiveOrganizationId: (state, action) => {
2267
- state.activeOrganizationId = action.payload;
2273
+ updateOrganizationAccess: (state, action) => {
2274
+ if (action.payload.offline_id in state.organizationAccesses) {
2275
+ state.organizationAccesses[action.payload.offline_id] = action.payload;
2276
+ } else {
2277
+ throw new Error(
2278
+ `Tried to update organization access with ID that doesn't exist: ${action.payload.offline_id}`
2279
+ );
2280
+ }
2281
+ },
2282
+ removeOrganizationAccess: (state, action) => {
2283
+ if (action.payload.offline_id in state.organizationAccesses) {
2284
+ delete state.organizationAccesses[action.payload.offline_id];
2285
+ } else {
2286
+ throw new Error(
2287
+ `Tried to remove organization access with ID that doesn't exist: ${action.payload.offline_id}`
2288
+ );
2289
+ }
2290
+ },
2291
+ setActiveOrganizationAccessId: (state, action) => {
2292
+ state.activeOrganizationAccessId = action.payload;
2268
2293
  }
2269
2294
  }
2270
2295
  });
2271
- const { setOrganizations, setActiveOrganizationId } = organizationSlice.actions;
2272
- const selectActiveOrganizationId = (state) => {
2273
- return state.organizationReducer.activeOrganizationId;
2296
+ const {
2297
+ setOrganizationAccesses,
2298
+ updateOrganizationAccess,
2299
+ removeOrganizationAccess,
2300
+ setActiveOrganizationAccessId
2301
+ } = organizationAccessSlice.actions;
2302
+ const selectOrganizationAccesses = (state) => {
2303
+ return state.organizationAccessReducer.organizationAccesses;
2274
2304
  };
2275
- const selectOrganizations = (state) => {
2276
- return Object.values(state.organizationReducer.organizations);
2305
+ const selectOrganizationAccess = (organizationAccessId) => (state) => {
2306
+ return state.organizationAccessReducer.organizationAccesses[organizationAccessId];
2277
2307
  };
2278
- const selectActiveOrganization = (state) => {
2279
- const id = selectActiveOrganizationId(state);
2280
- if (!id) {
2281
- return null;
2282
- }
2283
- const organization = state.organizationReducer.organizations[id];
2284
- if (!organization) {
2308
+ const selectActiveOrganizationAccess = (state) => {
2309
+ const activeOrganizationAccessId = state.organizationAccessReducer.activeOrganizationAccessId;
2310
+ if (!activeOrganizationAccessId) {
2285
2311
  return null;
2286
2312
  }
2287
- return organization;
2288
- };
2289
- const selectOrganization = (id) => (state) => {
2290
- return state.organizationReducer.organizations[id];
2313
+ return state.organizationAccessReducer.organizationAccesses[activeOrganizationAccessId] ?? null;
2291
2314
  };
2292
- const organizationReducer = organizationSlice.reducer;
2293
- const createOfflineAction = (request2, baseUrl) => {
2294
- const requestWithUuid = request2.uuid ? request2 : { ...request2, uuid: v4() };
2295
- return {
2296
- payload: requestWithUuid,
2297
- type: "",
2298
- meta: {
2299
- offline: {
2300
- effect: {
2301
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2302
- request: requestWithUuid,
2303
- BASE_URL: baseUrl
2304
- }
2305
- }
2306
- }
2307
- };
2315
+ const selectOrganizationAccessForUser = (user) => (state) => {
2316
+ return Object.values(state.organizationAccessReducer.organizationAccesses).find(
2317
+ (organizationAccess) => organizationAccess.user === user.id
2318
+ );
2308
2319
  };
2309
- const initialState$9 = {
2310
- deletedRequests: [],
2311
- latestRetryTime: 0
2320
+ const selectOrganizationAccessUserMapping = (state) => {
2321
+ const organizationAccesses = {};
2322
+ Object.values(state.organizationAccessReducer.organizationAccesses).forEach((organizationAccess) => {
2323
+ organizationAccesses[organizationAccess.user] = organizationAccess;
2324
+ });
2325
+ return organizationAccesses;
2312
2326
  };
2313
- const outboxSlice = createSlice({
2314
- name: "outbox",
2315
- initialState: initialState$9,
2316
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
2317
- reducers: {
2318
- // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
2319
- // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
2320
- // Then this reducer enqueueRequest() is responsible for adding the actual request data to the outbox
2321
- enqueueRequest: {
2322
- reducer: (state, _action) => {
2323
- return state;
2324
- },
2325
- prepare: (payload) => {
2326
- console.debug("Preparing to enqueue request", payload);
2327
- const { BASE_URL, ...rest } = payload;
2328
- return createOfflineAction(rest, BASE_URL);
2329
- }
2330
- },
2331
- markForDeletion(state, action) {
2332
- state.deletedRequests.push(action.payload);
2333
- },
2334
- markAsDeleted(state, action) {
2335
- const index = state.deletedRequests.indexOf(action.payload);
2336
- if (index !== -1)
2337
- state.deletedRequests.splice(index, 1);
2338
- },
2339
- _setLatestRetryTime: (state, action) => {
2340
- state.latestRetryTime = action.payload;
2341
- }
2342
- }
2343
- });
2344
- const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
2345
- const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
2346
- const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
2347
- const outboxReducer = outboxSlice.reducer;
2348
- const initialState$8 = {
2327
+ const organizationAccessReducer = organizationAccessSlice.reducer;
2328
+ var ProjectAccessLevel = /* @__PURE__ */ ((ProjectAccessLevel2) => {
2329
+ ProjectAccessLevel2[ProjectAccessLevel2["BASIC"] = 0] = "BASIC";
2330
+ ProjectAccessLevel2[ProjectAccessLevel2["ADMIN"] = 2] = "ADMIN";
2331
+ return ProjectAccessLevel2;
2332
+ })(ProjectAccessLevel || {});
2333
+ var OrganizationAccessLevel = /* @__PURE__ */ ((OrganizationAccessLevel2) => {
2334
+ OrganizationAccessLevel2[OrganizationAccessLevel2["BASIC"] = 0] = "BASIC";
2335
+ OrganizationAccessLevel2[OrganizationAccessLevel2["ADMIN"] = 2] = "ADMIN";
2336
+ return OrganizationAccessLevel2;
2337
+ })(OrganizationAccessLevel || {});
2338
+ var ProjectType = /* @__PURE__ */ ((ProjectType2) => {
2339
+ ProjectType2[ProjectType2["PERSONAL"] = 0] = "PERSONAL";
2340
+ ProjectType2[ProjectType2["ORGANIZATION"] = 2] = "ORGANIZATION";
2341
+ return ProjectType2;
2342
+ })(ProjectType || {});
2343
+ var VerificationCodeType = /* @__PURE__ */ ((VerificationCodeType2) => {
2344
+ VerificationCodeType2[VerificationCodeType2["USER_REGISTRATION"] = 0] = "USER_REGISTRATION";
2345
+ VerificationCodeType2[VerificationCodeType2["APPLICATION_INVITE"] = 2] = "APPLICATION_INVITE";
2346
+ VerificationCodeType2[VerificationCodeType2["PROJECT_INVITE"] = 4] = "PROJECT_INVITE";
2347
+ VerificationCodeType2[VerificationCodeType2["ORGANIZATION_INVITE"] = 6] = "ORGANIZATION_INVITE";
2348
+ VerificationCodeType2[VerificationCodeType2["ADD_EMAIL_DOMAIN"] = 8] = "ADD_EMAIL_DOMAIN";
2349
+ VerificationCodeType2[VerificationCodeType2["RESET_PASSWORD"] = 10] = "RESET_PASSWORD";
2350
+ return VerificationCodeType2;
2351
+ })(VerificationCodeType || {});
2352
+ const initialState$a = {
2349
2353
  projectAccesses: {}
2350
2354
  };
2351
2355
  const projectAccessSlice = createSlice({
2352
2356
  name: "projectAccess",
2353
- initialState: initialState$8,
2354
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
2357
+ initialState: initialState$a,
2358
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2355
2359
  reducers: {
2356
2360
  setProjectAccesses: (state, action) => {
2357
2361
  if (!Array.isArray(action.payload))
@@ -2419,31 +2423,240 @@ const selectProjectAccessUserMapping = (state) => {
2419
2423
  return projectAccesses;
2420
2424
  };
2421
2425
  const projectAccessReducer = projectAccessSlice.reducer;
2422
- var ProjectAccessLevel = /* @__PURE__ */ ((ProjectAccessLevel2) => {
2423
- ProjectAccessLevel2[ProjectAccessLevel2["BASIC"] = 0] = "BASIC";
2424
- ProjectAccessLevel2[ProjectAccessLevel2["ADMIN"] = 2] = "ADMIN";
2425
- return ProjectAccessLevel2;
2426
- })(ProjectAccessLevel || {});
2427
- var OrganizationAccessLevel = /* @__PURE__ */ ((OrganizationAccessLevel2) => {
2428
- OrganizationAccessLevel2[OrganizationAccessLevel2["BASIC"] = 0] = "BASIC";
2429
- OrganizationAccessLevel2[OrganizationAccessLevel2["ADMIN"] = 2] = "ADMIN";
2430
- return OrganizationAccessLevel2;
2431
- })(OrganizationAccessLevel || {});
2432
- var ProjectType = /* @__PURE__ */ ((ProjectType2) => {
2433
- ProjectType2[ProjectType2["PERSONAL"] = 0] = "PERSONAL";
2434
- ProjectType2[ProjectType2["ORGANIZATION"] = 2] = "ORGANIZATION";
2435
- return ProjectType2;
2436
- })(ProjectType || {});
2437
- var VerificationCodeType = /* @__PURE__ */ ((VerificationCodeType2) => {
2438
- VerificationCodeType2[VerificationCodeType2["USER_REGISTRATION"] = 0] = "USER_REGISTRATION";
2439
- VerificationCodeType2[VerificationCodeType2["APPLICATION_INVITE"] = 2] = "APPLICATION_INVITE";
2440
- VerificationCodeType2[VerificationCodeType2["PROJECT_INVITE"] = 4] = "PROJECT_INVITE";
2441
- VerificationCodeType2[VerificationCodeType2["ORGANIZATION_INVITE"] = 6] = "ORGANIZATION_INVITE";
2442
- VerificationCodeType2[VerificationCodeType2["ADD_EMAIL_DOMAIN"] = 8] = "ADD_EMAIL_DOMAIN";
2443
- VerificationCodeType2[VerificationCodeType2["RESET_PASSWORD"] = 10] = "RESET_PASSWORD";
2444
- return VerificationCodeType2;
2445
- })(VerificationCodeType || {});
2426
+ const initialState$9 = {
2427
+ users: {},
2428
+ currentUser: {
2429
+ id: 0,
2430
+ username: "",
2431
+ email: "",
2432
+ profile: { file: null, file_sha1: null, favourite_project_ids: [], tour_step: -1 }
2433
+ }
2434
+ };
2435
+ const userSlice = createSlice({
2436
+ name: "users",
2437
+ initialState: initialState$9,
2438
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
2439
+ reducers: {
2440
+ setUsers: (state, action) => {
2441
+ const usersMapping = {};
2442
+ action.payload.forEach((user) => {
2443
+ usersMapping[user.id] = user;
2444
+ });
2445
+ state.users = usersMapping;
2446
+ },
2447
+ setCurrentUser: (state, action) => {
2448
+ state.currentUser = action.payload;
2449
+ },
2450
+ setProfilePicture: (state, action) => {
2451
+ state.currentUser.profile.file = action.payload.file ?? null;
2452
+ state.currentUser.profile.file_sha1 = action.payload.file_sha1 ?? null;
2453
+ const currentUser = state.users[state.currentUser.id];
2454
+ if (!currentUser) {
2455
+ throw new Error("Unable to find current user in users slice");
2456
+ }
2457
+ currentUser.profile.file = action.payload.file ?? null;
2458
+ currentUser.profile.file_sha1 = action.payload.file_sha1 ?? null;
2459
+ },
2460
+ addFavouriteProjectId: (state, action) => {
2461
+ state.currentUser.profile.favourite_project_ids.push(action.payload);
2462
+ },
2463
+ removeFavouriteProjectId: (state, action) => {
2464
+ state.currentUser.profile.favourite_project_ids = state.currentUser.profile.favourite_project_ids.filter(
2465
+ (id) => id !== action.payload
2466
+ );
2467
+ },
2468
+ setTourStep: (state, action) => {
2469
+ state.currentUser.profile.tour_step = action.payload;
2470
+ },
2471
+ removeUser: (state, action) => {
2472
+ delete state.users[action.payload];
2473
+ }
2474
+ }
2475
+ });
2476
+ const {
2477
+ setCurrentUser,
2478
+ setProfilePicture,
2479
+ setUsers,
2480
+ addFavouriteProjectId,
2481
+ removeFavouriteProjectId,
2482
+ setTourStep,
2483
+ removeUser
2484
+ } = userSlice.actions;
2485
+ const selectCurrentUser = (state) => state.userReducer.currentUser;
2486
+ const selectUser = (userId) => (state) => {
2487
+ if (userId === null)
2488
+ return void 0;
2489
+ return state.userReducer.users[userId];
2490
+ };
2491
+ const selectUsersAsMapping = (state) => state.userReducer.users;
2492
+ const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
2493
+ const selectSortedUsers = createSelector(
2494
+ [selectCurrentUser, selectUsersAsMapping, selectProjectAccessUserMapping],
2495
+ (currentUser, userMapping, projectAccessMapping) => {
2496
+ return Object.values(userMapping).sort((userA, userB) => {
2497
+ if (userA.id === currentUser.id) {
2498
+ return -1;
2499
+ } else if (userB.id === currentUser.id) {
2500
+ return 1;
2501
+ }
2502
+ const projectAccessesA = projectAccessMapping[userA.id];
2503
+ const projectAccessesB = projectAccessMapping[userB.id];
2504
+ if ((projectAccessesA == null ? void 0 : projectAccessesA.access_level) === (projectAccessesB == null ? void 0 : projectAccessesB.access_level)) {
2505
+ return userA.username.localeCompare(userB.username);
2506
+ }
2507
+ if ((projectAccessesA == null ? void 0 : projectAccessesA.access_level) === ProjectAccessLevel.ADMIN) {
2508
+ return -1;
2509
+ }
2510
+ return 1;
2511
+ });
2512
+ }
2513
+ );
2514
+ const userReducer = userSlice.reducer;
2515
+ const initialState$8 = {
2516
+ organizations: {},
2517
+ users: {},
2518
+ activeOrganizationId: 0
2519
+ };
2520
+ const organizationSlice = createSlice({
2521
+ name: "organizations",
2522
+ initialState: initialState$8,
2523
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
2524
+ reducers: {
2525
+ setOrganizations: (state, action) => {
2526
+ for (const org of action.payload) {
2527
+ state.organizations[org.id] = org;
2528
+ }
2529
+ },
2530
+ setActiveOrganization: (state, action) => {
2531
+ if (!state.activeOrganizationId) {
2532
+ throw new Error("Cannot update name of active organization. Active organization ID does not exist");
2533
+ }
2534
+ if (state.activeOrganizationId !== action.payload.id) {
2535
+ throw new Error("Tried updating active organization with different organization");
2536
+ }
2537
+ state.organizations[state.activeOrganizationId] = action.payload;
2538
+ },
2539
+ setActiveOrganizationId: (state, action) => {
2540
+ state.activeOrganizationId = action.payload;
2541
+ },
2542
+ setOrganizationUsers: (state, action) => {
2543
+ const usersMapping = {};
2544
+ action.payload.forEach((user) => {
2545
+ usersMapping[user.id] = user;
2546
+ });
2547
+ state.users = usersMapping;
2548
+ },
2549
+ removeOrganizationUser: (state, action) => {
2550
+ delete state.users[action.payload];
2551
+ }
2552
+ }
2553
+ });
2554
+ const {
2555
+ setOrganizations,
2556
+ setActiveOrganizationId,
2557
+ setActiveOrganization,
2558
+ setOrganizationUsers,
2559
+ removeOrganizationUser
2560
+ } = organizationSlice.actions;
2561
+ const selectActiveOrganizationId = (state) => {
2562
+ return state.organizationReducer.activeOrganizationId;
2563
+ };
2564
+ const selectOrganizations = (state) => {
2565
+ return Object.values(state.organizationReducer.organizations);
2566
+ };
2567
+ const selectActiveOrganization = (state) => {
2568
+ const id = selectActiveOrganizationId(state);
2569
+ if (!id) {
2570
+ return null;
2571
+ }
2572
+ const organization = state.organizationReducer.organizations[id];
2573
+ if (!organization) {
2574
+ return null;
2575
+ }
2576
+ return organization;
2577
+ };
2578
+ const selectOrganizationUsersAsMapping = (state) => state.organizationReducer.users;
2579
+ const selectSortedOrganizationUsers = createSelector(
2580
+ [selectCurrentUser, selectOrganizationUsersAsMapping, selectOrganizationAccessUserMapping],
2581
+ (currentUser, userMapping, organizationAccessMapping) => {
2582
+ return Object.values(userMapping).sort((userA, userB) => {
2583
+ if (userA.id === currentUser.id) {
2584
+ return -1;
2585
+ } else if (userB.id === currentUser.id) {
2586
+ return 1;
2587
+ }
2588
+ const organizationAccessesA = organizationAccessMapping[userA.id];
2589
+ const organizationAccessesB = organizationAccessMapping[userB.id];
2590
+ if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === (organizationAccessesB == null ? void 0 : organizationAccessesB.access_level)) {
2591
+ return userA.username.localeCompare(userB.username);
2592
+ }
2593
+ if ((organizationAccessesA == null ? void 0 : organizationAccessesA.access_level) === OrganizationAccessLevel.ADMIN) {
2594
+ return -1;
2595
+ }
2596
+ return 1;
2597
+ });
2598
+ }
2599
+ );
2600
+ const selectOrganization = (id) => (state) => {
2601
+ return state.organizationReducer.organizations[id];
2602
+ };
2603
+ const organizationReducer = organizationSlice.reducer;
2604
+ const createOfflineAction = (request2, baseUrl) => {
2605
+ const requestWithUuid = request2.uuid ? request2 : { ...request2, uuid: v4() };
2606
+ return {
2607
+ payload: requestWithUuid,
2608
+ type: "",
2609
+ meta: {
2610
+ offline: {
2611
+ effect: {
2612
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2613
+ request: requestWithUuid,
2614
+ BASE_URL: baseUrl
2615
+ }
2616
+ }
2617
+ }
2618
+ };
2619
+ };
2446
2620
  const initialState$7 = {
2621
+ deletedRequests: [],
2622
+ latestRetryTime: 0
2623
+ };
2624
+ const outboxSlice = createSlice({
2625
+ name: "outbox",
2626
+ initialState: initialState$7,
2627
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
2628
+ reducers: {
2629
+ // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
2630
+ // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
2631
+ // Then this reducer enqueueRequest() is responsible for adding the actual request data to the outbox
2632
+ enqueueRequest: {
2633
+ reducer: (state, _action) => {
2634
+ return state;
2635
+ },
2636
+ prepare: (payload) => {
2637
+ console.debug("Preparing to enqueue request", payload);
2638
+ const { BASE_URL, ...rest } = payload;
2639
+ return createOfflineAction(rest, BASE_URL);
2640
+ }
2641
+ },
2642
+ markForDeletion(state, action) {
2643
+ state.deletedRequests.push(action.payload);
2644
+ },
2645
+ markAsDeleted(state, action) {
2646
+ const index = state.deletedRequests.indexOf(action.payload);
2647
+ if (index !== -1)
2648
+ state.deletedRequests.splice(index, 1);
2649
+ },
2650
+ _setLatestRetryTime: (state, action) => {
2651
+ state.latestRetryTime = action.payload;
2652
+ }
2653
+ }
2654
+ });
2655
+ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
2656
+ const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
2657
+ const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
2658
+ const outboxReducer = outboxSlice.reducer;
2659
+ const initialState$6 = {
2447
2660
  projects: {},
2448
2661
  activeProjectId: null,
2449
2662
  recentProjectIds: [],
@@ -2452,7 +2665,7 @@ const initialState$7 = {
2452
2665
  };
2453
2666
  const projectSlice = createSlice({
2454
2667
  name: "projects",
2455
- initialState: initialState$7,
2668
+ initialState: initialState$6,
2456
2669
  reducers: {
2457
2670
  setProjects: (state, action) => {
2458
2671
  const projectsMap = {};
@@ -2516,7 +2729,7 @@ const selectRecentProjects = (state) => {
2516
2729
  };
2517
2730
  const selectCreateProjectType = (state) => state.projectReducer.createProjectType;
2518
2731
  const projectReducer = projectSlice.reducer;
2519
- const initialState$6 = {
2732
+ const initialState$5 = {
2520
2733
  projectFiles: {},
2521
2734
  activeProjectFileId: null,
2522
2735
  isImportingProjectFile: false,
@@ -2524,8 +2737,8 @@ const initialState$6 = {
2524
2737
  };
2525
2738
  const projectFileSlice = createSlice({
2526
2739
  name: "projectFiles",
2527
- initialState: initialState$6,
2528
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
2740
+ initialState: initialState$5,
2741
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
2529
2742
  reducers: {
2530
2743
  addOrReplaceProjectFiles: (state, action) => {
2531
2744
  for (let fileObj of action.payload) {
@@ -2626,12 +2839,12 @@ const selectProjectFiles = createSelector(
2626
2839
  const selectActiveProjectFileId = (state) => state.projectFileReducer.activeProjectFileId;
2627
2840
  const selectIsImportingProjectFile = (state) => state.projectFileReducer.isImportingProjectFile;
2628
2841
  const projectFileReducer = projectFileSlice.reducer;
2629
- const initialState$5 = {
2842
+ const initialState$4 = {
2630
2843
  isRehydrated: false
2631
2844
  };
2632
2845
  const rehydratedSlice = createSlice({
2633
2846
  name: "rehydrated",
2634
- initialState: initialState$5,
2847
+ initialState: initialState$4,
2635
2848
  // The `reducers` field lets us define reducers and generate associated actions
2636
2849
  reducers: {
2637
2850
  setRehydrated: (state, action) => {
@@ -2641,7 +2854,7 @@ const rehydratedSlice = createSlice({
2641
2854
  });
2642
2855
  const selectRehydrated = (state) => state.rehydratedReducer.isRehydrated;
2643
2856
  const rehydratedReducer = rehydratedSlice.reducer;
2644
- const initialState$4 = {
2857
+ const initialState$3 = {
2645
2858
  useIssueTemplate: false,
2646
2859
  placementMode: false,
2647
2860
  enableClustering: true,
@@ -2656,8 +2869,8 @@ const initialState$4 = {
2656
2869
  };
2657
2870
  const settingSlice = createSlice({
2658
2871
  name: "settings",
2659
- initialState: initialState$4,
2660
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
2872
+ initialState: initialState$3,
2873
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
2661
2874
  reducers: {
2662
2875
  setEnableDuplicateIssues: (state, action) => {
2663
2876
  state.useIssueTemplate = action.payload;
@@ -2720,7 +2933,7 @@ function considerCachingRevision(revision, formId, preferPending = false) {
2720
2933
  function getLatestRevisionFromCache(formId) {
2721
2934
  return LATEST_REVISION_CACHE[formId];
2722
2935
  }
2723
- const initialState$3 = {
2936
+ const initialState$2 = {
2724
2937
  userForms: {},
2725
2938
  revisions: {},
2726
2939
  submissions: {},
@@ -2728,8 +2941,8 @@ const initialState$3 = {
2728
2941
  };
2729
2942
  const userFormSlice = createSlice({
2730
2943
  name: "userForms",
2731
- initialState: initialState$3,
2732
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
2944
+ initialState: initialState$2,
2945
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$2)),
2733
2946
  reducers: {
2734
2947
  setUserForms: (state, action) => {
2735
2948
  state.userForms = {};
@@ -2977,171 +3190,38 @@ const selectNumberOfUserForms = createSelector([selectUserFormMapping], (userFor
2977
3190
  return Object.keys(userForms).length;
2978
3191
  });
2979
3192
  const userFormReducer = userFormSlice.reducer;
2980
- const initialState$2 = {
2981
- users: {},
2982
- currentUser: {
2983
- id: 0,
2984
- username: "",
2985
- email: "",
2986
- profile: { file: null, file_sha1: null, favourite_project_ids: [], tour_step: -1 }
2987
- }
2988
- };
2989
- const userSlice = createSlice({
2990
- name: "users",
2991
- initialState: initialState$2,
2992
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$2)),
2993
- reducers: {
2994
- setUsers: (state, action) => {
2995
- const usersMapping = {};
2996
- action.payload.forEach((user) => {
2997
- usersMapping[user.id] = user;
2998
- });
2999
- state.users = usersMapping;
3000
- },
3001
- setCurrentUser: (state, action) => {
3002
- state.currentUser = action.payload;
3003
- },
3004
- setProfilePicture: (state, action) => {
3005
- state.currentUser.profile.file = action.payload.file ?? null;
3006
- state.currentUser.profile.file_sha1 = action.payload.file_sha1 ?? null;
3007
- const currentUser = state.users[state.currentUser.id];
3008
- if (!currentUser) {
3009
- throw new Error("Unable to find current user in users slice");
3010
- }
3011
- currentUser.profile.file = action.payload.file ?? null;
3012
- currentUser.profile.file_sha1 = action.payload.file_sha1 ?? null;
3013
- },
3014
- addFavouriteProjectId: (state, action) => {
3015
- state.currentUser.profile.favourite_project_ids.push(action.payload);
3016
- },
3017
- removeFavouriteProjectId: (state, action) => {
3018
- state.currentUser.profile.favourite_project_ids = state.currentUser.profile.favourite_project_ids.filter(
3019
- (id) => id !== action.payload
3020
- );
3021
- },
3022
- setTourStep: (state, action) => {
3023
- state.currentUser.profile.tour_step = action.payload;
3024
- },
3025
- removeUser: (state, action) => {
3026
- delete state.users[action.payload];
3027
- }
3028
- }
3029
- });
3030
- const {
3031
- setCurrentUser,
3032
- setProfilePicture,
3033
- setUsers,
3034
- addFavouriteProjectId,
3035
- removeFavouriteProjectId,
3036
- setTourStep,
3037
- removeUser
3038
- } = userSlice.actions;
3039
- const selectCurrentUser = (state) => state.userReducer.currentUser;
3040
- const selectUser = (userId) => (state) => {
3041
- if (userId === null)
3042
- return void 0;
3043
- return state.userReducer.users[userId];
3044
- };
3045
- const selectUsersAsMapping = (state) => state.userReducer.users;
3046
- const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
3047
- const selectSortedUsers = createSelector(
3048
- [selectCurrentUser, selectUsersAsMapping, selectProjectAccessUserMapping],
3049
- (currentUser, userMapping, projectAccessMapping) => {
3050
- return Object.values(userMapping).sort((userA, userB) => {
3051
- if (userA.id === currentUser.id) {
3052
- return -1;
3053
- } else if (userB.id === currentUser.id) {
3054
- return 1;
3055
- }
3056
- const projectAccessesA = projectAccessMapping[userA.id];
3057
- const projectAccessesB = projectAccessMapping[userB.id];
3058
- if ((projectAccessesA == null ? void 0 : projectAccessesA.access_level) === (projectAccessesB == null ? void 0 : projectAccessesB.access_level)) {
3059
- return userA.username.localeCompare(userB.username);
3060
- }
3061
- if ((projectAccessesA == null ? void 0 : projectAccessesA.access_level) === ProjectAccessLevel.ADMIN) {
3062
- return -1;
3063
- }
3064
- return 1;
3065
- });
3066
- }
3067
- );
3068
- const userReducer = userSlice.reducer;
3069
3193
  const initialState$1 = {
3070
- organizationAccesses: {},
3071
- activeOrganizationAccessId: null
3194
+ emailDomains: {}
3072
3195
  };
3073
- const organizationAccessSlice = createSlice({
3074
- name: "organizationAccess",
3196
+ const emailDomainsSlice = createSlice({
3197
+ name: "emailDomains",
3075
3198
  initialState: initialState$1,
3076
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$1)),
3077
3199
  reducers: {
3078
- setOrganizationAccesses: (state, action) => {
3079
- if (!Array.isArray(action.payload))
3080
- throw new Error("Expected an array of OrganizationAccess");
3081
- if (action.payload.filter(onlyUniqueOfflineIds).length !== action.payload.length) {
3082
- throw new Error("Tried to use setOrganizationAccesses reducer with duplicate ID's");
3083
- }
3084
- const organizationAccesses = {};
3085
- for (const organizationAccess of action.payload) {
3086
- organizationAccesses[organizationAccess.offline_id] = organizationAccess;
3087
- }
3088
- state.organizationAccesses = organizationAccesses;
3200
+ setEmailDomains: (state, action) => {
3201
+ const emailDomains = {};
3202
+ action.payload.forEach((emailDomain) => {
3203
+ emailDomains[emailDomain.offline_id] = emailDomain;
3204
+ });
3205
+ state.emailDomains = emailDomains;
3089
3206
  },
3090
- updateOrganizationAccess: (state, action) => {
3091
- if (action.payload.offline_id in state.organizationAccesses) {
3092
- state.organizationAccesses[action.payload.offline_id] = action.payload;
3093
- } else {
3094
- throw new Error(
3095
- `Tried to update organization access with ID that doesn't exist: ${action.payload.offline_id}`
3096
- );
3097
- }
3207
+ addEmailDomain: (state, action) => {
3208
+ state.emailDomains[action.payload.offline_id] = action.payload;
3098
3209
  },
3099
- removeOrganizationAccess: (state, action) => {
3100
- if (action.payload.offline_id in state.organizationAccesses) {
3101
- delete state.organizationAccesses[action.payload.offline_id];
3210
+ removeEmailDomain: (state, action) => {
3211
+ if (action.payload.offline_id in state.emailDomains) {
3212
+ delete state.emailDomains[action.payload.offline_id];
3102
3213
  } else {
3103
- throw new Error(
3104
- `Tried to remove organization access with ID that doesn't exist: ${action.payload.offline_id}`
3105
- );
3214
+ throw new Error(`Tried to remove email domain with ID that doesn't exist: ${action.payload.offline_id}`);
3106
3215
  }
3107
- },
3108
- setActiveOrganizationAccessId: (state, action) => {
3109
- state.activeOrganizationAccessId = action.payload;
3110
3216
  }
3111
3217
  }
3112
3218
  });
3113
- const {
3114
- setOrganizationAccesses,
3115
- updateOrganizationAccess,
3116
- removeOrganizationAccess,
3117
- setActiveOrganizationAccessId
3118
- } = organizationAccessSlice.actions;
3119
- const selectOrganizationAccesses = (state) => {
3120
- return state.organizationAccessReducer.organizationAccesses;
3121
- };
3122
- const selectOrganizationAccess = (organizationAccessId) => (state) => {
3123
- return state.organizationAccessReducer.organizationAccesses[organizationAccessId];
3124
- };
3125
- const selectActiveOrganizationAccess = (state) => {
3126
- const activeOrganizationAccessId = state.organizationAccessReducer.activeOrganizationAccessId;
3127
- if (!activeOrganizationAccessId) {
3128
- return null;
3129
- }
3130
- return state.organizationAccessReducer.organizationAccesses[activeOrganizationAccessId] ?? null;
3131
- };
3132
- const selectOrganizationAccessForUser = (user) => (state) => {
3133
- return Object.values(state.organizationAccessReducer.organizationAccesses).find(
3134
- (organizationAccess) => organizationAccess.user === user.id
3135
- );
3136
- };
3137
- const selectOrganizationAccessUserMapping = (state) => {
3138
- const organizationAccesses = {};
3139
- Object.values(state.organizationAccessReducer.organizationAccesses).forEach((organizationAccess) => {
3140
- organizationAccesses[organizationAccess.user] = organizationAccess;
3141
- });
3142
- return organizationAccesses;
3143
- };
3144
- const organizationAccessReducer = organizationAccessSlice.reducer;
3219
+ const { setEmailDomains, addEmailDomain, removeEmailDomain } = emailDomainsSlice.actions;
3220
+ const selectEmailDomainsAsMapping = (state) => state.emailDomainsReducer.emailDomains;
3221
+ const selectSortedEmailDomains = (state) => Object.values(state.emailDomainsReducer.emailDomains).sort(
3222
+ (ed1, ed2) => ed1.domain.localeCompare(ed2.domain)
3223
+ );
3224
+ const emailDomainsReducer = emailDomainsSlice.reducer;
3145
3225
  const initialState = {
3146
3226
  version: 0
3147
3227
  };
@@ -3178,7 +3258,8 @@ const overmapReducers = {
3178
3258
  settingReducer,
3179
3259
  userFormReducer,
3180
3260
  userReducer,
3181
- workspaceReducer
3261
+ workspaceReducer,
3262
+ emailDomainsReducer
3182
3263
  };
3183
3264
  const overmapReducer = combineReducers(overmapReducers);
3184
3265
  const resetStore = "RESET";
@@ -4707,7 +4788,7 @@ class MainService extends BaseApiService {
4707
4788
  return result;
4708
4789
  });
4709
4790
  }
4710
- async fetchUsers(projectId) {
4791
+ async fetchProjectUsers(projectId) {
4711
4792
  return this.enqueueRequest({
4712
4793
  description: "Fetch users",
4713
4794
  method: HttpMethod.GET,
@@ -4716,6 +4797,15 @@ class MainService extends BaseApiService {
4716
4797
  blocks: []
4717
4798
  });
4718
4799
  }
4800
+ async fetchOrganizationUsers(orgId) {
4801
+ return this.enqueueRequest({
4802
+ description: "Fetch organization users",
4803
+ method: HttpMethod.GET,
4804
+ url: `/organizations/${orgId}/users/`,
4805
+ blockers: [],
4806
+ blocks: []
4807
+ });
4808
+ }
4719
4809
  // TODO:
4720
4810
  // Don't accept updateStore in ComponentService.list. Just return the offline objects and promise. Here, if
4721
4811
  // overwrite, use setComponents. Otherwise, use bulkAddComponents.
@@ -4758,13 +4848,22 @@ class MainService extends BaseApiService {
4758
4848
  const firstOrg = organizationsData[0];
4759
4849
  const currProjObj = projects.find((project) => project.id === currentProjectId);
4760
4850
  const isOrgProject = !!(currProjObj == null ? void 0 : currProjObj.owner_organization);
4851
+ let currentOrgId = -1;
4761
4852
  if (isOrgProject && currProjObj.owner_organization) {
4762
- store.dispatch(setActiveOrganizationId(currProjObj.owner_organization));
4853
+ currentOrgId = currProjObj.owner_organization;
4763
4854
  } else if (firstOrg) {
4764
4855
  console.warn(
4765
4856
  "No active organization; using the first available one. TODO: No active organization in personal projects."
4766
4857
  );
4767
- store.dispatch(setActiveOrganizationId(firstOrg.id));
4858
+ currentOrgId = firstOrg.id;
4859
+ }
4860
+ if (currentOrgId !== -1) {
4861
+ store.dispatch(setActiveOrganizationId(currentOrgId));
4862
+ const orgUsersResultPromise = this.fetchOrganizationUsers(currentOrgId);
4863
+ const organizationAccessRefreshPromise = this.client.organizationAccess.refreshStore();
4864
+ const orgUsersResult = await orgUsersResultPromise;
4865
+ await organizationAccessRefreshPromise;
4866
+ store.dispatch(setOrganizationUsers(orgUsersResult));
4768
4867
  }
4769
4868
  if (!isProjectIdValid) {
4770
4869
  if (projects.length !== 0) {
@@ -4787,12 +4886,10 @@ class MainService extends BaseApiService {
4787
4886
  }
4788
4887
  }
4789
4888
  if (currentProjectId) {
4790
- const usersResultPromise = this.fetchUsers(currentProjectId);
4889
+ const usersResultPromise = this.fetchProjectUsers(currentProjectId);
4791
4890
  const projectAccessRefreshPromise = this.client.projectAccesses.refreshStore();
4792
- const organizationAccessRefreshPromise = this.client.organizationAccess.refreshStore();
4793
4891
  const usersResult = await usersResultPromise;
4794
4892
  await projectAccessRefreshPromise;
4795
- await organizationAccessRefreshPromise;
4796
4893
  store.dispatch(setUsers(usersResult));
4797
4894
  }
4798
4895
  let currentWorkspaceId;
@@ -4819,6 +4916,7 @@ class MainService extends BaseApiService {
4819
4916
  void this.client.userForms.refreshStore().then(() => {
4820
4917
  void this.client.userFormSubmissions.refreshStore().then();
4821
4918
  });
4919
+ void this.client.emailDomains.refreshStore().then();
4822
4920
  }
4823
4921
  if (currentProjectId) {
4824
4922
  const [_offlineAttachments, promise] = this.client.attachments.fetchAll(currentProjectId);
@@ -4842,8 +4940,7 @@ class MainService extends BaseApiService {
4842
4940
  }
4843
4941
  }
4844
4942
  class ProjectAccessService extends BaseApiService {
4845
- fetchAll(projectId) {
4846
- const { store } = this.client;
4943
+ async fetchAll(projectId) {
4847
4944
  const promise = this.enqueueRequest({
4848
4945
  description: "Get project accesses",
4849
4946
  method: HttpMethod.GET,
@@ -4851,12 +4948,11 @@ class ProjectAccessService extends BaseApiService {
4851
4948
  blockers: [],
4852
4949
  blocks: []
4853
4950
  });
4854
- const offlineProjectAccesses = Object.values(store.getState().projectAccessReducer.projectAccesses);
4855
- return [offlineProjectAccesses, promise];
4951
+ return promise;
4856
4952
  }
4857
- update(projectAccess) {
4953
+ async update(projectAccess) {
4858
4954
  this.client.store.dispatch(updateProjectAccess(projectAccess));
4859
- const promise = this.enqueueRequest({
4955
+ return this.enqueueRequest({
4860
4956
  description: "Edit project access",
4861
4957
  method: HttpMethod.PATCH,
4862
4958
  url: `/access/${projectAccess.offline_id}/`,
@@ -4864,10 +4960,9 @@ class ProjectAccessService extends BaseApiService {
4864
4960
  blockers: [projectAccess.offline_id],
4865
4961
  blocks: [projectAccess.offline_id]
4866
4962
  });
4867
- return [projectAccess, promise];
4868
4963
  }
4869
4964
  // TODO: Re-add user to project if removal fails
4870
- remove(projectAccess) {
4965
+ async remove(projectAccess) {
4871
4966
  const { store } = this.client;
4872
4967
  store.dispatch(removeProjectAccess(projectAccess));
4873
4968
  store.dispatch(removeUser(projectAccess.user));
@@ -4887,7 +4982,7 @@ class ProjectAccessService extends BaseApiService {
4887
4982
  if (!projectId) {
4888
4983
  throw new Error("No active project");
4889
4984
  }
4890
- const [_offlineProjectAccesses, promise] = this.fetchAll(projectId);
4985
+ const promise = this.fetchAll(projectId);
4891
4986
  const result = await promise;
4892
4987
  const activeProjectAccess = result.find((projectAccess) => projectAccess.user === currentUser.id);
4893
4988
  if (!activeProjectAccess) {
@@ -5484,6 +5579,31 @@ class WorkspaceService extends BaseApiService {
5484
5579
  }
5485
5580
  }
5486
5581
  class OrganizationAccessService extends BaseApiService {
5582
+ async update(organizationAccess) {
5583
+ const promise = this.enqueueRequest({
5584
+ description: "Edit organization access",
5585
+ method: HttpMethod.PATCH,
5586
+ url: `/organizations/${organizationAccess.organization}/access/${organizationAccess.offline_id}/`,
5587
+ payload: organizationAccess,
5588
+ blockers: [organizationAccess.offline_id],
5589
+ blocks: [organizationAccess.offline_id]
5590
+ });
5591
+ void promise.then(() => {
5592
+ this.client.store.dispatch(updateOrganizationAccess(organizationAccess));
5593
+ });
5594
+ return promise;
5595
+ }
5596
+ async remove(organizationAccess) {
5597
+ this.client.store.dispatch(removeOrganizationAccess(organizationAccess));
5598
+ this.client.store.dispatch(removeOrganizationUser(organizationAccess.user));
5599
+ return this.enqueueRequest({
5600
+ description: "Remove organization access",
5601
+ method: HttpMethod.DELETE,
5602
+ url: `/organizations/${organizationAccess.organization}/access/${organizationAccess.offline_id}/`,
5603
+ blockers: [organizationAccess.offline_id],
5604
+ blocks: []
5605
+ });
5606
+ }
5487
5607
  async refreshStore() {
5488
5608
  const { store } = this.client;
5489
5609
  const state = store.getState();
@@ -5731,6 +5851,86 @@ class EmailVerificationService extends BaseApiService {
5731
5851
  return this.enqueueRequest(requestDetails);
5732
5852
  }
5733
5853
  }
5854
+ class EmailDomainsService extends BaseApiService {
5855
+ async fetchAll(orgId) {
5856
+ return this.enqueueRequest({
5857
+ description: "Fetch email domains for organization",
5858
+ method: HttpMethod.GET,
5859
+ url: `/organizations/${orgId}/email-domains/`,
5860
+ blockers: [orgId.toString()],
5861
+ blocks: []
5862
+ });
5863
+ }
5864
+ async add(orgId, email) {
5865
+ return this.enqueueRequest({
5866
+ description: "Add email domain to organization",
5867
+ method: HttpMethod.POST,
5868
+ url: `/organizations/${orgId}/email-domains/`,
5869
+ payload: { email },
5870
+ blockers: [orgId.toString()],
5871
+ blocks: []
5872
+ });
5873
+ }
5874
+ async remove(emailDomain) {
5875
+ this.client.store.dispatch(removeEmailDomain(emailDomain));
5876
+ return this.enqueueRequest({
5877
+ description: "Remove email domain from organization",
5878
+ method: HttpMethod.DELETE,
5879
+ url: `/organizations/${emailDomain.organization}/email-domains/${emailDomain.offline_id}/`,
5880
+ blockers: [],
5881
+ blocks: []
5882
+ }).catch((e) => {
5883
+ this.client.store.dispatch(addEmailDomain(emailDomain));
5884
+ throw e;
5885
+ });
5886
+ }
5887
+ async refreshStore() {
5888
+ const organizationId = this.client.store.getState().organizationReducer.activeOrganizationId;
5889
+ if (!organizationId) {
5890
+ throw new Error("No active organization");
5891
+ }
5892
+ const promise = this.fetchAll(organizationId);
5893
+ const result = await promise;
5894
+ this.client.store.dispatch(setEmailDomains(result));
5895
+ }
5896
+ }
5897
+ class OrganizationService extends BaseApiService {
5898
+ async create(name) {
5899
+ const result = await this.enqueueRequest({
5900
+ description: "Create organization",
5901
+ method: HttpMethod.POST,
5902
+ url: "/organizations/",
5903
+ payload: { name },
5904
+ blockers: [`add-org-${name}`],
5905
+ blocks: [`add-org-${name}`]
5906
+ });
5907
+ await this.client.main.fetchInitialData(true);
5908
+ return result;
5909
+ }
5910
+ async update(organization) {
5911
+ const promise = this.enqueueRequest({
5912
+ description: "Edit organization",
5913
+ method: HttpMethod.PATCH,
5914
+ url: `/organizations/${organization.id}/`,
5915
+ payload: organization,
5916
+ blockers: [`add-org-${organization.name}`, organization.id.toString()],
5917
+ blocks: [organization.id.toString()]
5918
+ });
5919
+ void promise.then(() => {
5920
+ this.client.store.dispatch(setActiveOrganization(organization));
5921
+ });
5922
+ return promise;
5923
+ }
5924
+ async invite(organizationId, email) {
5925
+ return this.enqueueRequest({
5926
+ description: "Invite user to organization",
5927
+ method: HttpMethod.POST,
5928
+ url: `/organizations/${organizationId}/invite/${email}/`,
5929
+ blockers: [],
5930
+ blocks: []
5931
+ });
5932
+ }
5933
+ }
5734
5934
  class OvermapSDK {
5735
5935
  constructor(apiUrl, store) {
5736
5936
  __publicField(this, "API_URL");
@@ -5740,6 +5940,7 @@ class OvermapSDK {
5740
5940
  __publicField(this, "auth", new AuthService(this));
5741
5941
  __publicField(this, "categories", new CategoryService(this));
5742
5942
  __publicField(this, "projectAccesses", new ProjectAccessService(this));
5943
+ __publicField(this, "organizations", new OrganizationService(this));
5743
5944
  __publicField(this, "organizationAccess", new OrganizationAccessService(this));
5744
5945
  __publicField(this, "issues", new IssueService(this));
5745
5946
  __publicField(this, "issueComments", new IssueCommentService(this));
@@ -5754,6 +5955,7 @@ class OvermapSDK {
5754
5955
  __publicField(this, "projects", new ProjectService(this));
5755
5956
  __publicField(this, "projectFiles", new ProjectFileService(this));
5756
5957
  __publicField(this, "emailVerification", new EmailVerificationService(this));
5958
+ __publicField(this, "emailDomains", new EmailDomainsService(this));
5757
5959
  this.API_URL = apiUrl;
5758
5960
  this.store = store;
5759
5961
  }
@@ -5796,6 +5998,7 @@ export {
5796
5998
  ComponentTypeService,
5797
5999
  DEFAULT_ISSUE_PRIORITY,
5798
6000
  DEFAULT_ISSUE_STATUS,
6001
+ EmailDomainsService,
5799
6002
  EmailVerificationService,
5800
6003
  FileService,
5801
6004
  GREEN,
@@ -5809,6 +6012,7 @@ export {
5809
6012
  OUTBOX_RETRY_DELAY,
5810
6013
  OrganizationAccessLevel,
5811
6014
  OrganizationAccessService,
6015
+ OrganizationService,
5812
6016
  OutboxCoordinator,
5813
6017
  OvermapContext,
5814
6018
  OvermapProvider,
@@ -5832,6 +6036,7 @@ export {
5832
6036
  addComponent,
5833
6037
  addComponentType,
5834
6038
  addComponentsInBatches,
6039
+ addEmailDomain,
5835
6040
  addFavouriteProjectId,
5836
6041
  addIssue,
5837
6042
  addOrReplaceCategories,
@@ -5890,6 +6095,8 @@ export {
5890
6095
  dequeue,
5891
6096
  discard,
5892
6097
  downloadInMemoryFile,
6098
+ emailDomainsReducer,
6099
+ emailDomainsSlice,
5893
6100
  emailRegex,
5894
6101
  enqueue,
5895
6102
  enqueueRequest,
@@ -5958,10 +6165,12 @@ export {
5958
6165
  removeCategory,
5959
6166
  removeColor,
5960
6167
  removeComponent,
6168
+ removeEmailDomain,
5961
6169
  removeFavouriteProjectId,
5962
6170
  removeIssue,
5963
6171
  removeIssueComment,
5964
6172
  removeOrganizationAccess,
6173
+ removeOrganizationUser,
5965
6174
  removeProjectAccess,
5966
6175
  removeProjectAccessesOfProject,
5967
6176
  removeProjectFile,
@@ -6016,6 +6225,7 @@ export {
6016
6225
  selectCreateProjectType,
6017
6226
  selectCurrentUser,
6018
6227
  selectDeletedRequests,
6228
+ selectEmailDomainsAsMapping,
6019
6229
  selectEnableClustering,
6020
6230
  selectEnableDuplicateIssues,
6021
6231
  selectEnablePlacementMode,
@@ -6050,6 +6260,7 @@ export {
6050
6260
  selectOrganizationAccessForUser,
6051
6261
  selectOrganizationAccessUserMapping,
6052
6262
  selectOrganizationAccesses,
6263
+ selectOrganizationUsersAsMapping,
6053
6264
  selectOrganizations,
6054
6265
  selectPermittedWorkspaceIds,
6055
6266
  selectPhotoAttachmentsOfIssue,
@@ -6066,6 +6277,8 @@ export {
6066
6277
  selectRehydrated,
6067
6278
  selectRevisionsForForm,
6068
6279
  selectShowTooltips,
6280
+ selectSortedEmailDomains,
6281
+ selectSortedOrganizationUsers,
6069
6282
  selectSortedUsers,
6070
6283
  selectStageMapping,
6071
6284
  selectStages,
@@ -6088,6 +6301,7 @@ export {
6088
6301
  selectWorkspaceMapping,
6089
6302
  selectWorkspaces,
6090
6303
  setActiveIssueId,
6304
+ setActiveOrganization,
6091
6305
  setActiveOrganizationAccessId,
6092
6306
  setActiveOrganizationId,
6093
6307
  setActiveProjectFileId,
@@ -6101,6 +6315,7 @@ export {
6101
6315
  setComponents,
6102
6316
  setCreateProjectType,
6103
6317
  setCurrentUser,
6318
+ setEmailDomains,
6104
6319
  setEnableClustering,
6105
6320
  setEnableDuplicateIssues,
6106
6321
  setEnablePlacementMode,
@@ -6111,6 +6326,7 @@ export {
6111
6326
  setLoggedIn,
6112
6327
  setMapStyle,
6113
6328
  setOrganizationAccesses,
6329
+ setOrganizationUsers,
6114
6330
  setOrganizations,
6115
6331
  setProfilePicture,
6116
6332
  setProjectAccesses,