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

tasks code and task history displayed in app panel #360

Merged
merged 22 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
865c7cc
task docstring, code and run histroy added
deepakdinesh1123 Aug 5, 2024
23aa8df
task result fields modified, docstring field removed
deepakdinesh1123 Aug 13, 2024
962b520
ADD : Task History added
prem056627 Aug 12, 2024
cf06402
Add : Code container changed to monaco editor
prem056627 Aug 13, 2024
f45f2c7
Fix:Task History card updated
prem056627 Aug 13, 2024
d9fdcc2
Fix : line breaks fixed at task history card
prem056627 Aug 13, 2024
bc87905
Add : card text made overflow x -axis
prem056627 Aug 13, 2024
a05b57e
Fix : task coloumn title changes bold to normal weight
prem056627 Aug 13, 2024
d300e70
Delete: comment deleted
prem056627 Aug 13, 2024
4c8f70b
FIX : task name text color changed
prem056627 Aug 13, 2024
1a88230
FIX : Mock data changes done
prem056627 Aug 14, 2024
770e067
fix lint errors
deepakdinesh1123 Aug 30, 2024
714ddb0
FIX: 1. Monoco editor made only readable 2. 'No task history' if no d…
prem056627 Sep 4, 2024
b0d0164
Fix : revert changes from main
prem056627 Sep 4, 2024
2d54a82
Add : task history modal additional added "name, id "
prem056627 Sep 4, 2024
c7e73e6
Fix : start_date issue fixed
prem056627 Sep 4, 2024
3cfe534
FIX : removed "remove policy button"
prem056627 Sep 9, 2024
5ef7943
extra workspace creation removed
deepakdinesh1123 Sep 9, 2024
5f4e43b
build removed
deepakdinesh1123 Sep 9, 2024
bc015eb
Fix : build files removed
prem056627 Sep 9, 2024
e110e3b
Remove : unwanted console removed
prem056627 Sep 11, 2024
2c0b96b
revert build changes
shahharsh176 Sep 11, 2024
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
44 changes: 43 additions & 1 deletion backend/src/zango/api/platform/tasks/v1/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import inspect
import json

from django_celery_beat.models import CrontabSchedule
from django_celery_beat.models import CrontabSchedule, PeriodicTask
from django_celery_results.models import TaskResult
from rest_framework import serializers

from zango.api.platform.permissions.v1.serializers import PolicySerializer
Expand All @@ -24,6 +26,8 @@ class TaskSerializer(serializers.ModelSerializer):
attached_policies = PolicySerializer(many=True)
crontab = CronTabSerializer()
schedule = serializers.SerializerMethodField()
code = serializers.SerializerMethodField()
run_history = serializers.SerializerMethodField()

class Meta:
model = AppTask
Expand All @@ -42,3 +46,41 @@ def update(self, instance, validated_data):

def get_schedule(self, obj):
return str(obj.crontab)[:-18]

def get_code(self, obj):
try:
md = self.context.get("plugin_source").load_plugin(
obj.name[: obj.name.rfind(".")]
)
task = getattr(md, obj.name[obj.name.rfind(".") + 1 :])
code = inspect.getsource(task)
return code
except Exception:
return ""

def get_run_history(self, obj):
if not self.context.get("history"):
return []
ptask = PeriodicTask.objects.get(id=obj.master_task_id)
serializer = TaskResultSerializer(
TaskResult.objects.filter(periodic_task_name=ptask.name).order_by(
"-date_done"
),
many=True,
)
return serializer.data


class TaskResultSerializer(serializers.ModelSerializer):
date_started = serializers.SerializerMethodField()
date_done = serializers.SerializerMethodField()

class Meta:
model = TaskResult
fields = ["date_started", "date_done", "result", "traceback"]

def get_date_started(self, obj):
return obj.date_done.strftime("%Y-%m-%d %H:%M:%S")

def get_date_done(self, obj):
return obj.date_done.strftime("%Y-%m-%d %H:%M:%S")
2 changes: 1 addition & 1 deletion backend/src/zango/api/platform/tasks/v1/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@

urlpatterns = [
path("", AppTaskView.as_view()),
re_path(r"(?P<task_uuid>[\w-]+)/", AppTaskDetailView.as_view()),
re_path(r"(?P<task_id>\d+)/", AppTaskDetailView.as_view()),
]
28 changes: 21 additions & 7 deletions backend/src/zango/api/platform/tasks/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def get_queryset(self, search, columns={}):
columns["is_enabled"] = True
if columns.get("is_enabled") == "false":
columns["is_enabled"] = False
records = AppTask.objects.all().order_by("-id")
records = AppTask.objects.filter(is_deleted=False).order_by("-id")
if search == "" and columns == {}:
return records
filters = Q()
Expand All @@ -50,7 +50,15 @@ def get(self, request, app_uuid, task_uuid=None, *args, **kwargs):
columns = get_search_columns(request)
app_tasks = self.get_queryset(search, columns)
paginated_tasks = self.paginate_queryset(app_tasks, request, view=self)
serializer = TaskSerializer(paginated_tasks, many=True)
tenant = TenantModel.objects.get(uuid=app_uuid)
connection.set_tenant(tenant)
with connection.cursor() as c:
ws = Workspace.get_plugin_source()
serializer = TaskSerializer(
paginated_tasks,
many=True,
context={"plugin_source": ws},
)
paginated_app_tasks = self.get_paginated_response_data(serializer.data)
success = True
response = {
Expand Down Expand Up @@ -85,10 +93,16 @@ def post(self, request, app_uuid, *args, **kwargs):

@method_decorator(set_app_schema_path, name="dispatch")
class AppTaskDetailView(ZangoGenericPlatformAPIView):
def get(self, request, app_uuid, task_uuid, *args, **kwargs):
def get(self, request, app_uuid, task_id, *args, **kwargs):
try:
app_task = AppTask.objects.get(id=task_uuid)
serializer = TaskSerializer(instance=app_task)
app_task = AppTask.objects.get(id=task_id)
tenant = TenantModel.objects.get(uuid=app_uuid)
connection.set_tenant(tenant)
with connection.cursor() as c:
serializer = TaskSerializer(
instance=app_task,
context={"history": True},
)
response = {"task": serializer.data}
status = 200
success = True
Expand All @@ -98,11 +112,11 @@ def get(self, request, app_uuid, task_uuid, *args, **kwargs):
success = False
return get_api_response(success, response, status)

def post(self, request, app_uuid, task_uuid, *args, **kwargs):
def post(self, request, app_uuid, task_id, *args, **kwargs):
data = request.data
crontab_exp = data.get("crontab_exp")
try:
app_task = AppTask.objects.get(id=task_uuid)
app_task = AppTask.objects.get(id=task_id)
serializer = TaskSerializer(
instance=app_task,
data=request.data,
Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion backend/src/zango/assets/js/jquery/3.7.1/jquery.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions backend/src/zango/config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@

# Celery
CELERY_RESULT_BACKEND = "django-db"
CELERY_RESULT_EXTENDED = True
X_FRAME_OPTIONS = "ALLOW"

PACKAGE_BUCKET_NAME = "zelthy3-packages"
Expand Down
64 changes: 64 additions & 0 deletions frontend/src/components/Table/HeaderInfoHover.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Menu, Transition } from '@headlessui/react';
import { Fragment, useState } from 'react';
import { usePopper } from 'react-popper';
import { ReactComponent as InfoIcon } from '../../../src/assets/images/svg/info-icon.svg';

export default function HeaderInfoHover({ message }) {
const [referenceElement, setReferenceElement] = useState(null);
const [popperElement, setPopperElement] = useState(null);
const [isOpen, setIsOpen] = useState(false);

const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: 'bottom-end',
modifiers: [
{
name: 'offset',
options: {
offset: [460, 2],
},
},
],
});

return (
<div
className="relative"
onMouseEnter={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)}
>
<Menu as="div" className="relative flex">
<Transition
as={Fragment}
ref={(ref) => setPopperElement(ref)}
style={styles.popper}
{...attributes.popper}
show={isOpen}
>
<Menu.Items className="absolute bottom-[30px] right-0 z-20 min-w-[186px] origin-bottom-right rounded-[4px] bg-white shadow-table-menu focus:outline-none">
<div className="p-[4px]">
<Menu.Item>
{({ active }) => (
<div
className={`${
active ? 'bg-white' : ''
} flex w-full max-w-fit flex-col rounded-[2px] px-[12px] py-[8px]`}
>
<span className="text-wrap text-start font-lato text-[12px] leading-[16px] tracking-[0.2px] text-[#6C747D]">
{message}
</span>
</div>
)}
</Menu.Item>
</div>
</Menu.Items>
</Transition>
<Menu.Button
className="relative z-10 flex w-full justify-center focus:outline-none"
ref={(ref) => setReferenceElement(ref)}
>
<InfoIcon className="h-[16px] min-h-[16px] w-[16px] min-w-[16px] " />
</Menu.Button>
</Menu>
</div>
);
}
2 changes: 1 addition & 1 deletion frontend/src/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "buildMajor": 0, "buildMinor": 3, "buildPatch": 0, "buildTag": "" }
{ "buildMajor": 0, "buildMinor": 3, "buildPatch": 0, "buildTag": "" }
110 changes: 110 additions & 0 deletions frontend/src/mocks/appTasksManagementHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const newTask = () => {
last_login: faker.date.past(),
is_enabled: faker.datatype.boolean(),
created_at: faker.date.past(),
docstring: '\n This is a docstring\n ',
code: '@shared_task()\ndef test():\n """\n This is a docstring\n """\n print("test")\n return "test"\n',
};
};

Expand Down Expand Up @@ -99,6 +101,7 @@ export const appTasksManagementHandlers = [
return res(
ctx.delay(500),
ctx.status(200),

ctx.json({
success: true,
response: {
Expand All @@ -123,6 +126,113 @@ export const appTasksManagementHandlers = [
);
}),

rest.get('/api/v1/apps/:appId/tasks/:taskId', (req, res, ctx) => {
return res(
ctx.delay(500),
ctx.status(200),
ctx.json({
success: true,
response: {
task: {
id: 2,
attached_policies: [],
crontab: {
minute: '*',
hour: '*',
day_of_week: '*',
day_of_month: '*',
month_of_year: '*',
},
schedule: '* * * * *',
docstring: '',
code: '',
run_history: [
{
date_started: '2024-08-12T07:30:00.043275Z',
date_done: '2024-08-12T07:30:00.043294Z',
result: '"Task completed successfully"',
traceback: null,
},
{
date_started: '2024-08-12T07:29:00.039694Z',
date_done: '2024-08-12T07:29:00.039726Z',
result: '"Data processed"',
traceback:
'Traceback(mostrecentalllast):Filetask.py,line4,inprocess_datadatafetch_dTraceback(mostrecent call last):\n File "task.py", line 34, in process_data\n data = fetch_dTraceback (most recent call last):\n File "task.py", line 34, in process_data\n data = fetch_dTraceback (most recent call last):\n File "task.py", line 34, in process_data\n data = fetch_dTraceback (most recent call last):\n File "task.py", line 34, in process_data\n data = fetch_dTraceback (most recent call last):Filetask.py", line 34, in process_data\n data = fetch_dTraceback (most recent call last):\n File "task.py", line 34, in process_data\n data = fetch_dTraceback (most recent call last):\n File "task.py", line 34, in process_data\n data = fetch_data()\nKeyError: \'id\'',
},
{
date_started: '2024-08-12T07:28:00.141579Z',
date_done: '2024-08-12T07:28:00.141628Z',
result: '"Export failed"',
traceback:
'TraceThisisaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocsspropertiesappliedtowraporbreakwordsappropriatelysuchtextcanoverfloworbreaklayoutsinunexpectedsituationsback (most recent call last):\n File "task.py", line 22, in export_data\n export_to_csv(data)\nFileNotFoundError: [Errno 2] No such file or directory: \'output.csv\'',
},
{
date_started: '2024-08-12T07:27:00.141579Z',
date_done: '2024-08-12T07:27:00.141628Z',
result: '"Email sent"',
traceback: null,
},
{
date_started: '2024-08-12T07:26:00.141579Z',
date_done: '2024-08-12T07:26:00.141628Z',
result: '"Database update failed"',
traceback:
'TracThisisaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocsspropertiesappliedtowraporbreakwordsappropriatelysuchtextcanoverfloworbreaklayoutsinunexpectedsituationseback (most recent call last):\n File "task.py", line 45, in update_database\n cursor.execute(query)\npsycopg2.IntegrityError: duplicate key value violates unique constraint "users_pkey"',
},
{
date_started: '2024-08-12T07:25:00.141579Z',
date_done: '2024-08-12T07:25:00.141628Z',
result: '"Backup completed with warnings"',
traceback:
'Traceback (most recent call last):\n File "backup.py", line 10, in perform_backup\n raise Warning(\'Low disk space\')\nWarning: Low disk space',
},
{
date_started: '2024-08-12T07:24:00.141579Z',
date_done: '2024-08-12T07:24:00.141628Z',
result: '"Report generation failed"',
traceback:
'Traceback (most recent call last):\n FiThisisaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocssproaplaceholderparagraphdesignedtoshowwhattextwithoutspaceslookslikewhenitisrenderedinawebpagewithnocsspropertiesappliedtowraporbreakwordsappropriatelysuchtextcanoverfloworbreaklayoutsinunexpectedsituationsle "report.py", line 59, in generate_report\n report = create_report(data)\nValueError: Missing required field \'report_name\'',
},
{
date_started: '2024-08-12T07:23:00.141579Z',
date_done: '2024-08-12T07:23:00.141628Z',
result: '"Task completed with warnings"',
traceback:
'Traceback (most recent call last):\n File "task.py", line 78, in execute_task\n validate_input(input_data)\nDeprecationWarning: \'validate_input\' is deprecated and will be removed in future versions',
},
{
date_started: '2024-08-12T07:22:00.141579Z',
date_done: '2024-08-12T07:22:00.141628Z',
result: '"Task failed"',
traceback:
'Traceback (most recent call last):\n File "task.py", line 11, in perform_task\n run_process()\nTypeError: \'NoneType\' object is not callable',
},
{
date_started: '2024-08-12T07:21:00.141579Z',
date_done: '2024-08-12T07:21:00.141628Z',
result: '"File upload failed"',
traceback:
'Traceback (most recent call last):\n File "upload.py", line 27, in upload_file\n response = requests.post(url, files=files)\nrequests.exceptions.ConnectionError: Failed to establish a new connection',
},
],

created_at: '2024-08-12T07:22:14.716445Z',
created_by: '',
modified_at: '2024-08-12T07:30:21.674722Z',
modified_by: '',
name: 'accounts.tasks.test',
is_enabled: false,
is_deleted: true,
args: '["CRMApp2", "accounts.tasks.test"]',
kwargs: {},
interval: null,
master_task: 52,
},
},
})
);
}),
rest.post('/api/v1/apps/:appId/tasks/', (req, res, ctx) => {
const action = req.url.searchParams.get('action');
if (action === 'sync_tasks') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createColumnHelper } from '@tanstack/react-table';
import { find } from 'lodash';
import moment from 'moment';
import HeaderInfo from '../../../../components/Table/HeaderInfo';

import ListGeneralCell from '../../../../components/Table/ListGeneralCell';
import TableDateRangeFilter from '../../../../components/Table/TableDateRangeFilter';
import TableDropdownFilter from '../../../../components/Table/TableDropdownFilter';
Expand Down Expand Up @@ -146,7 +147,7 @@ function columns({ debounceSearch, localTableData, tableData }) {
id: 'actor',
header: () => (
<div className="flex h-full items-start justify-start gap-[10px] whitespace-nowrap border-b-[4px] border-[#F0F3F4] px-[20px] py-[12px] text-start">
<span className="font-lato text-[11px] font-bold uppercase leading-[16px] tracking-[0.6px] text-[#6C747D]">
<span className="font-lato text-[11px] font-bold uppercase leading-[16px] tracking-[0.6px] text-[#6C747D] ">
Actor
</span>
<HeaderInfo message={'* Denotes Platform User'} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,11 @@ export default function RowMenu({ rowData }) {
</Menu.Button>
<Transition
as={Fragment}
// @ts-ignore
ref={(ref) => setPopperElement(ref)}
style={styles['popper']}
{...attributes['popper']}
>
<Menu.Items className="absolute top-[30px] right-0 w-[186px] origin-top-right rounded-[4px] bg-white shadow-table-menu focus:outline-none">
<Menu.Items className="absolute right-0 top-[30px] w-[186px] origin-top-right rounded-[4px] bg-white shadow-table-menu focus:outline-none">
<div className="p-[4px]">
{rowData?.status === 'Installed' ? null : (
<Menu.Item>
Expand All @@ -72,9 +71,6 @@ export default function RowMenu({ rowData }) {
<span className="text-start font-lato text-[14px] font-bold leading-[20px] tracking-[0.2px] text-[#212429]">
Install Package
</span>
{/* <span className="text-start font-lato text-[12px] leading-[16px] tracking-[0.2px] text-[#6C747D]">
install package
</span> */}
</div>
</button>
)}
Expand Down
Loading
Loading