diff --git a/packages/nc-gui/pages/index/index/index.vue b/packages/nc-gui/pages/index/index/index.vue
index 262a57f1fd..8b3bb91c92 100644
--- a/packages/nc-gui/pages/index/index/index.vue
+++ b/packages/nc-gui/pages/index/index/index.vue
@@ -1,5 +1,7 @@
@@ -221,6 +331,7 @@ const copyProjectMeta = async () => {
{
-
+
diff --git a/packages/nocodb/src/lib/Noco.ts b/packages/nocodb/src/lib/Noco.ts
index 0dc767c026..71258fa3ba 100644
--- a/packages/nocodb/src/lib/Noco.ts
+++ b/packages/nocodb/src/lib/Noco.ts
@@ -101,7 +101,7 @@ export default class Noco {
constructor() {
process.env.PORT = process.env.PORT || '8080';
// todo: move
- process.env.NC_VERSION = '0098005';
+ process.env.NC_VERSION = '0100003';
// if env variable NC_MINIMAL_DBS is set, then disable project creation with external sources
if (process.env.NC_MINIMAL_DBS) {
diff --git a/packages/nocodb/src/lib/meta/api/projectApis.ts b/packages/nocodb/src/lib/meta/api/projectApis.ts
index e2f07a1147..85977b2b6a 100644
--- a/packages/nocodb/src/lib/meta/api/projectApis.ts
+++ b/packages/nocodb/src/lib/meta/api/projectApis.ts
@@ -56,8 +56,18 @@ export async function projectUpdate(
'title',
'meta',
'color',
+ 'order',
]);
+ // todo: maintain project order in user_project table for non super admin users
+ // block project order update for non super admin users
+ if (
+ 'order' in data &&
+ !req['user']?.roles?.includes(OrgUserRoles.SUPER_ADMIN)
+ ) {
+ NcError.forbidden('Only super admin can update order');
+ }
+
if (
data?.title &&
project.title !== data.title &&
@@ -465,7 +475,7 @@ export async function projectInfoGet(_req, res) {
export async function projectCost(req, res) {
let cost = 0;
const project = await Project.getWithInfo(req.params.projectId);
-
+
for (const base of project.bases) {
const sqlClient = NcConnectionMgrv2.getSqlClient(base);
const userCount = await ProjectUser.getUsersCount(req.query);
diff --git a/packages/nocodb/src/lib/models/Project.ts b/packages/nocodb/src/lib/models/Project.ts
index cf1cdf5a4d..1174079aac 100644
--- a/packages/nocodb/src/lib/models/Project.ts
+++ b/packages/nocodb/src/lib/models/Project.ts
@@ -54,6 +54,9 @@ export default class Project implements ProjectType {
is_meta: projectBody.is_meta,
created_at: projectBody.created_at,
updated_at: projectBody.updated_at,
+ order:
+ projectBody.order ??
+ (await ncMeta.metaGetNextOrder(MetaTable.PROJECT, {})),
}
);
@@ -101,6 +104,9 @@ export default class Project implements ProjectType {
},
],
},
+ orderBy: {
+ order: 'asc',
+ },
});
await NocoCache.setList(CacheScope.PROJECT, [], projectList);
}
@@ -261,6 +267,11 @@ export default class Project implements ProjectType {
}
o = { ...o, ...updateObj };
+ // if order is changed, delete existing project list to get new ordered list
+ if ('order' in updateObj) {
+ await NocoCache.delAll(CacheScope.PROJECT, '*');
+ }
+
await NocoCache.del(CacheScope.INSTANCE_META);
// set cache
diff --git a/packages/nocodb/src/lib/models/ProjectUser.ts b/packages/nocodb/src/lib/models/ProjectUser.ts
index c4c7454a31..1f485f5c41 100644
--- a/packages/nocodb/src/lib/models/ProjectUser.ts
+++ b/packages/nocodb/src/lib/models/ProjectUser.ts
@@ -245,7 +245,7 @@ export default class ProjectUser {
this.where(`${MetaTable.PROJECT}.deleted`, false).orWhereNull(
`${MetaTable.PROJECT}.deleted`
);
- });
+ }).orderBy('order', 'asc');
if (projectList?.length) {
await NocoCache.setList(CacheScope.USER_PROJECT, [userId], projectList);
diff --git a/packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts b/packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts
index a51d04910b..23878d85d7 100644
--- a/packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts
+++ b/packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts
@@ -8,6 +8,7 @@ import ncProjectEnvUpgrader0011045 from './ncProjectEnvUpgrader0011045';
import ncProjectUpgraderV2_0090000 from './ncProjectUpgraderV2_0090000';
import ncDataTypesUpgrader from './ncDataTypesUpgrader';
import ncProjectRolesUpgrader from './ncProjectRolesUpgrader';
+import ncProjectOrderUpgrader from './ncProjectOrderUpgrader';
const log = debug('nc:version-upgrader');
import boxen from 'boxen';
@@ -35,6 +36,7 @@ export default class NcUpgrader {
{ name: '0090000', handler: ncProjectUpgraderV2_0090000 },
{ name: '0098004', handler: ncDataTypesUpgrader },
{ name: '0098005', handler: ncProjectRolesUpgrader },
+ { name: '0100003', handler: ncProjectOrderUpgrader },
];
if (!(await ctx.ncMeta.knexConnection?.schema?.hasTable?.('nc_store'))) {
return;
diff --git a/packages/nocodb/src/lib/version-upgrader/ncProjectOrderUpgrader.ts b/packages/nocodb/src/lib/version-upgrader/ncProjectOrderUpgrader.ts
new file mode 100644
index 0000000000..5fbdb8ae23
--- /dev/null
+++ b/packages/nocodb/src/lib/version-upgrader/ncProjectOrderUpgrader.ts
@@ -0,0 +1,18 @@
+import { MetaTable } from '../utils/globals'
+import { NcUpgraderCtx } from './NcUpgrader'
+
+/** Upgrader for upgrading roles */
+export default async function({ ncMeta }: NcUpgraderCtx) {
+ const projects = await ncMeta.metaList2(null, null, MetaTable.PROJECT)
+
+ let order = 0;
+ for (const project of projects) {
+ await ncMeta.metaUpdate(
+ null,
+ null,
+ MetaTable.PROJECT,
+ {
+ order: ++order,
+ }, project.id)
+ }
+}