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

Issues/215 #219

Merged
merged 8 commits into from
May 3, 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
2 changes: 1 addition & 1 deletion assets/styles/scss/components/project/_ProjectSection.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
color: color(grey-dark);
}

ol.tasks {
> ol.tasks {
list-style-type: none;
margin: 0;
padding: 0;
Expand Down
24 changes: 24 additions & 0 deletions assets/styles/scss/components/task/_TaskListItem.scss
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,30 @@
}
}//.main

.subtasks {

ol.tasks {
list-style-type: none;
margin: 0;
padding: 0;
border-radius: 10px;
border: 2px solid color(grey-lighter);
background: color(white);
overflow: hidden;

> li {

&:first-child {
border-top: none;
}

&:last-child {
border-bottom: none;
}
}
}
}

.subtask-count {
display: flex;
flex-wrap: nowrap;
Expand Down
35 changes: 35 additions & 0 deletions assets/styles/scss/components/task/_TaskSingleAsync.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@import '../../abstracts/colors';
@import '../../abstracts/animated';

//----------------------

.ptc-TaskSingleAsync {

.ptc-loader {
padding: 1em 2em;
border-radius: 10px;
border: 2px dashed color(grey-light);
background: color(white);
color: color(grey-dark);

@include loader;
}

.ptc-error {
padding: 1em 2em;
text-align: center;
border-radius: 10px;
border: 2px solid color(danger-light);
background: color(danger-lightest);
color: #b20000;
}

> .ptc-TaskListItem {
margin: 0;
padding: 0;
border-radius: 10px;
border: 2px solid color(grey-lighter);
background: color(white);
overflow: hidden;
}
}//.ptc-TaskSingleAsync
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#### Added

- New shortcode `[ptc_asana_task]` to display an individual Asana task.
- Automation Actions now support dynamically pinning the newly created Asana task to the WordPress post which triggered its creation. Clear the "Pin to Post" input field value to see both available options, `{post.ID}` and `{post.post_parent}`.

#### Changed
Expand Down
14 changes: 7 additions & 7 deletions completionist.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,42 +44,42 @@
*
* @since 3.0.0
*/
define( __NAMESPACE__ . '\PLUGIN_FILE', __FILE__ );
define( 'PTC_Completionist\PLUGIN_FILE', __FILE__ );

/**
* The full file path to this plugin's directory ending with a slash.
*
* @since 3.0.0
*/
define( __NAMESPACE__ . '\PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
define( 'PTC_Completionist\PLUGIN_PATH', plugin_dir_path( __FILE__ ) );

/**
* This plugin's current version.
*
* @since 3.0.0
*/
define( __NAMESPACE__ . '\PLUGIN_VERSION', get_file_data( __FILE__, array( 'Version' => 'Version' ), 'plugin' )['Version'] );
define( 'PTC_Completionist\PLUGIN_VERSION', get_file_data( __FILE__, array( 'Version' => 'Version' ), 'plugin' )['Version'] );

/**
* This plugin's basename.
*
* @since 3.0.0
*/
define( __NAMESPACE__ . '\PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
define( 'PTC_Completionist\PLUGIN_BASENAME', plugin_basename( __FILE__ ) );

/**
* This plugin's directory basename.
*
* @since 3.2.0
*/
define( __NAMESPACE__ . '\PLUGIN_SLUG', dirname( PLUGIN_BASENAME ) );
define( 'PTC_Completionist\PLUGIN_SLUG', dirname( PLUGIN_BASENAME ) );

/**
* The full url to this plugin's directory, NOT ending with a slash.
*
* @since 3.0.0
*/
define( __NAMESPACE__ . '\PLUGIN_URL', plugins_url( '', __FILE__ ) );
define( 'PTC_Completionist\PLUGIN_URL', plugins_url( '', __FILE__ ) );

/**
* The namespace for all v1 REST API routes registered by this plugin.
Expand All @@ -88,7 +88,7 @@
*
* @var string REST_API_NAMESPACE_V1
*/
define( __NAMESPACE__ . '\REST_API_NAMESPACE_V1', PLUGIN_SLUG . '/v1' );
define( 'PTC_Completionist\REST_API_NAMESPACE_V1', PLUGIN_SLUG . '/v1' );

/* REGISTER PLUGIN FUNCTIONS ---------------------- */

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
},
"scripts": {
"wp-env": "wp-env",
"build": "wp-scripts build src/index_DashboardWidget.jsx src/index_Automations.jsx src/index_BlockEditor.jsx src/index_ShortcodeAsanaProject.jsx src/index_PinnedTasksMetabox.jsx --output-path=build && npm run styles",
"start": "wp-scripts start src/index_DashboardWidget.jsx src/index_Automations.jsx src/index_BlockEditor.jsx src/index_ShortcodeAsanaProject.jsx src/index_PinnedTasksMetabox.jsx --output-path=build",
"build": "wp-scripts build src/index_DashboardWidget.jsx src/index_Automations.jsx src/index_BlockEditor.jsx src/index_ShortcodeAsanaProject.jsx src/index_ShortcodeAsanaTask.jsx src/index_PinnedTasksMetabox.jsx --output-path=build && npm run styles",
"start": "wp-scripts start src/index_DashboardWidget.jsx src/index_Automations.jsx src/index_BlockEditor.jsx src/index_ShortcodeAsanaProject.jsx src/index_ShortcodeAsanaTask.jsx src/index_PinnedTasksMetabox.jsx --output-path=build",
"bundle": "npm run build && bash bundle.sh",
"styles": "sass --style=compressed assets/styles/scss:assets/styles",
"watch:styles": "sass --style=expanded --watch assets/styles/scss:assets/styles"
Expand Down
3 changes: 2 additions & 1 deletion phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
<exclude-pattern>/build/*</exclude-pattern>

<!-- Strip the filepaths down to the relevant bit. -->
<arg name="basepath" value="."/>
<!-- Disabled for VS Code PHPCS extension to work via absolute file paths. -->
<!-- <arg name="basepath" value="."/> -->

<!-- Check up to 8 files simultaneously. -->
<arg name="parallel" value="8"/>
Expand Down
6 changes: 3 additions & 3 deletions src/components/task/TaskListItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import '../../../assets/styles/scss/components/task/_TaskListItem.scss';

const { useState, useEffect, useRef } = wp.element;

export default function TaskListItem({ task, rowNumber = null }) {
export default function TaskListItem({ task, rowNumber = null, tagName: Element = 'li' }) {
const [ isExpanded, setIsExpanded ] = useState(false);
const rootRef = useRef(null);

Expand Down Expand Up @@ -272,7 +272,7 @@ export default function TaskListItem({ task, rowNumber = null }) {
);

return (
<li className={"ptc-TaskListItem"+extraClassNames} ref={rootRef}>
<Element className={"ptc-TaskListItem"+extraClassNames} ref={rootRef}>
<div
className="main"
onClick={
Expand All @@ -289,6 +289,6 @@ export default function TaskListItem({ task, rowNumber = null }) {
</div>
</div>
{maybeExpandedDetails}
</li>
</Element>
);
}
90 changes: 90 additions & 0 deletions src/components/task/TaskSingleAsync.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* TaskSingleAsync component
*
* @since [unreleased]
*/

import TaskListItem from './TaskListItem.jsx';

import '../../../assets/styles/scss/components/task/_TaskSingleAsync.scss';

import { useEffect, useState } from '@wordpress/element';

export default function TaskSingleAsync({ src }) {
const [ status, setStatus ] = useState('idle');
const [ task, setTask ] = useState(null);

useEffect(() => {
// Load task data from src on mount.
if ( 'idle' === status && null === task ) {

if ( 'string' === typeof src ) {

// Signal loading.
setStatus('loading');

// Request data from src URL string.
window
.fetch(src)
.then( res => {
if ( 200 !== res.status ) {
return Promise.reject( `Error ${res.status}. Failed to load task.` );
}
return res.json();
})
.then( data => {
setTask(data);
setStatus('success');
return Promise.resolve();
})
.catch( err => {
setStatus(err);
setTask(null);
});
} else if ( 'object' === typeof src ) {
// Use provided task src data.
setTask(src);
setStatus('success');
} else {
// Unsupported task src provided!
setStatus('Failed to load task due to an unexpected error.');
setTask(null);
window.console.warn('Unsupported TaskSingleAsync[src] type:', src);
}
}
}, []);

// Render.

let innerContent = null;
switch ( status ) {

case 'success':
if ( task ) {
innerContent = <TaskListItem tagName="div" task={task} />;
}
break;

case 'loading':
innerContent = <p className="ptc-loader">Loading task...</p>;
break;

case 'error':
innerContent = <p className="ptc-error">Failed to load task.</p>;
break;

case 'idle':
innerContent = null;
break;

default:
innerContent = <p className="ptc-error">{status}</p>;
break;
}

return (
<div className="ptc-TaskSingleAsync">
{innerContent}
</div>
);
}
29 changes: 18 additions & 11 deletions src/includes/class-asana-interface.php
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ public static function get_project_data(
)
) {
// Ensure sorting field is returned.
// Always add "name" subfield in case its an object.
// Always add "name" subfield in case its an object like "assignee".
$task_fields .= ",{$args['sort_tasks_by']},{$args['sort_tasks_by']}.name";
$do_remove_tasks_sort_field = true;
}
Expand Down Expand Up @@ -1287,11 +1287,13 @@ function ( $err ) {
* Attempts to retrieve task data. Providing the post id of the provided
* pinned task gid will also attempt data self-healing.
*
* @since [unreleased] Revived $opt_fields param.
* @since 3.1.0 Marked $opt_fields param as deprecated.
* @since 1.0.0
*
* @param string $task_gid The gid of the task to retrieve.
* @param string $opt_fields_deprecated Deprecated.
* @param string $opt_fields Optional. The task fields to be retrieved.
* Default '' to use Asana_Interface::TASK_OPT_FIELDS.
* @param int $post_id Optional. The post ID on which
* the task belongs to attempt self-healing on certain error
* responses. Default 0 to take no action on failure.
Expand All @@ -1302,14 +1304,10 @@ function ( $err ) {
* * 400: Invalid task gid - The provided task gid is invalid.
* * 410: Invalid task - The task is no longer available or relevent.
*/
public static function maybe_get_task_data( string $task_gid, string $opt_fields_deprecated = '', int $post_id = 0 ) : \stdClass {
public static function maybe_get_task_data( string $task_gid, string $opt_fields = '', int $post_id = 0 ) : \stdClass {

if ( ! empty( $opt_fields_deprecated ) ) {
_deprecated_argument(
__FUNCTION__,
'3.1.0',
'$opt_fields is now a member constant, ' . __CLASS__ . '::TASK_OPT_FIELDS'
);
if ( empty( $opt_fields ) ) {
$opt_fields = self::TASK_OPT_FIELDS;
}

$task_gid = Options::sanitize( 'gid', $task_gid );
Expand All @@ -1319,8 +1317,17 @@ public static function maybe_get_task_data( string $task_gid, string $opt_fields

try {

$asana = self::get_client();
$task = $asana->tasks->findById( $task_gid, array( 'opt_fields' => self::TASK_OPT_FIELDS ) );
// Load Asana client.
$asana = null;
if ( ! isset( self::$asana ) ) {
// Might throw exception.
$asana = self::get_client();
} else {
$asana = self::$asana;
}

// Fetch the task data.
$task = $asana->tasks->findById( $task_gid, array( 'opt_fields' => $opt_fields ) );

if (
isset( $task->workspace->gid ) &&
Expand Down
34 changes: 32 additions & 2 deletions src/includes/class-html-builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ public static function get_relative_due( \stdClass $task ) : \stdClass {

} else {

$dt_string = $dt->format( 'M j' );
$dt_string = $dt_due->format( 'M j' );
$relative_due->status = 'later';
}

Expand Down Expand Up @@ -530,7 +530,8 @@ public static function get_oembed_for_url( string $url ) : string {
}

/**
* Gets the local API endpoint for retrieving an attachment.
* Gets the local API endpoint for retrieving an attachment's content
* for viewing.
*
* @since 3.7.0 Deprecated $post_id parameter.
* @since 3.5.0
Expand Down Expand Up @@ -570,6 +571,35 @@ public static function get_local_attachment_view_url(
);
}

/**
* Gets the local API endpoint for retrieving an attachment with
* the provided arguments.
*
* @see PTC_Completionist\REST_API\Attachments::handle_get_attachment()
*
* @since [unreleased]
*
* @param string $attachment_gid The Asana attachment's GID.
* @param array $args Optional. Additional arguments for the
* API endpoint which retrieves the attachment's data.
* @return string The local API endpoint URL.
*/
public static function get_local_attachment_url(
string $attachment_gid,
array $args = array()
) : string {

$args['_cache_key'] = 'get_local_attachment_url';
$args['attachment_gid'] = $attachment_gid;

$token = Request_Token::save( $args );

return add_query_arg(
array( 'token' => $token ),
rest_url( REST_API_NAMESPACE_V1 . '/attachments' )
);
}

/**
* Sanitizes content for allowed HTML tags for post content.
*
Expand Down
Loading
Loading