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

Typescriptize Library files #4961

Merged
merged 4 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
27 changes: 26 additions & 1 deletion jsapp/js/actions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,28 @@ interface DuplicateSubmissionCompletedDefinition extends Function {
listen: (callback: (assetUid: string, submissionUid: string, duplicatedSubmission: SubmissionResponse) => void) => Function;
}

interface GetUserDefinition extends Function {
(username: string): void;
completed: GetUserCompletedDefinition;
failed: GenericFailedDefinition;
}

interface GetUserCompletedDefinition extends Function {
(response: AccountResponse): void;
listen: (callback: (response: AccountResponse) => void) => Function;
}

interface SetAssetPublicDefinition extends Function {
(asset: AssetResponse, shouldSetAnonPerms: boolean): void;
completed: SetAssetPublicCompletedDefinition;
failed: GenericFailedDefinition;
}

interface SetAssetPublicCompletedDefinition extends Function {
(assetUid: string, shouldSetAnonPerms: boolean): void;
listen: (callback: (assetUid: string, shouldSetAnonPerms: boolean) => void) => Function;
}

// NOTE: as you use more actions in your ts files, please extend this namespace,
// for now we are defining only the ones we need.
export namespace actions {
Expand Down Expand Up @@ -171,7 +193,9 @@ export namespace actions {
getAssetFiles: GenericDefinition;
};
const hooks: object;
const misc: object;
const misc: {
getUser: GetUserDefinition;
};
const reports: object;
const table: {
updateSettings: TableUpdateSettingsDefinition;
Expand All @@ -184,6 +208,7 @@ export namespace actions {
assignAssetPermission: GenericDefinition;
bulkSetAssetPermissions: GenericDefinition;
getAssetPermissions: GenericDefinition;
setAssetPublic: SetAssetPublicDefinition;
};
const help: {
getInAppMessages: GenericDefinition;
Expand Down
16 changes: 11 additions & 5 deletions jsapp/js/components/assetsTable/assetsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ interface AssetsTableProps {
/** Displays a spinner */
isLoading?: boolean;
/** To display contextual empty message when zero assets. */
emptyMessage?: string;
emptyMessage?: React.ReactNode;
/** List of assets to be displayed. */
assets: AssetResponse[];
/** Number of assets on all pages. */
totalAssets: number;
totalAssets: number | null;
/** List of available filters values. */
metadata?: MetadataResponse; // this type ??
/** Seleceted order column id, one of ASSETS_TABLE_COLUMNS. */
orderColumnId: string;
/** Seleceted order column value. */
orderValue: string;
/** Seleceted order column value. Defaults to "ascending" */
orderValue: OrderDirection | null;
/** Called when user selects a column for odering. */
onOrderChange: OrderChangeCallback;
/** Seleceted filter column, one of ASSETS_TABLE_COLUMNS. */
Expand All @@ -84,7 +84,13 @@ interface AssetsTableState {
}

/**
* Displays a table of assets.
* DEPRECATED-ish (see below)
* Displays a table of assets. This old-ish component is handling three routes:
* - My Library
* - Public Collections
* - Single Collection
* The new and shiny component that handles Projects List is `ProjectsTable`,
* and in the future it should become (if possible) the only one to be used.
*/
export default class AssetsTable extends React.Component<
AssetsTableProps,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
import React from 'react';
import autoBind from 'react-autobind';
import bem from 'js/bem';
import {
getFlatQuestionsList,
renderQuestionTypeIcon,
} from 'js/assetUtils';
import {QUESTION_TYPES} from 'js/constants';
import {ANY_ROW_TYPE_NAMES} from 'js/constants';
import type {FlatQuestion} from 'js/assetUtils';
import type {AssetResponse} from 'js/dataInterface';

interface AssetContentSummaryProps {
asset: AssetResponse;
}

interface AssetContentSummaryState {
isExpanded: boolean;
}

const DISPLAY_LIMIT = 8;

/**
* AKA "Quick Look" component
* AKA "Quick Look" component, it displays a list of questions from given asset.
*/

class AssetContentSummary extends React.Component {
constructor(props){
export default class AssetContentSummary extends React.Component<
AssetContentSummaryProps,
AssetContentSummaryState
> {
constructor(props: AssetContentSummaryProps) {
super(props);
this.state = {
isExpanded: false,
};
autoBind(this);
}

renderQuestion(question, itemIndex) {
renderQuestion(question: FlatQuestion, itemIndex: number) {
const modifiers = ['columns', 'padding-small'];
if (itemIndex !== 0) {
modifiers.push('bordertop');
Expand All @@ -47,9 +57,9 @@ class AssetContentSummary extends React.Component {
);
}

filterRealQuestions(questions) {
filterRealQuestions(questions: FlatQuestion[]) {
return questions.filter((question) => {
return QUESTION_TYPES[question.type];
return Object.values(ANY_ROW_TYPE_NAMES).includes(question.type);
});
}

Expand All @@ -58,7 +68,7 @@ class AssetContentSummary extends React.Component {
}

render() {
if (!this.props.asset) {
if (!this.props.asset?.content?.survey) {
return null;
}

Expand All @@ -82,12 +92,12 @@ class AssetContentSummary extends React.Component {
return (
<React.Fragment>
<bem.FormView__cell m={['box', 'bordered']}>
{items.map(this.renderQuestion)}
{items.map(this.renderQuestion.bind(this))}
</bem.FormView__cell>

{isExpandable &&
<bem.FormView__cell m={['toggle-details']}>
<button onClick={this.toggleExpanded}>
<button onClick={this.toggleExpanded.bind(this)}>
{this.state.isExpanded ? <i className='k-icon k-icon-angle-up'/> : <i className='k-icon k-icon-angle-down'/>}
{this.state.isExpanded ? t('Show less') : t('Show more')}
</button>
Expand All @@ -97,5 +107,3 @@ class AssetContentSummary extends React.Component {
);
}
}

export default AssetContentSummary;
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import React from 'react';
import reactMixin from 'react-mixin';
import autoBind from 'react-autobind';
import Reflux from 'reflux';
import bem from 'js/bem';
import {actions} from 'js/actions';
import sessionStore from 'js/stores/session';
Expand All @@ -10,37 +7,57 @@ import {ASSET_TYPES} from 'js/constants';
import {
notify,
formatTime,
} from 'utils';
} from 'js/utils';
import './assetInfoBox.scss';
import type {AssetResponse, AccountResponse} from 'js/dataInterface';

interface AssetInfoBoxProps {
asset: AssetResponse;
}

interface AssetInfoBoxState {
areDetailsVisible: boolean;
ownerData: AccountResponse | {username: string; date_joined: string} | null;
}

/**
* @prop asset
* Displays some meta information about given asset.
*/
class AssetInfoBox extends React.Component {
constructor(props){
export default class AssetInfoBox extends React.Component<
AssetInfoBoxProps,
AssetInfoBoxState
> {
private unlisteners: Function[] = [];

constructor(props: AssetInfoBoxProps){
super(props);
this.state = {
areDetailsVisible: false,
ownerData: null,
};
autoBind(this);
}

componentDidMount() {
if (!assetUtils.isSelfOwned(this.props.asset)) {
this.listenTo(actions.misc.getUser.completed, this.onGetUserCompleted);
this.listenTo(actions.misc.getUser.failed, this.onGetUserFailed);
this.unlisteners.push(
actions.misc.getUser.completed.listen(this.onGetUserCompleted.bind(this)),
actions.misc.getUser.failed.listen(this.onGetUserFailed.bind(this))
)
actions.misc.getUser(this.props.asset.owner);
} else {
this.setState({ownerData: sessionStore.currentAccount});
}
}

componentWillUnmount() {
this.unlisteners.forEach((clb) => {clb();});
}

toggleDetails() {
this.setState({areDetailsVisible: !this.state.areDetailsVisible});
}

onGetUserCompleted(userData) {
onGetUserCompleted(userData: AccountResponse) {
this.setState({ownerData: userData});
}

Expand Down Expand Up @@ -136,7 +153,7 @@ class AssetInfoBox extends React.Component {
</bem.AssetInfoBox__column>

<bem.AssetInfoBox__column m='toggle'>
<bem.AssetInfoBox__toggle onClick={this.toggleDetails}>
<bem.AssetInfoBox__toggle onClick={this.toggleDetails.bind(this)}>
{this.state.areDetailsVisible ? <i className='k-icon k-icon-angle-up'/> : <i className='k-icon k-icon-angle-down'/>}
{this.state.areDetailsVisible ? t('Hide full details') : t('Show full details')}
</bem.AssetInfoBox__toggle>
Expand All @@ -145,7 +162,3 @@ class AssetInfoBox extends React.Component {
);
}
}

reactMixin(AssetInfoBox.prototype, Reflux.ListenerMixin);

export default AssetInfoBox;
Original file line number Diff line number Diff line change
@@ -1,36 +1,53 @@
import React from 'react';
import autoBind from 'react-autobind';
import bem from 'js/bem';
import {actions} from 'js/actions';
import assetUtils from 'js/assetUtils';
import {ASSET_TYPES} from 'js/constants';
import {
notify
} from 'js/utils';
import {notify} from 'js/utils';
import type {AssetResponse} from 'js/dataInterface';

interface AssetPublicButtonProps {
asset: AssetResponse;
}

interface AssetPublicButtonState {
isPublicPending: boolean;
isAwaitingFreshPermissions: boolean;
}

/**
* @prop asset
* Button for making asset (works only for `collection` type) public or non-public.
*/
class AssetPublicButton extends React.Component {
constructor(props){
export default class AssetPublicButton extends React.Component<
AssetPublicButtonProps,
AssetPublicButtonState
> {
private unlisteners: Function[] = [];

constructor(props: AssetPublicButtonProps) {
super(props);
this.state = {
isPublicPending: false,
isAwaitingFreshPermissions: false
};
autoBind(this);
}

componentDidMount() {
actions.permissions.setAssetPublic.completed.listen(this.onSetAssetPublicCompleted);
actions.permissions.setAssetPublic.failed.listen(this.onSetAssetPublicFailed);
this.unlisteners.push(
actions.permissions.setAssetPublic.completed.listen(this.onSetAssetPublicCompleted.bind(this)),
actions.permissions.setAssetPublic.failed.listen(this.onSetAssetPublicFailed.bind(this))
);
}

componentWillUnmount() {
this.unlisteners.forEach((clb) => {clb();});
}

componentWillReceiveProps() {
this.setState({isAwaitingFreshPermissions: false});
}

onSetAssetPublicCompleted(assetUid) {
onSetAssetPublicCompleted(assetUid: string) {
if (this.props.asset.uid === assetUid) {
this.setState({
isPublicPending: false,
Expand All @@ -39,7 +56,7 @@ class AssetPublicButton extends React.Component {
}
}

onSetAssetPublicFailed(assetUid) {
onSetAssetPublicFailed(assetUid: string) {
if (this.props.asset.uid === assetUid) {
this.setState({isPublicPending: false});
notify(t('Failed to change asset public status.'), 'error');
Expand Down Expand Up @@ -86,7 +103,7 @@ class AssetPublicButton extends React.Component {
{!isPublic &&
<bem.AssetActionButtons__button
m='on'
onClick={this.makePublic}
onClick={this.makePublic.bind(this)}
disabled={this.isSetPublicButtonDisabled()}
>
<i className='k-icon k-icon-globe-alt'/>
Expand All @@ -96,7 +113,7 @@ class AssetPublicButton extends React.Component {
{isPublic &&
<bem.AssetActionButtons__button
m='off'
onClick={this.makePrivate}
onClick={this.makePrivate.bind(this)}
disabled={this.isSetPublicButtonDisabled()}
>
<i className='k-icon k-icon-close'/>
Expand All @@ -107,5 +124,3 @@ class AssetPublicButton extends React.Component {
);
}
}

export default AssetPublicButton;
Loading
Loading