Skip to content

Commit

Permalink
feat!: convert attribute enums to string unions (#2962)
Browse files Browse the repository at this point in the history
All enums used as properties on components have been converted to string union types
Updates doc comments for better doc generation in Storybook
Fixes string casing to match typed string unions

refactor: ViewType is now a string union type and not an enum
  BREAKING CHANGE: ViewType is now a string union type and not an enum

refactor: UserType is now a string union type and not an enum
  BREAKING CHANGE: UserType is now a string union type and not an enum

refactor: PersonType is now a string union type and not an enum
  BREAKING CHANGE: PersonType is now a string union type and not an enum

refactor: GroupType is now a string union type and not an enum
  BREAKING CHANGE: GroupType is now a string union type and not an enum

refactor: groupType property on MgtPeoplePicker is now GroupType[]
  BREAKING CHANGE: groupType property on MgtPeoplePicker is now a GroupType[] not a GroupType that is a bitmask of the desired group types. Developers using the group-type attribute will find the behavior unchanged.

refactor: avatarType renamed to AvatarType and converted to string union type
  BREAKING CHANGE: the avatarType eunm has been renamed to AvatarType for consistency and converted to a string union type

refactor: ResponseType for mgt-get converted to string union type from enum
  BREAKING CHANGE: the ResponseType for mgt-get is now a string union type and not an enum

refactor: PersonCardInteraction is now a string union type and not an enum
  BREAKING CHANGE: PersonCardInteraction is now a string union type and not an enum
  • Loading branch information
gavinbarron committed Jan 24, 2024
1 parent eda4b19 commit 18d0aec
Show file tree
Hide file tree
Showing 41 changed files with 375 additions and 530 deletions.
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ <h2>mgt-login</h2>
</div>
<!-- <mgt-login></mgt-login> -->
<!-- <h2>mgt-person me query two lines card on click with presence</h2> -->
<mgt-person person-query="me" view="twoLines" person-card="hover" show-presence></mgt-person>
<mgt-person person-query="me" view="twolines" person-card="hover" show-presence></mgt-person>
<mgt-person-card person-query="me"></mgt-person-card>
<!-- <mgt-person person-query="me" view="twoLines" person-card="hover" show-presence></mgt-person> -->
<!-- <mgt-person person-query="me" view="twolines" person-card="hover" show-presence></mgt-person> -->
<mgt-person fetch-image person-details='{
"id": "a2a36b00-b196-4286-adfc-7c1bedbffa39",
"deletedDateTime": null,
Expand Down
30 changes: 13 additions & 17 deletions packages/mgt-components/src/components/PersonCardInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,24 @@
* -------------------------------------------------------------------------------------------
*/

/* istanbul ignore file */
const interactions = ['none', 'hover', 'click'] as const;

/**
* Defines how a person card is shown when a user interacts with
* a person component
*
* @export
* @enum {number}
*/
export enum PersonCardInteraction {
/**
* Don't show person card
*/
none,
export type PersonCardInteraction = (typeof interactions)[number];

/**
* Show person card on hover
*/
hover,
export const isPersonCardInteraction = (value: unknown): value is PersonCardInteraction =>
typeof value === 'string' && interactions.includes(value as PersonCardInteraction);

/**
* Show person card on click
*/
click
}
export const personCardConverter = (
value: string,
defaultValue: PersonCardInteraction = 'none'
): PersonCardInteraction => {
if (isPersonCardInteraction(value)) {
return value;
}
return defaultValue;
};
6 changes: 6 additions & 0 deletions packages/mgt-components/src/components/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ import './mgt-search-results/mgt-search-results';
import './mgt-theme-toggle/mgt-theme-toggle';
import './sub-components/mgt-spinner/mgt-spinner';

// type exports
import type { PersonCardInteraction } from './PersonCardInteraction';

export { PersonCardInteraction };

// component exports
export * from './mgt-agenda/mgt-agenda';
export * from './mgt-file/mgt-file';
export * from './mgt-file-list/mgt-file-list';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
} from '../../graph/graph.files';
import './mgt-file-upload/mgt-file-upload';
import { getSvg, SvgIcon } from '../../utils/SvgHelper';
import { OfficeGraphInsightString, ViewType } from '../../graph/types';
import { OfficeGraphInsightString, ViewType, viewTypeConverter } from '../../graph/types';
import { styles } from './mgt-file-list-css';
import { strings } from './strings';
import { MgtFile, registerMgtFileComponent } from '../mgt-file/mgt-file';
Expand Down Expand Up @@ -245,29 +245,17 @@ export class MgtFileList extends MgtTemplatedTaskComponent implements CardSectio
public insightType: OfficeGraphInsightString;

/**
* Sets what data to be rendered (file icon only, oneLine, twoLines threeLines).
* Default is 'threeLines'.
* Sets what data to be rendered (file icon only, oneline, twolines threelines).
* Default is 'threelines'.
*
* @type {ViewType}
* @memberof MgtFileList
*/
@property({
attribute: 'item-view',
converter: value => {
if (!value || value.length === 0) {
return ViewType.threelines;
}

value = value.toLowerCase();

if (typeof ViewType[value] === 'undefined') {
return ViewType.threelines;
} else {
return ViewType[value] as ViewType;
}
}
converter: value => viewTypeConverter(value, 'threelines')
})
public itemView = ViewType.threelines;
public itemView: ViewType = 'threelines';

/**
* allows developer to provide file type to filter the list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,11 @@ const isDataTransferItem = (item: DataTransferItem | File): item is DataTransfer
('getAsFile' in item && typeof item.getAsFile === 'function') ||
('webkitGetAsEntry' in item && typeof item.webkitGetAsEntry === 'function');

const conflictBehaviors = ['rename', 'replace'] as const;
/**
* Upload conflict behavior status
*/
export const enum MgtFileUploadConflictBehavior {
rename,
replace
}
export type MgtFileUploadConflictBehavior = (typeof conflictBehaviors)[number];

/**
* MgtFileUpload upload item lifecycle object.
Expand Down Expand Up @@ -243,6 +241,13 @@ export const registerMgtFileUploadComponent = () => {
registerComponent('file-upload', MgtFileUpload);
};

const calculateConflictBehavior = (behavior: (number | true | MgtFileUploadConflictBehavior)[]) => {
if (behavior?.length > 1) {
return behavior[1] === 'replace' ? 'replace' : 'rename';
}
return null;
};

/**
* A component to upload files to OneDrive or SharePoint Sites
*
Expand Down Expand Up @@ -429,7 +434,7 @@ export class MgtFileUpload extends MgtBaseComponent {
name: fileItem.fullPath.substring(1, fileItem.fullPath.lastIndexOf('/')),
folder: 'Folder'
}}
.view=${ViewType.oneline}
view="oneline"
class="mgt-file-item">
</mgt-file>
</div>
Expand Down Expand Up @@ -686,7 +691,7 @@ export class MgtFileUpload extends MgtBaseComponent {
if (file.size > this.fileUploadList.maxFileSize * 1024) {
acceptFile = false;
if (this._maximumFileSize === false) {
const maximumFileSize: (number | true)[] = await this.getFileUploadStatus(
const maximumFileSize: (number | true | string)[] = await this.getFileUploadStatus(
file,
fullPath,
'MaxFileSize',
Expand All @@ -711,7 +716,7 @@ export class MgtFileUpload extends MgtBaseComponent {
) {
acceptFile = false;
if (this._excludedFileType === false) {
const excludedFileType: (number | true)[] = await this.getFileUploadStatus(
const excludedFileType: (number | true | string)[] = await this.getFileUploadStatus(
file,
fullPath,
'ExcludedFileType',
Expand All @@ -729,7 +734,7 @@ export class MgtFileUpload extends MgtBaseComponent {

// Collect accepted files
if (acceptFile) {
const conflictBehavior: (number | true)[] = await this.getFileUploadStatus(
const conflictBehavior: (number | true | MgtFileUploadConflictBehavior)[] = await this.getFileUploadStatus(
file,
fullPath,
'Upload',
Expand All @@ -752,10 +757,10 @@ export class MgtFileUpload extends MgtBaseComponent {
name: file.name
},
fullPath,
conflictBehavior: conflictBehavior !== null ? (conflictBehavior[1] ? 1 : 0) : null,
conflictBehavior: calculateConflictBehavior(conflictBehavior),
iconStatus: null,
percent: 1,
view: ViewType.image,
view: 'image',
completed,
maxSize: this._maxChunkSize,
minSize: 0
Expand Down Expand Up @@ -793,7 +798,7 @@ export class MgtFileUpload extends MgtBaseComponent {
fullPath: string,
DialogStatus: string,
fileUploadList: MgtFileUploadConfig
) {
): Promise<(number | true | MgtFileUploadConflictBehavior)[]> {
const fileUploadDialog: HTMLElement = this.renderRoot.querySelector('#file-upload-dialog');

switch (DialogStatus) {
Expand All @@ -811,7 +816,7 @@ export class MgtFileUpload extends MgtBaseComponent {
this._dialogSecondaryButton = strings.buttonKeep;
await super.requestStateUpdate(true);

return new Promise<number[]>(resolve => {
return new Promise<(number | MgtFileUploadConflictBehavior)[]>(resolve => {
const fileUploadDialogClose: HTMLElement = this.renderRoot.querySelector('.file-upload-dialog-close');
const fileUploadDialogOk: HTMLElement = this.renderRoot.querySelector('.file-upload-dialog-ok');
const fileUploadDialogCancel: HTMLElement = this.renderRoot.querySelector('.file-upload-dialog-cancel');
Expand All @@ -822,13 +827,13 @@ export class MgtFileUpload extends MgtBaseComponent {
// Replace File
const onOkDialogClick = () => {
fileUploadDialog.classList.remove('visible');
resolve([fileUploadDialogCheck.checked ? 1 : 0, MgtFileUploadConflictBehavior.replace]);
resolve([fileUploadDialogCheck.checked ? 1 : 0, 'replace']);
};

// Rename File
const onCancelDialogClick = () => {
fileUploadDialog.classList.remove('visible');
resolve([fileUploadDialogCheck.checked ? 1 : 0, MgtFileUploadConflictBehavior.rename]);
resolve([fileUploadDialogCheck.checked ? 1 : 0, 'rename']);
};

// Cancel File
Expand Down Expand Up @@ -1010,13 +1015,10 @@ export class MgtFileUpload extends MgtBaseComponent {
if (fileItem.file.size < this._maxChunkSize) {
try {
if (!fileItem.completed) {
if (
fileItem.conflictBehavior === null ||
fileItem.conflictBehavior === MgtFileUploadConflictBehavior.replace
) {
if (fileItem.conflictBehavior === null || fileItem.conflictBehavior === 'replace') {
graphQuery = `${this.getGrapQuery(fileItem.fullPath)}:/content`;
}
if (fileItem.conflictBehavior === MgtFileUploadConflictBehavior.rename) {
if (fileItem.conflictBehavior === 'rename') {
graphQuery = `${this.getGrapQuery(fileItem.fullPath)}:/content?@microsoft.graph.conflictBehavior=rename`;
}
fileItem.driveItem = await sendFileContent(graph, graphQuery, fileItem.file);
Expand Down Expand Up @@ -1114,7 +1116,7 @@ export class MgtFileUpload extends MgtBaseComponent {
void super.requestStateUpdate(true);
setTimeout(() => {
fileUpload.iconStatus = getSvg(SvgIcon.Success);
fileUpload.view = ViewType.twolines;
fileUpload.view = 'twolines';
fileUpload.fieldUploadResponse = 'lastModifiedDateTime';
fileUpload.completed = true;
void super.requestStateUpdate(true);
Expand All @@ -1130,7 +1132,7 @@ export class MgtFileUpload extends MgtBaseComponent {
protected setUploadFail(fileUpload: MgtFileUploadItem, errorMessage: string) {
setTimeout(() => {
fileUpload.iconStatus = getSvg(SvgIcon.Fail);
fileUpload.view = ViewType.twolines;
fileUpload.view = 'twolines';
fileUpload.driveItem.description = errorMessage;
fileUpload.fieldUploadResponse = 'description';
fileUpload.completed = true;
Expand Down
31 changes: 10 additions & 21 deletions packages/mgt-components/src/components/mgt-file/mgt-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
getUserInsightsDriveItemById
} from '../../graph/graph.files';
import { formatBytes, getRelativeDisplayDate } from '../../utils/Utils';
import { OfficeGraphInsightString, ViewType } from '../../graph/types';
import { OfficeGraphInsightString, ViewType, viewTypeConverter } from '../../graph/types';
import { getFileTypeIconUriByExtension } from '../../styles/fluent-icons';
import { getSvg, SvgIcon } from '../../utils/SvgHelper';
import { strings } from './strings';
Expand Down Expand Up @@ -246,27 +246,16 @@ export class MgtFile extends MgtTemplatedTaskComponent {
@property({ attribute: 'line3-property' }) public line3Property: string;

/**
* Sets what data to be rendered (file icon only, oneLine, twoLines threeLines).
* Default is 'threeLines'.
* Sets what data will be rendered.
* Valid options are 'image', 'oneline', 'twolines', 'threelines', or 'fourlines'
* Default is 'threelines'.
*
* @type {ViewType}
* @memberof MgtFile
*/
@property({
attribute: 'view',
converter: value => {
if (!value || value.length === 0) {
return ViewType.threelines;
}

value = value.toLowerCase();

if (typeof ViewType[value] === 'undefined') {
return ViewType.threelines;
} else {
return ViewType[value] as ViewType;
}
}
converter: value => viewTypeConverter(value, 'threelines')
})
public view: ViewType;

Expand Down Expand Up @@ -304,7 +293,7 @@ export class MgtFile extends MgtTemplatedTaskComponent {
this.line1Property = 'name';
this.line2Property = 'lastModifiedDateTime';
this.line3Property = 'size';
this.view = ViewType.threelines;
this.view = 'threelines';
}

public renderContent = () => {
Expand Down Expand Up @@ -397,13 +386,13 @@ export class MgtFile extends MgtTemplatedTaskComponent {
* @memberof MgtFile
*/
protected renderDetails(driveItem: DriveItem): TemplateResult {
if (!driveItem || this.view === ViewType.image) {
if (!driveItem || this.view === 'image') {
return html``;
}

const details: TemplateResult[] = [];

if (this.view > ViewType.image) {
if (this.view > 'image') {
const text = this.getTextFromProperty(driveItem, this.line1Property);
if (text) {
details.push(html`
Expand All @@ -412,7 +401,7 @@ export class MgtFile extends MgtTemplatedTaskComponent {
}
}

if (this.view > ViewType.oneline) {
if (this.view > 'oneline') {
const text = this.getTextFromProperty(driveItem, this.line2Property);
if (text) {
details.push(html`
Expand All @@ -421,7 +410,7 @@ export class MgtFile extends MgtTemplatedTaskComponent {
}
}

if (this.view > ViewType.twolines) {
if (this.view > 'twolines') {
const text = this.getTextFromProperty(driveItem, this.line3Property);
if (text) {
details.push(html`
Expand Down
24 changes: 10 additions & 14 deletions packages/mgt-components/src/components/mgt-get/mgt-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,18 @@ interface ImageValue {
export const isCollectionResponse = (value: unknown): value is CollectionResponse<unknown> =>
Array.isArray((value as CollectionResponse<unknown>)?.value);

const responseTypes = ['json', 'image'] as const;
/**
* Enumeration to define what types of query are available
*
* @export
* @enum {string}
*/
export enum ResponseType {
/**
* Fetches a call as JSON
*/
json = 'json',

/**
* Fetches a call as image
*/
image = 'image'
}
export type ResponseType = (typeof responseTypes)[number];
const isResponseType = (value: unknown): value is ResponseType =>
typeof value === 'string' && responseTypes.includes(value as ResponseType);
const responseTypeConverter = (value: string, defaultValue: ResponseType = 'json'): ResponseType =>
isResponseType(value) ? value : defaultValue;

/**
* Defines the expiration time
Expand Down Expand Up @@ -147,9 +142,10 @@ export class MgtGet extends MgtTemplatedTaskComponent {
@property({
attribute: 'type',
reflect: true,
type: ResponseType
type: String,
converter: value => responseTypeConverter(value, 'json')
})
public type: ResponseType = ResponseType.json;
public type: ResponseType = 'json';

/**
* Maximum number of pages to get for the resource
Expand Down Expand Up @@ -367,7 +363,7 @@ export class MgtGet extends MgtTemplatedTaskComponent {
request = request.middlewareOptions(prepScopes(this.scopes));
}

if (this.type === ResponseType.json) {
if (this.type === 'json') {
response = (await request.get()) as CollectionResponse<Entity> | Entity;

if (isDeltaLink && isCollectionResponse(this.response) && isCollectionResponse(response)) {
Expand Down
Loading

0 comments on commit 18d0aec

Please sign in to comment.