Skip to content

Commit

Permalink
added project variables deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
d.maximchuk committed Sep 23, 2024
1 parent 206dac6 commit 7cd2102
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 12 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
postgres:
image: postgres:13-alpine
ports:
- "127.0.0.1:5432:5432"
- "127.0.0.1:6543:6543"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
Expand Down
15 changes: 15 additions & 0 deletions featureflags/graph/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,3 +484,18 @@ async def update_value_changelog(
}
)
)


@auth_required
@track
async def delete_variable(
variable_id: str, *, conn: SAConnection,
) -> None:
assert variable_id, "Variable id is required"

variable_uuid = UUID(hex=variable_id)
await conn.execute(
Variable.__table__.delete().where(
Variable.id == variable_uuid
)
)
60 changes: 59 additions & 1 deletion featureflags/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
ResetValueResult,
SaveFlagResult,
SaveValueResult,
DeleteVariableResult,
)
from featureflags.graph.utils import is_valid_uuid
from featureflags.metrics import wrap_metric
Expand Down Expand Up @@ -840,7 +841,29 @@ def get_field(name: str) -> str | None:
DeleteValueNode = Node(
"DeleteValue",
[
Field("error", None, delete_flag_info),
Field("error", None, delete_value_info),
],
)


async def delete_variable_info(
fields: list[Field], results: list[DeleteVariableResult]
) -> list[list]:
[result] = results

def get_field(name: str) -> str | None:
if name == "error":
return result.error

raise ValueError(f"Unknown field: {name}")

return [[get_field(f.name)] for f in fields]


DeleteVariableNode = Node(
"DeleteVariable",
[
Field("error", None, delete_variable_info),
],
)

Expand Down Expand Up @@ -1111,6 +1134,33 @@ async def delete_value(ctx: dict, options: dict) -> DeleteValueResult:
return DeleteValueResult(None)


@pass_context
async def delete_variable(ctx: dict, options: dict) -> DeleteVariableResult:
async with ctx[GraphContext.DB_ENGINE].acquire() as conn:
is_variable_checks_exists = await exec_scalar(
ctx[GraphContext.DB_ENGINE],
(
select([Check.id])
.where(Check.variable == UUID(options["id"]))
.limit(1)
),
)
if is_variable_checks_exists:
return DeleteVariableResult(
"Cannot delete Variable which uses in Conditions."
)

try:
await actions.delete_variable(
options["id"],
conn=conn,
)
except Exception as e:
return DeleteVariableResult(str(e))

return DeleteVariableResult(None)


mutation_data_types = {
"SaveFlagOperation": Record[{"type": String, "payload": Any}],
"SaveValueOperation": Record[{"type": String, "payload": Any}],
Expand All @@ -1127,6 +1177,7 @@ async def delete_value(ctx: dict, options: dict) -> DeleteValueResult:
ResetValueNode,
DeleteFlagNode,
DeleteValueNode,
DeleteVariableNode,
Root(
[
Link(
Expand Down Expand Up @@ -1191,6 +1242,13 @@ async def delete_value(ctx: dict, options: dict) -> DeleteValueResult:
options=[Option("id", String)],
requires=None,
),
Link(
"deleteVariable",
TypeRef["DeleteVariable"],
delete_variable,
options=[Option("id", String)],
requires=None,
),
]
),
],
Expand Down
4 changes: 4 additions & 0 deletions featureflags/graph/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,7 @@ class ResetValueResult(NamedTuple):

class DeleteValueResult(NamedTuple):
error: str | None = None


class DeleteVariableResult(NamedTuple):
error: str | None = None
57 changes: 48 additions & 9 deletions ui/src/Dashboard/Check.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ import {
Row,
Space,
Select,
message,
} from 'antd';
import {
MinusOutlined,
} from '@ant-design/icons';
import { CloseOutlined, MinusOutlined } from '@ant-design/icons';

import './Check.less';
import { Operators, TYPES, Type } from './constants';
import {
useChecks,
useProjectsMap,
} from './context';
import { useMutation } from '@apollo/client';
import { useChecks, useProjectsMap } from './context';
import { DELETE_VARIABLE_MUTATION } from "./queries";

const { Option } = Select;

Expand Down Expand Up @@ -81,6 +79,38 @@ const CheckInput = ({ conditionId, check, projectName }) => {
/>;
}

const DeleteVariable = ({ varName, varId }) => {
const [removeValue] = useMutation(DELETE_VARIABLE_MUTATION, {
variables: { id: varId },
onCompleted: (data) => {
if (data.deleteVariable && data.deleteVariable.error) {
message.error(data.deleteVariable.error);
} else {
message.success(`Variable "${varName}" removed successfully`);
}
},
onError: (error) => {
message.error(`Error removing variable "${varName}": ${error.message}`);
}
});

const handleRemove = () => {
if (confirm(`Are you sure to delete "${varName}" variable from project?`)) {
removeValue();
}
};

return (
<CloseOutlined
onClick={(e) => {
e.stopPropagation();
handleRemove();
}}
style={{ cursor: 'pointer' }}
/>
);
};

export const Check = ({ conditionId, check, onDeleteCheck, projectName }) => {
const projectsMap = useProjectsMap();
const project = projectsMap[projectName];
Expand Down Expand Up @@ -116,8 +146,17 @@ export const Check = ({ conditionId, check, onDeleteCheck, projectName }) => {
onChange={onVariableOptionChange}
>
{project.variables.map((variable) => (
<Option key={variable.id}
value={variable.id}>{variable.name}</Option>
<Option key={variable.id} value={variable.id}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span>{variable.name}</span>
{check.variable !== variable.id && (
<DeleteVariable
varId={variable.id}
varName={variable.name}
/>
)}
</div>
</Option>
))}
</Select>
<Select
Expand Down
1 change: 0 additions & 1 deletion ui/src/Dashboard/context.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export const useProjectsMap = () => {
return project;
}


export const FlagContext = createContext({});
export const useFlagState = () => {
const { state } = useContext(FlagContext);
Expand Down
8 changes: 8 additions & 0 deletions ui/src/Dashboard/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,14 @@ export const DELETE_VALUE_MUTATION = gql`
}
`;

export const DELETE_VARIABLE_MUTATION = gql`
mutation DeleteVariable($id: String!) {
deleteVariable(id: $id) {
error
}
}
`;

export const VALUE_QUERY = gql`
${VALUE_FRAGMENT}
query Value($id: String!) {
Expand Down

0 comments on commit 7cd2102

Please sign in to comment.