Skip to content

Commit

Permalink
Merge branch '3916-upgrade-plugin-button-updated' into develop
Browse files Browse the repository at this point in the history
Issue #3916
PR #4180
  • Loading branch information
VakarisZ committed May 15, 2024
2 parents dcdd9ec + 194b8af commit c21c15b
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ import {
} from '@/app/(protected)/plugins/_lib/PluginTable';
import _ from 'lodash';

type PluginFilterFunc = (row: PluginRow) => boolean;

type InstalledPluginFilterProps = {
setDisplayedRowsCallback: (rows: PluginRow[]) => void;
setIsFilteringCallback: (isFiltering: boolean) => void;
};

export type FilterProps = {
setFiltersCallback: (filters: any) => void;
};

export const defaultSearchableColumns = [
'name',
'pluginType',
Expand All @@ -31,6 +29,15 @@ const InstalledPluginFilters = (props: InstalledPluginFilterProps) => {
const { data: installedPlugins } = useGetInstalledPluginsQuery();
const [filters, setFilters] = useState({});

const setFilterCallback = (
filterName: string,
filterFunc: PluginFilterFunc
) => {
setFilters((prevState) => {
return { ...prevState, [filterName]: filterFunc };
});
};

const filterRows = (rows: PluginRow[]): PluginRow[] => {
setIsFilteringCallback(true);
let filteredRows = _.cloneDeep(rows);
Expand Down Expand Up @@ -62,7 +69,7 @@ const InstalledPluginFilters = (props: InstalledPluginFilterProps) => {
item
sx={{ alignItems: 'flex-end', display: 'flex' }}>
<SearchFilter
setFiltersCallback={setFilters}
setFilterCallback={setFilterCallback}
searchableColumns={defaultSearchableColumns}
/>
</Grid>
Expand All @@ -71,7 +78,7 @@ const InstalledPluginFilters = (props: InstalledPluginFilterProps) => {
item
sx={{ alignItems: 'flex-end', display: 'flex' }}>
<TypeFilter
setFiltersCallback={setFilters}
setFilterCallback={setFilterCallback}
allRows={allPluginRows}
/>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { GridActionsCellItem } from '@mui/x-data-grid';
import FileDownloadIcon from '@mui/icons-material/FileDownload';
import React from 'react';
import {
useGetLatestPluginVersionQuery,
useInstallPluginMutation
} from '@/redux/features/api/agentPlugins/agentPluginEndpoints';
import MonkeyLoadingIcon from '@/_components/icons/MonkeyLoadingIcon';
import DownloadDoneIcon from '@mui/icons-material/DownloadDone';
import { PluginId, PluginInfo } from '@/redux/features/api/agentPlugins/types';

const PluginUpgradeButton = (props: PluginInfo) => {
const { pluginType, pluginName, pluginVersion, pluginId } = props;

const [
upgradePlugin,
{
isLoading: isUpgrading,
isSuccess: isUpgradeSuccessful,
reset: resetUpgradePlugin
}
] = useInstallPluginMutation({ fixedCacheKey: pluginName + pluginType });
const { data: latestPluginVersion, isLoading: isLoadingLatestVersion } =
useGetLatestPluginVersionQuery({
pluginType: pluginType,
pluginName: pluginName
});

const isUpgradable = React.useMemo(() => {
if (!latestPluginVersion) {
return false;
}
const upgradeAvailable = latestPluginVersion !== pluginVersion;
upgradeAvailable && isUpgradeSuccessful && resetUpgradePlugin();
return upgradeAvailable;
}, [latestPluginVersion, pluginVersion]);

const onUpgradeClick = () => {
upgradePlugin({
pluginVersion: String(latestPluginVersion),
pluginName: pluginName,
pluginType: pluginType,
pluginId: pluginId
});
};

if (isUpgrading) {
return UpgradeInProgressButton(pluginId);
} else if (isUpgradeSuccessful) {
return UpgradeDoneButton(pluginId);
} else if (isLoadingLatestVersion || !isUpgradable) {
return;
} else {
return UpgradeButton(pluginId, onUpgradeClick);
}
};

const UpgradeButton = (pluginId: PluginId, onUpgradeClick: () => void) => {
return (
<GridActionsCellItem
key={pluginId}
icon={<FileDownloadIcon />}
label="Download"
onClick={onUpgradeClick}
/>
);
};

const UpgradeInProgressButton = (pluginId: PluginId) => {
return (
<GridActionsCellItem
key={pluginId}
icon={<MonkeyLoadingIcon />}
label="Upgrading"
/>
);
};

const UpgradeDoneButton = (pluginId: PluginId) => {
return (
<GridActionsCellItem
key={pluginId}
icon={<DownloadDoneIcon />}
label="Upgrade Complete"
/>
);
};

export default PluginUpgradeButton;
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import PluginTable, {
import Grid from '@mui/material/Grid';
import { InstalledPlugin } from '@/redux/features/api/agentPlugins/types';
import InstalledPluginFilters from '@/app/(protected)/plugins/installed/InstalledPluginFilters';
import PluginUpgradeButton from '@/app/(protected)/plugins/installed/PluginUpgradeButton';

export default function InstalledPluginsPage() {
const {
Expand All @@ -19,9 +20,15 @@ export default function InstalledPluginsPage() {
const [displayedRows, setDisplayedRows] = React.useState<PluginRow[]>([]);
const [isLoadingRows, setIsLoadingRows] = React.useState(false);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const getUpgradeAction = (plugin: InstalledPlugin) => {
return [];
return (
<PluginUpgradeButton
pluginType={plugin.pluginType}
pluginName={plugin.name}
pluginVersion={plugin.version}
pluginId={plugin.id}
/>
);
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand All @@ -35,7 +42,7 @@ export default function InstalledPluginsPage() {
(installedPlugin) => installedPlugin.id === row.id
);
if (!plugin) return [];
return [...getUpgradeAction(plugin), ...getUninstallAction(plugin)];
return [getUpgradeAction(plugin)];
};

const getOverlayMessage = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ import MonkeyFileUpload, {
} from '@/_components/file-upload/MonkeyFileUpload';
import { useUploadPluginMutation } from '@/redux/features/api/agentPlugins/agentPluginEndpoints';
import MonkeyAlert from '@/_components/alerts/MonkeyAlert';
import { Severity } from '@/_components/lib/severity';

const UploadNewPlugin = () => {
const [upload, { isError, error, isLoading, isSuccess }] =
useUploadPluginMutation();
const [plugin, setPlugin] = useState(null);
const [plugin, setPlugin] = useState<null | Uint8Array>(null);
const [showSuccessAlert, setShowSuccessAlert] = useState(false);
const [pluginName, setPluginName] = useState('');
const [errors, setErrors] = useState([]);
const [errors, setErrors] = useState<any[]>([]);

const uploadStatus = useMemo(() => {
if (plugin !== null) {
Expand Down Expand Up @@ -56,8 +57,10 @@ const UploadNewPlugin = () => {
if (acceptedPlugin?.length) {
const reader = new FileReader();
reader.onload = (e) => {
if (e.target.readyState === FileReader.DONE) {
const binaryPlugin = new Uint8Array(e.target.result);
if (e.target?.readyState === FileReader.DONE) {
const binaryPlugin = new Uint8Array(
e.target.result as ArrayBuffer
);
setPlugin(binaryPlugin);
setPluginName(Object.assign(acceptedPlugin?.[0]).name);
}
Expand Down Expand Up @@ -123,15 +126,17 @@ const UploadNewPlugin = () => {
<Box sx={{ mt: '10px', mb: '10px' }}>
{showSuccessAlert && (
<MonkeyAlert
severity="success"
severity={Severity.SUCCESS}
onClose={() => setShowSuccessAlert(false)}>
<AlertTitle>
&apos;{pluginName}&apos; was successfully installed!
</AlertTitle>
</MonkeyAlert>
)}
{showErrors && (
<MonkeyAlert severity="error" onClose={() => setErrors([])}>
<MonkeyAlert
severity={Severity.ERROR}
onClose={() => setErrors([])}>
<AlertTitle>Error uploading Plugin Tar</AlertTitle>
<ul id="circle-list">
{errors.map((error, index) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
PluginTar
} from '@/redux/features/api/agentPlugins/types';
import {
parsePluginFromResponse,
parsePluginManifestResponse,
parsePluginMetadataResponse
} from '@/redux/features/api/agentPlugins/responseParsers';
Expand All @@ -34,6 +35,27 @@ export const agentPluginEndpoints = islandApiSlice.injectEndpoints({
return parsePluginMetadataResponse(response.plugins);
}
}),
getLatestPluginVersion: builder.query<
string,
{ pluginType: string; pluginName: string }
>({
// eslint-disable-next-line @typescript-eslint/no-unused-vars
query: ({ pluginType, pluginName }) => ({
url: BackendEndpoints.PLUGIN_INDEX,
method: HTTP_METHODS.GET
}),
transformResponse: (
response: {
plugins: PluginMetadataResponse;
},
_,
{ pluginType, pluginName }
): string => {
const pluginFromResponse =
response.plugins[pluginType][pluginName].slice(-1)[0];
return parsePluginFromResponse(pluginFromResponse)['version'];
}
}),
getInstalledPlugins: builder.query<InstalledPlugin[], void>({
query: () => ({
url: BackendEndpoints.PLUGIN_MANIFESTS,
Expand All @@ -43,7 +65,8 @@ export const agentPluginEndpoints = islandApiSlice.injectEndpoints({
response: PluginManifestResponse
): InstalledPlugin[] => {
return parsePluginManifestResponse(response);
}
},
providesTags: ['InstalledAgentPlugins']
}),
installPlugin: builder.mutation<any, PluginInfo>({
query: (pluginInfo: PluginInfo) => ({
Expand All @@ -54,15 +77,29 @@ export const agentPluginEndpoints = islandApiSlice.injectEndpoints({
name: pluginInfo.pluginName,
version: pluginInfo.pluginVersion
}
})
}),
invalidatesTags: ['InstalledAgentPlugins']
}),
uploadPlugin: builder.mutation<any, PluginTar>({
query: (pluginTar: PluginTar) => ({
url: BackendEndpoints.PLUGIN_INSTALL,
method: HTTP_METHODS.PUT,
headers: { 'Content-Type': 'application/octet-stream' },
body: pluginTar
})
}),
invalidatesTags: ['InstalledAgentPlugins']
}),
upgradePlugin: builder.mutation<any, PluginInfo>({
query: (pluginInfo: PluginInfo) => ({
url: BackendEndpoints.PLUGIN_INSTALL,
method: HTTP_METHODS.PUT,
body: {
plugin_type: pluginInfo.pluginType,
name: pluginInfo.pluginName,
version: pluginInfo.pluginVersion
}
}),
invalidatesTags: ['InstalledAgentPlugins']
})
})
});
Expand All @@ -71,5 +108,6 @@ export const {
useGetAvailablePluginsQuery,
useGetInstalledPluginsQuery,
useInstallPluginMutation,
useUploadPluginMutation
useUploadPluginMutation,
useGetLatestPluginVersionQuery
} = agentPluginEndpoints;
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const parsePluginMetadataResponse = (
return plugins;
};

const parsePluginFromResponse = (
export const parsePluginFromResponse = (
unparsedPlugin: PluginMetadata
): AvailablePlugin => {
return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export type PluginId = string;

export type AgentPlugin = {
id: string;
id: PluginId;
name: string;
pluginType: string;
description: string;
Expand Down Expand Up @@ -55,7 +57,7 @@ export type PluginInfo = {
pluginType: string;
pluginName: string;
pluginVersion: string;
pluginId: string;
pluginId: PluginId;
};

export type PluginTar = Uint8Array;
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const getIslandBaseQuery = async (

export const islandApiSlice = createApi({
reducerPath: 'islandApi',
tagTypes: ['InstalledAgentPlugins'],
baseQuery: getIslandBaseQuery,
endpoints: () => ({})
});

0 comments on commit c21c15b

Please sign in to comment.