Skip to content

Commit

Permalink
Added project delete
Browse files Browse the repository at this point in the history
  • Loading branch information
githubsaturn committed Oct 5, 2024
1 parent a92cc47 commit 4aa542e
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 50 deletions.
11 changes: 11 additions & 0 deletions src/api/ApiManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,17 @@ export default class ApiManager {
)
}

deleteProjects(projectIds: string[]) {
const http = this.http

return Promise.resolve() //
.then(
http.fetch(http.POST, '/user/projects/delete', {
projectIds,
})
)
}

enableSslForBaseDomain(appName: string) {
const http = this.http

Expand Down
46 changes: 34 additions & 12 deletions src/containers/apps/AppsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class AppsTable extends Component<
{
searchTerm: string
isBulkEditMode: boolean
selectedRowKeys: React.Key[]
selectedAppKeys: React.Key[]
selectedProjectKeys: React.Key[]
selectedProjectId: string // project ID, ROOT_APPS, or ALL_APPS
}
> {
Expand All @@ -58,7 +59,8 @@ class AppsTable extends Component<
this.state = {
searchTerm: urlsQuery,
isBulkEditMode: false,
selectedRowKeys: [],
selectedAppKeys: [],
selectedProjectKeys: [],
selectedProjectId: ALL_APPS,
}
}
Expand Down Expand Up @@ -312,13 +314,17 @@ class AppsTable extends Component<
<Tooltip
title={localize(
'apps_table.bulk_delete_tooltip',
'Delete selected apps'
'Delete selected apps and projects'
)}
>
<Button
disabled={
!self.state.selectedRowKeys ||
self.state.selectedRowKeys.length === 0
(!self.state.selectedAppKeys ||
self.state.selectedAppKeys
.length === 0) &&
(!self.state.selectedProjectKeys ||
self.state.selectedProjectKeys
.length === 0)
}
type="text"
danger={true}
Expand All @@ -327,10 +333,17 @@ class AppsTable extends Component<
self.props.apps.filter(
(a) =>
a.appName &&
self.state.selectedRowKeys.includes(
self.state.selectedAppKeys.includes(
a.appName
)
),
self.props.projects.filter(
(a) =>
a.id &&
self.state.selectedProjectKeys.includes(
a.id
)
),
self.props.apiManager,
(success) => {
// with or without errors, let's refresh the page
Expand All @@ -350,8 +363,12 @@ class AppsTable extends Component<
self.setState({
isBulkEditMode: newState,
})
if (!newState)
self.setState({ selectedRowKeys: [] })
if (!newState) {
self.setState({
selectedAppKeys: [],
selectedProjectKeys: [],
})
}
}}
>
<UnorderedListOutlined />
Expand Down Expand Up @@ -470,12 +487,12 @@ class AppsTable extends Component<
? {
selectedRowKeys:
self.state
.selectedRowKeys,
.selectedAppKeys,
onChange: (
newSelectedRowKeys: React.Key[]
) => {
self.setState({
selectedRowKeys:
selectedAppKeys:
newSelectedRowKeys,
})
},
Expand Down Expand Up @@ -670,8 +687,11 @@ class AppsTable extends Component<
}

const onCheck: TreeProps['onCheck'] = (checkedKeys, info) => {
// console.log('onCheck', checkedKeys, info)
// TODO!
self.setState({
selectedProjectKeys: (checkedKeys as any).length
? checkedKeys
: (checkedKeys as any).checked,
})
}

return (
Expand Down Expand Up @@ -707,6 +727,7 @@ class AppsTable extends Component<
<Tree.DirectoryTree
style={{ marginLeft: -22, position: 'absolute' }}
showLine
checkStrictly={true}
showIcon={false}
checkable={!!self.state.isBulkEditMode}
defaultExpandedKeys={[ROOT_APPS]}
Expand All @@ -717,6 +738,7 @@ class AppsTable extends Component<
? [self.state.selectedProjectId]
: []
}
checkedKeys={self.state.selectedProjectKeys}
onSelect={onSelect}
onCheck={onCheck}
treeData={treeData}
Expand Down
121 changes: 83 additions & 38 deletions src/containers/apps/DeleteAppConfirm.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Checkbox, Input, Modal, message } from 'antd'
import ApiManager from '../../api/ApiManager'
import { IHashMapGeneric } from '../../models/IHashMapGeneric'
import ProjectDefinition from '../../models/ProjectDefinition'
import Toaster from '../../utils/Toaster'
import Utils from '../../utils/Utils'
import NewTabLink from '../global/NewTabLink'
import { IAppDef } from './AppDefinition'

export default function onDeleteAppClicked(
appDefinitionsInput: IAppDef[],
projects: ProjectDefinition[],
apiManager: ApiManager,
onFinished: (success: boolean) => void
) {
Expand Down Expand Up @@ -44,13 +46,35 @@ export default function onDeleteAppClicked(
</ul>
)

const projectList = (
<ul style={{ marginTop: 6 }}>
{projects.map((a) => (
<li key={a.id || ''}>
{' '}
<code>{a.name}</code>
</li>
))}
</ul>
)

Modal.confirm({
okType: 'danger',
title: 'Confirm Permanent Delete?',
content: (
<div>
<div>
You are about to delete {appsList}
<div
className={
appDefinitions.length ? '' : 'hide-on-demand'
}
>
Apps:
{appsList}
</div>
<div className={projects.length ? '' : 'hide-on-demand'}>
Projects:
{projectList}
</div>
Please note that this is
<b> not reversible</b>.
</div>
Expand Down Expand Up @@ -101,45 +125,66 @@ export default function onDeleteAppClicked(
}
})

return apiManager
.deleteApp(
undefined,
volumes,
appDefinitions.map((a) => a.appName || '')
)
.then(function (data) {
const volumesFailedToDelete =
data.volumesFailedToDelete as string[]
if (volumesFailedToDelete && volumesFailedToDelete.length) {
Modal.info({
title: "Some volumes weren't deleted!",
content: (
<div>
<p>
Some volumes weren't deleted because
they were probably being used by other
containers. Sometimes, this is because
of a temporary delay when the original
container deletion was done with a
delay. Please consult the{' '}
<NewTabLink url="https://caprover.com/docs/persistent-apps.html#removing-persistent-apps">
documentation
</NewTabLink>{' '}
and delete them manually if needed.
Skipped volumes are:
</p>
<ul>
{volumesFailedToDelete.map((v) => (
<li>
<code>{v}</code>
</li>
))}
</ul>
</div>
),
return Promise.resolve()
.then(function () {
if (!appDefinitions || appDefinitions.length === 0) return
return apiManager
.deleteApp(
undefined,
volumes,
appDefinitions.map((a) => a.appName || '')
)
.then(function (data) {
const volumesFailedToDelete =
data.volumesFailedToDelete as string[]
if (
volumesFailedToDelete &&
volumesFailedToDelete.length
) {
Modal.info({
title: "Some volumes weren't deleted!",
content: (
<div>
<p>
Some volumes weren't deleted
because they were probably being
used by other containers.
Sometimes, this is because of a
temporary delay when the
original container deletion was
done with a delay. Please
consult the{' '}
<NewTabLink url="https://caprover.com/docs/persistent-apps.html#removing-persistent-apps">
documentation
</NewTabLink>{' '}
and delete them manually if
needed. Skipped volumes are:
</p>
<ul>
{volumesFailedToDelete.map(
(v) => (
<li>
<code>{v}</code>
</li>
)
)}
</ul>
</div>
),
})
}

message.success('App(s) deleted!')
})
})
.then(function () {
if (projects.length) {
return apiManager
.deleteProjects(projects.map((it) => it.id))
.then(() => {
message.success('Project(s) deleted!')
})
}
message.success('App deleted!')
})
.then(function () {
onFinished(true)
Expand Down
1 change: 1 addition & 0 deletions src/containers/apps/appDetails/AppDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ class AppDetails extends ApiComponent<
.appDefinition
),
],
[],
self.apiManager,
(success) => {
// with or without error, go back to apps
Expand Down

0 comments on commit 4aa542e

Please sign in to comment.