dbdocs 0.13.1 → 0.14.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/README.md CHANGED
File without changes
package/bin/run.cmd CHANGED
File without changes
@@ -1 +1 @@
1
- {"version":"0.13.1","commands":{"build":{"id":"build","description":"build docs","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{"project":{"name":"project","type":"option","description":"project name","multiple":false},"public":{"name":"public","type":"boolean","description":"anyone with the URL can access","helpGroup":"sharing","allowNo":false,"exclusive":["private","password"]},"private":{"name":"private","type":"boolean","description":"only invited people can access","helpGroup":"sharing","allowNo":false,"exclusive":["public","password"]},"password":{"name":"password","type":"option","char":"p","description":"anyone with the URL + password can access","helpGroup":"sharing","multiple":false,"exclusive":["public","private"]}},"args":[{"name":"filepath","description":"dbml file path"}]},"db2dbml":{"id":"db2dbml","description":"Generate DBML directly from a database","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"examples":"Postgres:\n $ db2dbml postgres 'postgresql://user:password@localhost:5432/dbname?schemas=schema1,schema2'\nMySQL:\n $ db2dbml mysql 'mysql://user:password@localhost:3306/dbname'\nMSSQL:\n $ db2dbml mssql 'Server=localhost,1433;Database=master;User Id=sa;Password=your_password;Encrypt=true;TrustServerCertificate=true;Schemas=schema1,schema2;'\nSnowflake:\n $ db2dbml snowflake 'SERVER=<account_identifier>.<region>;UID=<your_username>;PWD=<your_password>;DATABASE=<your_database>;WAREHOUSE=<your_warehouse>;ROLE=<your_role>;SCHEMAS=schema1,schema2;'\nBigQuery:\n $ db2dbml bigquery /path_to_json_credential.json\n \n Note: Your JSON credential file must contain:\n {\n \"project_id\": \"your-project-id\",\n \"client_email\": \"your-client-email\",\n \"private_key\": \"your-private-key\",\n \"datasets\": [\"dataset_1\", \"dataset_2\", ...]\n }\n If \"datasets\" key is not provided or is empty, it will fetch all datasets.","flags":{"outFile":{"name":"outFile","type":"option","char":"o","description":"output file path","helpValue":"/path-to-your-file","multiple":false}},"args":[{"name":"database-type","description":"your database type (postgres, mysql, mssql, snowflake, bigquery)","required":true},{"name":"connection-string","description":"your database connection string (See below examples for more details)","required":true}]},"login":{"id":"login","description":"login to dbdocs\nlogin with your dbdocs credentials\n","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"logout":{"id":"logout","description":"logout\nclears local login credentials\n","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"ls":{"id":"ls","description":"list projects","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"password":{"id":"password","description":"set password for your project or remove password","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{"project":{"name":"project","type":"option","char":"p","description":"project name","helpValue":"project name","multiple":false},"set":{"name":"set","type":"option","char":"s","description":"password for your project","helpValue":"password","multiple":false},"remove":{"name":"remove","type":"boolean","char":"r","description":"remove password from your project","allowNo":false}},"args":[]},"remove":{"id":"remove","description":"remove project","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"project_name","description":"name of the project which you want to remove"}]},"rename":{"id":"rename","description":"change your username","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"set":{"id":"set","description":"Set the Web URL and API URL of dbdocs self-hosted server","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"examples":"$ dbdocs set --webUrl http://webserver.dev --apiUrl http://apiserver.dev","flags":{"webUrl":{"name":"webUrl","type":"option","description":"Self-hosted web url","required":true,"multiple":false},"apiUrl":{"name":"apiUrl","type":"option","description":"Self-hosted api url","required":true,"multiple":false}},"args":[]},"token":{"id":"token","description":"generate or revoke your authentication token","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{"generate":{"name":"generate","type":"boolean","char":"g","description":"generate authentication token","allowNo":false},"revoke":{"name":"revoke","type":"boolean","char":"r","description":"revoke authentication token","allowNo":false}},"args":[]},"validate":{"id":"validate","description":"validate docs content","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"filepath","description":"dbml file path"}]}}}
1
+ {"version":"0.14.0","commands":{"build":{"id":"build","description":"build docs","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{"project":{"name":"project","type":"option","description":"<username>/<project_name> or <project_name>","multiple":false},"public":{"name":"public","type":"boolean","description":"anyone with the URL can access","helpGroup":"sharing","allowNo":false,"exclusive":["private","password"]},"private":{"name":"private","type":"boolean","description":"only invited people can access","helpGroup":"sharing","allowNo":false,"exclusive":["public","password"]},"password":{"name":"password","type":"option","char":"p","description":"anyone with the URL + password can access","helpGroup":"sharing","multiple":false,"exclusive":["public","private"]}},"args":[{"name":"filepath","description":"dbml file path"}]},"db2dbml":{"id":"db2dbml","description":"Generate DBML directly from a database","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"examples":"Postgres:\n $ db2dbml postgres 'postgresql://user:password@localhost:5432/dbname?schemas=schema1,schema2'\nMySQL:\n $ db2dbml mysql 'mysql://user:password@localhost:3306/dbname'\nMSSQL:\n $ db2dbml mssql 'Server=localhost,1433;Database=master;User Id=sa;Password=your_password;Encrypt=true;TrustServerCertificate=true;Schemas=schema1,schema2;'\nSnowflake:\n $ db2dbml snowflake 'SERVER=<account_identifier>.<region>;UID=<your_username>;PWD=<your_password>;DATABASE=<your_database>;WAREHOUSE=<your_warehouse>;ROLE=<your_role>;SCHEMAS=schema1,schema2;'\nBigQuery:\n $ db2dbml bigquery /path_to_json_credential.json\n \n Note: Your JSON credential file must contain:\n {\n \"project_id\": \"your-project-id\",\n \"client_email\": \"your-client-email\",\n \"private_key\": \"your-private-key\",\n \"datasets\": [\"dataset_1\", \"dataset_2\", ...]\n }\n If \"datasets\" key is not provided or is empty, it will fetch all datasets.","flags":{"outFile":{"name":"outFile","type":"option","char":"o","description":"output file path","helpValue":"/path-to-your-file","multiple":false}},"args":[{"name":"database-type","description":"your database type (postgres, mysql, mssql, snowflake, bigquery)","required":true},{"name":"connection-string","description":"your database connection string (See below examples for more details)","required":true}]},"login":{"id":"login","description":"login to dbdocs\nlogin with your dbdocs credentials\n","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"logout":{"id":"logout","description":"logout\nclears local login credentials\n","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"ls":{"id":"ls","description":"list projects","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"password":{"id":"password","description":"set password for your project or remove password","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{"project":{"name":"project","type":"option","char":"p","description":"project name","helpValue":"project name","multiple":false},"set":{"name":"set","type":"option","char":"s","description":"password for your project","helpValue":"password","multiple":false},"remove":{"name":"remove","type":"boolean","char":"r","description":"remove password from your project","allowNo":false}},"args":[]},"remove":{"id":"remove","description":"remove project","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"project_name","description":"name of the project which you want to remove"}]},"rename":{"id":"rename","description":"change your username","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[]},"set":{"id":"set","description":"Set the Web URL and API URL of dbdocs self-hosted server","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"examples":"$ dbdocs set --webUrl http://webserver.dev --apiUrl http://apiserver.dev","flags":{"webUrl":{"name":"webUrl","type":"option","description":"Self-hosted web url","required":true,"multiple":false},"apiUrl":{"name":"apiUrl","type":"option","description":"Self-hosted api url","required":true,"multiple":false}},"args":[]},"token":{"id":"token","description":"generate or revoke your authentication token","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{"generate":{"name":"generate","type":"boolean","char":"g","description":"generate authentication token","allowNo":false},"revoke":{"name":"revoke","type":"boolean","char":"r","description":"revoke authentication token","allowNo":false}},"args":[]},"validate":{"id":"validate","description":"validate docs content","strict":true,"pluginName":"dbdocs","pluginAlias":"dbdocs","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"filepath","description":"dbml file path"}]}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbdocs",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "author": "@holistics",
5
5
  "bin": {
6
6
  "dbdocs": "./bin/run"
@@ -14,7 +14,7 @@ const { shouldAskForFeedback } = require('../utils/feedback');
14
14
  const { isValidName } = require('../validators/projectName');
15
15
  const parse = require('../utils/parse');
16
16
  const { PROJECT_GENERAL_ACCESS_TYPE, FLAG_HELP_GROUP } = require('../utils/constants');
17
- const { getProjectUrl } = require('../utils/helper');
17
+ const { getProjectUrl, parseProjectName } = require('../utils/helper');
18
18
  const { getIsPublicValueFromBuildFlag } = require('../utils/helper');
19
19
  const { formatParserV2ErrorMessage } = require('../utils/error-formatter');
20
20
 
@@ -26,6 +26,16 @@ async function build (project, authConfig) {
26
26
  return { newProject: res.data.project, isCreated: res.status === 201 };
27
27
  }
28
28
 
29
+ async function enterOrgName (defaultOrgName) {
30
+ const answer = await inquirer.prompt([
31
+ {
32
+ message: `Username: (${defaultOrgName})`,
33
+ name: 'orgName',
34
+ },
35
+ ]);
36
+ return answer.orgName || defaultOrgName;
37
+ }
38
+
29
39
  async function enterProjectName () {
30
40
  const answer = await inquirer.prompt([
31
41
  {
@@ -43,15 +53,26 @@ class BuildCommand extends Command {
43
53
  try {
44
54
  const authConfig = await verifyToken();
45
55
  const { flags, args } = await this.parse(BuildCommand);
46
- const { public: publicFlag, private: privateFlag, password } = flags;
47
- let { project } = flags;
56
+ const {
57
+ public: publicFlag, private: privateFlag, password, project,
58
+ } = flags;
48
59
 
49
60
  const { filepath } = args;
50
61
  let content = '';
51
62
  content = fs.readFileSync(path.resolve(process.cwd(), filepath), 'utf-8');
52
63
 
53
- const userOrg = await getOrg(authConfig);
54
- const org = userOrg.name;
64
+ const defaultOrgName = (await getOrg(authConfig)).name;
65
+ let orgName = '';
66
+ let projectNameFromDbml = null;
67
+ let projectNameFromInput = null;
68
+
69
+ // Re-parse the project name from argument to get the username
70
+ if (project) {
71
+ const parseRes = parseProjectName(project);
72
+
73
+ if (!parseRes) spinner.warn('Invalid username or project name!');
74
+ else [orgName, projectNameFromInput] = parseRes;
75
+ }
55
76
 
56
77
  // validate dbml syntax, get project name if it's already defined in the file
57
78
  spinner.text = 'Parsing file content';
@@ -60,7 +81,7 @@ class BuildCommand extends Command {
60
81
  try {
61
82
  model = await parse(content);
62
83
  if (!project) {
63
- project = model.name;
84
+ projectNameFromDbml = model.name;
64
85
  }
65
86
  spinner.succeed('Parsing file content');
66
87
  } catch (error) {
@@ -69,34 +90,47 @@ class BuildCommand extends Command {
69
90
  throw new Error(message);
70
91
  }
71
92
 
93
+ if (!orgName) orgName = defaultOrgName;
94
+
95
+ let projectName = projectNameFromInput || projectNameFromDbml;
96
+
72
97
  // if project name is not defined yet, ask user to input the project name
73
- if (!project) {
74
- project = await enterProjectName();
98
+ if (!projectName) {
99
+ // ask the username to publish to
100
+ orgName = await enterOrgName(defaultOrgName);
101
+ while (!isValidName(orgName)) {
102
+ // eslint-disable-next-line max-len
103
+ spinner.warn('Invalid username! Username can only contain alphabets, numbers, space, "-" or "_", or leave it blank to publish to your personal account!');
104
+ // eslint-disable-next-line no-await-in-loop
105
+ orgName = await enterOrgName(defaultOrgName);
106
+ }
107
+ projectName = await enterProjectName();
75
108
  }
76
109
 
77
- while (!isValidName(project)) {
78
- spinner.warn('Invalid project name! Project name can only contain only alphabets, numbers, space, "-" or "_" and can not be blanked!');
110
+ while (!isValidName(projectName)) {
111
+ spinner.warn('Invalid project name! Project name can only contain alphabets, numbers, space, "-" or "_" and can not be blanked!');
79
112
  // eslint-disable-next-line no-await-in-loop
80
- project = await enterProjectName();
113
+ projectName = await enterProjectName();
81
114
  }
82
115
 
83
116
  // pushing project
84
- spinner.text = `Pushing new database to project ${project}`;
117
+ spinner.text = `Pushing new database to project ${projectName}`;
85
118
  spinner.start();
86
119
  try {
87
120
  const isPublic = getIsPublicValueFromBuildFlag(publicFlag, privateFlag, password);
88
121
  const { newProject } = await build({
89
- projectName: project,
122
+ projectName,
90
123
  description: removeMd(model.description),
91
124
  isPublic,
92
125
  password,
93
- orgName: org,
126
+ orgName,
94
127
  doc: {
95
128
  content,
96
129
  },
97
130
  shallowSchema: model.schemas,
98
131
  normalizedDatabase: model.normalizedDatabase,
99
132
  dbmlVersion: VERSION,
133
+ clientType: 'cli',
100
134
  }, authConfig);
101
135
  switch (newProject.generalAccessType) {
102
136
  case PROJECT_GENERAL_ACCESS_TYPE.public:
@@ -165,7 +199,7 @@ BuildCommand.description = 'build docs';
165
199
  // dbdocs build ./abc.dbml --project abc --public --private # error
166
200
  // dbdocs build ./abc.dbml --project abc --public --password 123456 # error
167
201
  BuildCommand.flags = {
168
- project: Flags.string({ description: 'project name' }),
202
+ project: Flags.string({ description: '<username>/<project_name> or <project_name>' }),
169
203
  public: Flags.boolean({ description: 'anyone with the URL can access', helpGroup: FLAG_HELP_GROUP.sharing, exclusive: ['private', 'password'] }),
170
204
  private: Flags.boolean({ description: 'only invited people can access', helpGroup: FLAG_HELP_GROUP.sharing, exclusive: ['public', 'password'] }),
171
205
  password: Flags.string({
File without changes
File without changes
File without changes
@@ -2,48 +2,114 @@ const { Command, CliUx } = require('@oclif/core');
2
2
  const chalk = require('chalk');
3
3
  const { vars } = require('../vars');
4
4
  const verifyToken = require('../utils/verifyToken');
5
- const { getProjectsByOrg } = require('../utils/org');
5
+ const { getProjectsByOrg, getProjectUserRolesByOrg } = require('../utils/org');
6
6
  const { getOrg } = require('../utils/org');
7
7
  const { PROJECT_SHARING_TEXT } = require('../utils/constants');
8
8
  const { getProjectUrl } = require('../utils/helper');
9
9
 
10
+ const ROLE_DESCRIPTIONS = {
11
+ viewer: 'View only',
12
+ editor: 'View and edit',
13
+ admin: 'Administrator',
14
+ noAccess: 'No access',
15
+ };
16
+
10
17
  class LsCommand extends Command {
18
+ showProjects (projects, orgName) {
19
+ const [maxUrlWidth, maxUpdatedAtWidth] = projects.reduce((accumulator, project) => {
20
+ const url = getProjectUrl(vars.hostUrl, orgName, project.urlName);
21
+ const updatedAt = (new Date(project.updatedAt)).toLocaleString();
22
+ return [
23
+ accumulator[0] > url.length ? accumulator[0] : url.length,
24
+ accumulator[1] > updatedAt.length ? accumulator[1] : updatedAt.length,
25
+ ];
26
+ }, [3, 12]);
27
+
28
+ this.log(chalk.bold(orgName));
29
+
30
+ CliUx.ux.table(projects, {
31
+ name: {
32
+ minWidth: 20,
33
+ },
34
+ generalAccess: {
35
+ header: 'Access Control',
36
+ minWidth: 20,
37
+ get: (project) => PROJECT_SHARING_TEXT[project.generalAccessType],
38
+ },
39
+ url: {
40
+ minWidth: maxUrlWidth + 2,
41
+ get: (project) => chalk.cyan(getProjectUrl(vars.hostUrl, orgName, project.urlName)),
42
+ },
43
+ updatedAt: {
44
+ minWidth: maxUpdatedAtWidth + 2,
45
+ header: 'Last updated',
46
+ get: (project) => (new Date(project.updatedAt)).toLocaleString(),
47
+ },
48
+ }, {
49
+ printLine: this.log.bind(this),
50
+ });
51
+
52
+ if (!projects.length) CliUx.ux.log('', '(empty)');
53
+ }
54
+
55
+ showSharedProjects (sharedProjectsData) {
56
+ const [maxOrgWidth, maxUrlWidth, maxUpdatedAtWidth, projects] = sharedProjectsData.reduce((accumulator, sharedData) => {
57
+ const { Project: project, Role: role } = sharedData;
58
+
59
+ const url = getProjectUrl(vars.hostUrl, project.Org.name, project.urlName);
60
+ const updatedAt = (new Date(project.updatedAt)).toLocaleString();
61
+
62
+ accumulator[3].push({ ...project, org: project.Org.name, role });
63
+ return [
64
+ accumulator[0] > project.Org.name.length ? accumulator[0] : project.Org.name.length,
65
+ accumulator[1] > url.length ? accumulator[1] : url.length,
66
+ accumulator[2] > updatedAt.length ? accumulator[2] : updatedAt.length,
67
+ accumulator[3],
68
+ ];
69
+ }, [3, 3, 12, []]);
70
+
71
+ this.log(chalk.bold('Shared with me'));
72
+
73
+ CliUx.ux.table(projects, {
74
+ name: {
75
+ minWidth: 20,
76
+ },
77
+ org: {
78
+ header: 'Owner',
79
+ minWidth: maxOrgWidth + 2,
80
+ },
81
+ permission: {
82
+ minWidth: 15,
83
+ get: (project) => ROLE_DESCRIPTIONS[project.role.name],
84
+ },
85
+ url: {
86
+ minWidth: maxUrlWidth + 2,
87
+ get: (project) => chalk.cyan(getProjectUrl(vars.hostUrl, project.org, project.urlName)),
88
+ },
89
+ updatedAt: {
90
+ minWidth: maxUpdatedAtWidth + 2,
91
+ header: 'Last updated',
92
+ get: (project) => (new Date(project.updatedAt)).toLocaleString(),
93
+ },
94
+ }, {
95
+ printLine: this.log.bind(this),
96
+ });
97
+
98
+ if (!projects.length) CliUx.ux.log('', '(empty)');
99
+ }
100
+
11
101
  async run () {
12
102
  try {
13
103
  const authConfig = await verifyToken();
14
104
  const org = await getOrg(authConfig);
15
- const projects = await getProjectsByOrg(org.name, authConfig);
16
- this.log(chalk.bold(org.name));
17
-
18
- const [maxUrlWidth, maxUpdatedAtWidth] = projects.reduce((accumulator, project) => {
19
- const url = getProjectUrl(vars.hostUrl, org.name, project.urlName);
20
- const updatedAt = (new Date(project.updatedAt)).toLocaleString();
21
- return [
22
- accumulator[0] > url.length ? accumulator[0] : url.length,
23
- accumulator[1] > updatedAt.length ? accumulator[1] : updatedAt.length,
24
- ];
25
- }, [3, 12]);
26
-
27
- CliUx.ux.table(projects, {
28
- name: {
29
- minWidth: 20,
30
- },
31
- sharing: {
32
- minWidth: 23,
33
- get: (project) => PROJECT_SHARING_TEXT[project.generalAccessType],
34
- },
35
- url: {
36
- minWidth: maxUrlWidth + 2,
37
- get: (project) => chalk.cyan(getProjectUrl(vars.hostUrl, org.name, project.urlName)),
38
- },
39
- updatedAt: {
40
- minWidth: maxUpdatedAtWidth + 2,
41
- header: 'Last updated',
42
- get: (project) => (new Date(project.updatedAt)).toLocaleString(),
43
- },
44
- }, {
45
- printLine: this.log.bind(this),
46
- });
105
+ const [projects, sharedProjectsData] = await Promise.all([
106
+ getProjectsByOrg(org.name, authConfig),
107
+ getProjectUserRolesByOrg(org.name, authConfig),
108
+ ]);
109
+
110
+ this.showProjects(projects, org.name);
111
+ this.log('\n');
112
+ this.showSharedProjects(sharedProjectsData);
47
113
  } catch (err) {
48
114
  this.error(err);
49
115
  }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/src/index.js CHANGED
File without changes
File without changes
@@ -5,9 +5,9 @@ const PROJECT_GENERAL_ACCESS_TYPE = {
5
5
  };
6
6
 
7
7
  const PROJECT_SHARING_TEXT = {
8
- public: 'Shared URL',
9
- protected: 'Shared URL & password',
10
- restricted: 'Only invited',
8
+ public: 'Public',
9
+ protected: 'Password-protected',
10
+ restricted: 'Private',
11
11
  };
12
12
 
13
13
  const FLAG_HELP_GROUP = {
package/src/utils/data.js CHANGED
File without changes
File without changes
File without changes
@@ -1,11 +1,22 @@
1
+ const { isValidName } = require('../validators/projectName');
2
+
1
3
  const getIsPublicValueFromBuildFlag = (publicFlag, privateFlag, passwordFlag) => {
2
4
  if (publicFlag || passwordFlag) return true;
3
5
  if (privateFlag) return false;
4
6
  return undefined; // 'undefined' means keep the old `isPublic` state
5
7
  };
8
+
9
+ const parseProjectName = (projectName) => {
10
+ if (!isValidName(projectName, true)) return null;
11
+ const middleIdx = projectName.indexOf('/');
12
+ if (middleIdx === -1) return ['', projectName];
13
+ return [projectName.slice(0, middleIdx), projectName.slice(middleIdx + 1)];
14
+ };
15
+
6
16
  const getProjectUrl = (hostUrl, orgName, projectUrl) => `${hostUrl}/${encodeURIComponent(orgName)}/${projectUrl}`;
7
17
 
8
18
  module.exports = {
9
19
  getIsPublicValueFromBuildFlag,
10
20
  getProjectUrl,
21
+ parseProjectName,
11
22
  };
package/src/utils/org.js CHANGED
@@ -9,8 +9,13 @@ async function getProjectsByOrg (orgName, authConfig) {
9
9
  const { data: { org: { projects } } } = await axios.get(`${vars.apiUrl}/orgs/${orgName}/projects`, authConfig);
10
10
  return projects;
11
11
  }
12
+ async function getProjectUserRolesByOrg (orgName, authConfig) {
13
+ const { data } = await axios.get(`${vars.apiUrl}/orgs/${orgName}/project_user_roles`, authConfig);
14
+ return data;
15
+ }
12
16
 
13
17
  module.exports = {
14
18
  getOrg,
15
19
  getProjectsByOrg,
20
+ getProjectUserRolesByOrg,
16
21
  };
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,6 +1,9 @@
1
- const pattern = /^([A-Za-z0-9_\-@.\s]+)$/;
2
- const isValidName = (name) => pattern.test(name);
1
+ const isValidName = (name, allowOrgPattern = false) => {
2
+ const pattern = '([A-Za-z0-9_\\-@.\\s]+)';
3
+ const testPattern = allowOrgPattern ? `^(${pattern}/)?${pattern}$` : `^${pattern}$`;
4
+ return (new RegExp(testPattern)).test(name);
5
+ };
3
6
 
4
7
  module.exports = {
5
- isValidName
6
- }
8
+ isValidName,
9
+ };
File without changes
File without changes
package/src/vars.js CHANGED
File without changes
File without changes