Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added internalName option for spo field commands #6379

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions docs/docs/cmd/spo/field/field-get.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ m365 spo field get [options]
: Server- or web-relative URL of the list where the field is located. Specify either `listTitle`, `listId` or `listUrl`.

`-i, --id [id]`
: The ID of the field to retrieve. Specify `id` or `title` but not both.
: The ID of the field to retrieve. Specify either `id`, `title` or `internalName`.

`-t, --title [title]`
: The display name (case-sensitive) of the field to retrieve. Specify `id` or `title` but not both.
: The display name (case-sensitive) of the field to retrieve. Specify either `id`, `title` or `internalName`.
```

`--internalName [internalName]`
: The internal name (case-sensitive) of the field to retrieve. Specify either `id`, `title` or `internalName`.
```

<Global />
Expand All @@ -56,6 +60,12 @@ Retrieves list column by display name located in the specified site. Retrieves t
m365 spo field get --webUrl https://contoso.sharepoint.com/sites/contoso-sales --listUrl "Lists/Events" --title "Title"
```

Retrieves list column by internal name located in the specified site. Retrieves the list by its url.

```sh
m365 spo field get --webUrl https://contoso.sharepoint.com/sites/contoso-sales --listUrl "Lists/Events" --internalName "Title"
```

## Response

<Tabs>
Expand Down
15 changes: 12 additions & 3 deletions docs/docs/cmd/spo/field/field-remove.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ m365 spo field remove [options]
: Server- or web-relative URL of the list where the field is located. Specify either `listTitle`, `listId` or `listUrl`.

`-i, --id [id]`
: The ID of the field to remove. Specify either `id`, `title`, or `group`.
: The ID of the field to remove. Specify either `id`, `title`, `internalName`, or `group`.

`-t, --title [title]`
: The display name (case-sensitive) of the field to remove. Specify either `id`, `title`, or `group`.
: The display name (case-sensitive) of the field to remove. Specify either `id`, `title`, `internalName`, or `group`.

`--internalName [internalName]`
: The internal name (case-sensitive) of the field to remove. Specify either `id`, `title`, `internalName`, or `group`.

`-g, --group [group]`
: Delete all fields from this group (case-sensitive). Specify either `id`, `title`, or `group`.
: Delete all fields from this group (case-sensitive). Specify either `id`, `title`, `internalName`, or `group`.

`-f, --force`
: Don't prompt for confirming removing the field.
Expand Down Expand Up @@ -60,6 +63,12 @@ Remove the list column with the specified display name, located in the specified
m365 spo field remove --webUrl https://contoso.sharepoint.com/sites/contoso-sales --listUrl "Lists/Events" --title "Title"
```

Remove the list column with the specified display name, located in the specified site. Retrieves the list by its url.

```sh
m365 spo field remove --webUrl https://contoso.sharepoint.com/sites/contoso-sales --listUrl "Lists/Events" --internalName "Title"
```

Remove all site columns from the specified group.

```sh
Expand Down
20 changes: 17 additions & 3 deletions docs/docs/cmd/spo/field/field-set.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ m365 spo field set [options]
: Server- or site-relative URL of the list where the field is located (if list column). Specify either `listTitle`, `listId` or `listUrl`.

`-i, --id [id]`
: ID of the field to update. Specify either `id` or `title` but not both.
: ID of the field to update. Specify either `id`, `title`, or 'internalName' but not all.

`-t, --title [title]`
: Title or internal name of the field to update. Specify either `id` or `title` but not both.
: Title of the field to update. Specify either `id`, `title`, or 'internalName' but not all.

`--internalName [internalName]`
: Internal name of the field to update. Specify either `id`, `title`, or 'internalName' but not all.

`--updateExistingLists`
: Set, to push the update to existing lists. Otherwise, the changes will apply to new lists only.
Expand All @@ -51,6 +54,12 @@ When updating column formatting for a field with the `--CustomFormatter` option,

Update the title of the site column specified by its internal name and push changes to existing lists.

```sh
m365 spo field set --webUrl https://contoso.sharepoint.com/sites/project-x --internalName 'MyColumn' --updateExistingLists --Title 'My column'
```

Update the title of the site column specified by its title and push changes to existing lists.

```sh
m365 spo field set --webUrl https://contoso.sharepoint.com/sites/project-x --title 'MyColumn' --updateExistingLists --Title 'My column'
```
Expand All @@ -67,11 +76,16 @@ Update the description of a column specified by the ID on a list retrieved by th
m365 spo field set --webUrl https://contoso.sharepoint.com/sites/project-x --listUrl '/sites/project-x/Lists/My List' --id 330f29c5-5c4c-465f-9f4b-7903020ae1ce --Description 'My column Description'
```

Update column formatting of the specified list column.
Update column formatting of the specified list column based on title.

```sh
m365 spo field set --webUrl https://contoso.sharepoint.com/sites/project-x --listTitle 'My List' --title 'MyColumn' --CustomFormatter '{"schema":"https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json", "elmType": "div", "txtContent": "@currentField"}'
```
Update column formatting of the specified list column based on internalName.

```sh
m365 spo field set --webUrl https://contoso.sharepoint.com/sites/project-x --listTitle 'My List' --internalName 'MyColumn' --CustomFormatter '{"schema":"https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json", "elmType": "div", "txtContent": "@currentField"}'
```

## Response

Expand Down
45 changes: 45 additions & 0 deletions src/m365/spo/commands/field/field-get.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,51 @@ describe(commands.FIELD_GET, () => {
assert.strictEqual(getStub.lastCall.args[0].url, 'https://contoso.sharepoint.com/sites/portal/_api/web/lists(guid\'03e45e84-1992-4d42-9116-26f756012634\')/fields/getbyinternalnameortitle(\'Title\')');
});

it('should call the correct GET url when field internalName and list title specified (verbose)', async () => {
const getStub = sinon.stub(request, 'get').callsFake(async (opts) => {
if ((opts.url as string).indexOf(`/_api/web/lists`) > -1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, let's use full url's

return {
"Id": "03e45e84-1992-4d42-9116-26f756012634"
};
}

throw 'Invalid request';
});

await command.action(logger, { options: { debug: true, verbose: true, webUrl: 'https://contoso.sharepoint.com/sites/portal', internalName: 'Title', listTitle: 'Documents' } });
assert.strictEqual(getStub.lastCall.args[0].url, 'https://contoso.sharepoint.com/sites/portal/_api/web/lists/getByTitle(\'Documents\')/fields/getbyinternalnameortitle(\'Title\')');
});

it('should call the correct GET url when field internalName and list title specified', async () => {
const getStub = sinon.stub(request, 'get').callsFake(async (opts) => {
if ((opts.url as string).indexOf(`/_api/web/lists`) > -1) {
return {
"Id": "03e45e84-1992-4d42-9116-26f756012634"
};
}

throw 'Invalid request';
});

await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/portal', internalName: 'Title', listTitle: 'Documents' } });
assert.strictEqual(getStub.lastCall.args[0].url, 'https://contoso.sharepoint.com/sites/portal/_api/web/lists/getByTitle(\'Documents\')/fields/getbyinternalnameortitle(\'Title\')');
});

it('should call the correct GET url when field internalName and list url specified', async () => {
const getStub = sinon.stub(request, 'get').callsFake(async (opts) => {
if ((opts.url as string).indexOf(`/_api/web/lists`) > -1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we please use full URL's instead of using indexOf please? Please do this for all your tests

return {
"Id": "03e45e84-1992-4d42-9116-26f756012634"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please let's use single quotes

};
}

throw 'Invalid request';
});

await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com/sites/portal', internalName: 'Title', listId: '03e45e84-1992-4d42-9116-26f756012634' } });
assert.strictEqual(getStub.lastCall.args[0].url, 'https://contoso.sharepoint.com/sites/portal/_api/web/lists(guid\'03e45e84-1992-4d42-9116-26f756012634\')/fields/getbyinternalnameortitle(\'Title\')');
});

it('correctly handles site column not found', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if ((opts.url as string).indexOf(`/_api/web/fields/getbyid('03e45e84-1992-4d42-9116-26f756012634')`) > -1) {
Expand Down
12 changes: 10 additions & 2 deletions src/m365/spo/commands/field/field-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ interface Options extends GlobalOptions {
listUrl?: string;
id?: string;
title?: string;
internalName?: string;
}

class SpoFieldGetCommand extends SpoCommand {
Expand Down Expand Up @@ -45,7 +46,8 @@ class SpoFieldGetCommand extends SpoCommand {
listTitle: typeof args.options.listTitle !== 'undefined',
listUrl: typeof args.options.listUrl !== 'undefined',
id: typeof args.options.id !== 'undefined',
title: typeof args.options.title !== 'undefined'
title: typeof args.options.title !== 'undefined',
internalName: typeof args.options.internalName !== 'undefined'
});
});
}
Expand All @@ -69,6 +71,9 @@ class SpoFieldGetCommand extends SpoCommand {
},
{
option: '-t, --title [title]'
},
{
option: '--internalName [internalName]'
}
);
}
Expand All @@ -95,7 +100,7 @@ class SpoFieldGetCommand extends SpoCommand {
}

#initOptionSets(): void {
this.optionSets.push({ options: ['id', 'title'] });
this.optionSets.push({ options: ['id', 'title', 'internalName'] });
}

public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
Expand All @@ -117,6 +122,9 @@ class SpoFieldGetCommand extends SpoCommand {
if (args.options.id) {
fieldRestUrl = `/getbyid('${formatting.encodeQueryParameter(args.options.id)}')`;
}
else if (args.options.internalName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we not do something like:

Suggested change
else if (args.options.internalName) {
else {
fieldRestUrl = `/getbyinternalnameortitle('${formatting.encodeQueryParameter(args.options.internalName || args.options.title)}')`;
}

fieldRestUrl = `/getbyinternalnameortitle('${formatting.encodeQueryParameter(args.options.internalName as string)}')`;
}
else {
fieldRestUrl = `/getbyinternalnameortitle('${formatting.encodeQueryParameter(args.options.title as string)}')`;
}
Expand Down
59 changes: 58 additions & 1 deletion src/m365/spo/commands/field/field-remove.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ describe(commands.FIELD_REMOVE, () => {
assert(promptIssued);
});

it('prompts before removing field when confirmation argument not passed (internalName)', async () => {
await command.action(logger, { options: { internalName: 'myfield1', webUrl: 'https://contoso.sharepoint.com' } });

assert(promptIssued);
});

it('prompts before removing list column when confirmation argument not passed (internalName)', async () => {
await command.action(logger, { options: { internalName: 'myfield1', webUrl: 'https://contoso.sharepoint.com', listTitle: 'My List' } });

assert(promptIssued);
});

it('aborts removing field when prompt not confirmed', async () => {
sinonUtil.restore(cli.promptForConfirmation);
sinon.stub(cli, 'promptForConfirmation').resolves(false);
Expand Down Expand Up @@ -454,6 +466,51 @@ describe(commands.FIELD_REMOVE, () => {
assert.strictEqual(getStub.lastCall.args[0].url, 'https://contoso.sharepoint.com/sites/portal/_api/web/lists(guid\'03e45e84-1992-4d42-9116-26f756012634\')/fields/getbyinternalnameortitle(\'Title\')');
});

it('calls the correct get url when field internalName and list title specified (verbose)', async () => {
const getStub = sinon.stub(request, 'post').callsFake(async (opts) => {
if ((opts.url as string).indexOf(`/_api/web/lists`) > -1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, let's use full URLs

return {
"Id": "03e45e84-1992-4d42-9116-26f756012634"
};
}

throw 'Invalid request';
});

await command.action(logger, { options: { debug: true, verbose: true, webUrl: 'https://contoso.sharepoint.com/sites/portal', internalName: 'Title', listTitle: 'Documents', force: true } });
assert.strictEqual(getStub.lastCall.args[0].url, 'https://contoso.sharepoint.com/sites/portal/_api/web/lists/getByTitle(\'Documents\')/fields/getbyinternalnameortitle(\'Title\')');
});

it('calls the correct get url when field internalName and list title specified', async () => {
const getStub = sinon.stub(request, 'post').callsFake(async (opts) => {
if ((opts.url as string).indexOf(`/_api/web/lists`) > -1) {
return {
"Id": "03e45e84-1992-4d42-9116-26f756012634"
};
}

throw 'Invalid request';
});

await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/portal', internalName: 'Title', listTitle: 'Documents', force: true } });
assert.strictEqual(getStub.lastCall.args[0].url, 'https://contoso.sharepoint.com/sites/portal/_api/web/lists/getByTitle(\'Documents\')/fields/getbyinternalnameortitle(\'Title\')');
});

it('calls the correct get url when field internalName and list url specified', async () => {
const getStub = sinon.stub(request, 'post').callsFake(async (opts) => {
if ((opts.url as string).indexOf(`/_api/web/lists`) > -1) {
return {
"Id": "03e45e84-1992-4d42-9116-26f756012634"
};
}

throw 'Invalid request';
});

await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com/sites/portal', internalName: 'Title', listId: '03e45e84-1992-4d42-9116-26f756012634', force: true } });
assert.strictEqual(getStub.lastCall.args[0].url, 'https://contoso.sharepoint.com/sites/portal/_api/web/lists(guid\'03e45e84-1992-4d42-9116-26f756012634\')/fields/getbyinternalnameortitle(\'Title\')');
});

it('correctly handles site column not found', async () => {
const error = {
error: {
Expand Down Expand Up @@ -534,7 +591,7 @@ describe(commands.FIELD_REMOVE, () => {
assert(containsTypeOption);
});

it('fails validation if both id and title options are not passed', async () => {
it('fails validation if either of id, title and internalName options are not passed', async () => {
sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => {
if (settingName === settingsNames.prompt) {
return false;
Expand Down
12 changes: 9 additions & 3 deletions src/m365/spo/commands/field/field-remove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface Options extends GlobalOptions {
group?: string;
listTitle?: string;
title?: string;
internalName?: string;
listUrl?: string;
webUrl: string;
}
Expand Down Expand Up @@ -50,6 +51,7 @@ class SpoFieldRemoveCommand extends SpoCommand {
id: typeof args.options.id !== 'undefined',
group: typeof args.options.group !== 'undefined',
title: typeof args.options.title !== 'undefined',
internalName: typeof args.options.internalName !== 'undefined',
force: (!(!args.options.force)).toString()
});
});
Expand All @@ -75,6 +77,9 @@ class SpoFieldRemoveCommand extends SpoCommand {
{
option: '-t, --title [title]'
},
{
option: '--internalName [internalName]'
},
{
option: '-g, --group [group]'
},
Expand Down Expand Up @@ -106,7 +111,7 @@ class SpoFieldRemoveCommand extends SpoCommand {
}

#initOptionSets(): void {
this.optionSets.push({ options: ['id', 'title', 'group'] });
this.optionSets.push({ options: ['id', 'title', 'internalName', 'group'] });
}

public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
Expand Down Expand Up @@ -191,7 +196,8 @@ class SpoFieldRemoveCommand extends SpoCommand {
}
else {
try {
await removeField(listRestUrl, args.options.id, args.options.title);
const columnName: string | undefined = args.options.title ? args.options.title : args.options.internalName;
await removeField(listRestUrl, args.options.id, columnName);
// REST post call doesn't return anything
}
catch (err: any) {
Expand All @@ -204,7 +210,7 @@ class SpoFieldRemoveCommand extends SpoCommand {
await prepareRemoval();
}
else {
const confirmMessage: string = `Are you sure you want to remove the ${args.options.group ? 'fields' : 'field'} ${args.options.id || args.options.title || 'from group ' + args.options.group} ${messageEnd}?`;
const confirmMessage: string = `Are you sure you want to remove the ${args.options.group ? 'fields' : 'field'} ${args.options.id || args.options.title || args.options.internalName || 'from group ' + args.options.group} ${messageEnd}?`;

const result = await cli.promptForConfirmation({ message: confirmMessage });

Expand Down
Loading