Skip to content

Commit

Permalink
added project deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
d.maximchuk committed Oct 2, 2024
1 parent b3ef507 commit 207ada5
Show file tree
Hide file tree
Showing 14 changed files with 303 additions and 48 deletions.
2 changes: 1 addition & 1 deletion featureflags/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.1.2"
__version__ = "1.1.3"
36 changes: 33 additions & 3 deletions featureflags/graph/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,13 +489,43 @@ async def update_value_changelog(
@auth_required
@track
async def delete_variable(
variable_id: str, *, conn: SAConnection,
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
Variable.__table__.delete().where(Variable.id == variable_uuid)
)


@auth_required
@track
async def delete_project(
project_id: str,
*,
conn: SAConnection,
) -> None:
assert project_id, "Project id is required"

project_uuid = UUID(hex=project_id)

variables = await conn.execute(
select([Variable.id]).where(Project.id == project_uuid)
)
variable_ids = [v.id for v in await variables.fetchall()]

if variable_ids:
await conn.execute(
Check.__table__.delete().where(Check.variable.in_(variable_ids))
)

await conn.execute(
Variable.__table__.delete().where(Variable.project == project_uuid)
)

await conn.execute(
Project.__table__.delete().where(Project.id == project_uuid)
)
65 changes: 62 additions & 3 deletions featureflags/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
SaveFlagResult,
SaveValueResult,
DeleteVariableResult,
DeleteProjectResult,
)
from featureflags.graph.utils import is_valid_uuid
from featureflags.metrics import wrap_metric
Expand Down Expand Up @@ -170,9 +171,7 @@ async def root_values(ctx: dict, options: dict) -> list:
)

if value_name:
expr = (
expr.where(Value.name.ilike(f"%{value_name}%"))
)
expr = expr.where(Value.name.ilike(f"%{value_name}%"))

return await exec_expression(ctx[GraphContext.DB_ENGINE], expr)

Expand Down Expand Up @@ -867,6 +866,28 @@ def get_field(name: str) -> str | None:
],
)


async def delete_project_info(
fields: list[Field], results: list[DeleteProjectResult]
) -> 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]


DeleteProjectNode = Node(
"DeleteProject",
[
Field("error", None, delete_project_info),
],
)

GRAPH = Graph(
[
ProjectNode,
Expand Down Expand Up @@ -1161,6 +1182,36 @@ async def delete_variable(ctx: dict, options: dict) -> DeleteVariableResult:
return DeleteVariableResult(None)


@pass_context
async def delete_project(ctx: dict, options: dict) -> DeleteProjectResult:
async with ctx[GraphContext.DB_ENGINE].acquire() as conn:
project_uuid = UUID(options["id"])

is_flags_exists = await exec_scalar(
ctx[GraphContext.DB_ENGINE],
(select([Flag.id]).where(Flag.project == project_uuid).limit(1)),
)
if is_flags_exists:
return DeleteProjectResult("You need delete all Flags firstly.")

is_values_exists = await exec_scalar(
ctx[GraphContext.DB_ENGINE],
(select([Value.id]).where(Value.project == project_uuid).limit(1)),
)
if is_values_exists:
return DeleteProjectResult("You need delete all Values firstly.")

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

return DeleteProjectResult(None)


mutation_data_types = {
"SaveFlagOperation": Record[{"type": String, "payload": Any}],
"SaveValueOperation": Record[{"type": String, "payload": Any}],
Expand All @@ -1178,6 +1229,7 @@ async def delete_variable(ctx: dict, options: dict) -> DeleteVariableResult:
DeleteFlagNode,
DeleteValueNode,
DeleteVariableNode,
DeleteProjectNode,
Root(
[
Link(
Expand Down Expand Up @@ -1249,6 +1301,13 @@ async def delete_variable(ctx: dict, options: dict) -> DeleteVariableResult:
options=[Option("id", String)],
requires=None,
),
Link(
"deleteProject",
TypeRef["DeleteProject"],
delete_project,
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 @@ -206,3 +206,7 @@ class DeleteValueResult(NamedTuple):

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


class DeleteProjectResult(NamedTuple):
error: str | None = None
21 changes: 4 additions & 17 deletions ui/src/Base.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@ function Base({ children }) {

const navigate = useNavigate();
const queryParams = new URLSearchParams(location.search);
const tab = queryParams.get('tab') || "flags";

const setTabToUrl = (name) => {
queryParams.set('tab', name);
navigate(`/?${queryParams.toString()}`);
}
const tab = queryParams.get('tab') === 'values' ? 'values' : 'flags';

const handleSearchTermChange = (e) => {
const value = e.target.value;
Expand All @@ -43,6 +38,7 @@ function Base({ children }) {
const setSearchTermToUrl = (e) => {
const value = e.target.value;
queryParams.set('term', value);
queryParams.set('tab', tab);
navigate(`/?${queryParams.toString()}`);
};

Expand Down Expand Up @@ -79,10 +75,9 @@ function Base({ children }) {
>
FeatureFlags
</Link>

</Space>
</Col>
<Col span={4} offset={10}>
<Col span={4} offset={9}>
{tab && (
<Input
ref={inputRef}
Expand All @@ -96,15 +91,7 @@ function Base({ children }) {
/>
)}
</Col>
<Col span={6} offset={0}>
<Button
type="link"
onClick={() => setTabToUrl("flags")}
>Flags</Button>
<Button
type="link"
onClick={() => setTabToUrl("values")}
>Values</Button>
<Col span={4}>
{auth.authenticated && <Button
type="link"
onClick={signOut}
Expand Down
52 changes: 36 additions & 16 deletions ui/src/Dashboard/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { Base } from '../Base';
import { CenteredSpinner } from '../components/Spinner';
import { FlagsContainer } from './Flags';
import { ValuesContainer } from './Values';
import { SettingsContainer } from "./Settings";

import { PROJECTS_QUERY } from './queries';

Expand Down Expand Up @@ -50,7 +51,7 @@ function Dashboard({ projects }) {
const navigate = useNavigate();
const queryParams = new URLSearchParams(location.search);
const projectFromQuery = queryParams.get('project');
const tab = queryParams.get('tab');
const tab = queryParams.get('tab') || 'flags';
const searchTerm = queryParams.get('term');

const [menuItems, setMenuItems] = useState([]);
Expand Down Expand Up @@ -151,21 +152,40 @@ function Dashboard({ projects }) {
minHeight: 360,
}}
>
{
tab === "values" ? (
!!selected || !!searchTerm ? (
<ValuesContainer projectName={!!selected ? projectsMap[selected].name : null} searchTerm={searchTerm} projectsMap={projectsMap} />
) : (
<div>No Values</div>
)
) : (
!!selected || !!searchTerm ? (
<FlagsContainer projectName={!!selected ? projectsMap[selected].name : null} searchTerm={searchTerm} projectsMap={projectsMap} />
) : (
<div>No Flags</div>
)
)
}
{(() => {
if (tab === "values") {
return !!selected || !!searchTerm ? (
<ValuesContainer
projectName={!!selected ? projectsMap[selected]?.name : null}
searchTerm={searchTerm}
projectsMap={projectsMap}
/>
) : (
<div>No Values</div>
);
} else if (tab === "flags") {
return !!selected || !!searchTerm ? (
<FlagsContainer
projectName={!!selected ? projectsMap[selected]?.name : null}
searchTerm={searchTerm}
projectsMap={projectsMap}
/>
) : (
<div>No Flags</div>
);
} else if (tab === "settings") {
return !!selected || !!searchTerm ? (
<SettingsContainer
projectName={!!selected ? projectsMap[selected]?.name : null}
projectsMap={projectsMap}
/>
) : (
<div>No Settings</div>
);
} else {
return <div>Invalid Tab</div>;
}
})()}
</div>
</Content>
</Layout>
Expand Down
15 changes: 12 additions & 3 deletions ui/src/Dashboard/Flags.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ import { CenteredSpinner } from '../components/Spinner';
import { ProjectsMapContext } from './context';
import { FLAGS_QUERY } from './queries';
import { Flag } from './Flag';
import { HeaderTabs } from "./Tabs";

const getShowAllMatches = (count, searchText) => ({
label: `Show all matches(${count})`,
value: searchText
});

function getFlagKey(flag) {
return `${flag.name}_${flag.project.name}`
}

const Flags = ({ flags, isSearch }) => {
const location = useLocation();
const navigate = useNavigate();
Expand Down Expand Up @@ -49,12 +54,15 @@ const Flags = ({ flags, isSearch }) => {
}, [flagFromQuery]);

const flagsMap = useMemo(() => flags.reduce((acc, flag) => {
acc[flag.name] = flag;
acc[getFlagKey(flag)] = flag;
return acc;
}, {}), [flags]);

if (!flags.length) {
return <div>No flags</div>;
return <div>
<HeaderTabs />
No flags
</div>;
}

const listData = flags
Expand All @@ -64,7 +72,7 @@ const Flags = ({ flags, isSearch }) => {
.map((flag) => {
return {
title: flag.name,
key: flag.name,
key: getFlagKey(flag),
};
});

Expand Down Expand Up @@ -108,6 +116,7 @@ const Flags = ({ flags, isSearch }) => {
padding: '0 16px',
}}
>
<HeaderTabs />
{!isSearch && (
<AutoComplete
className='search-flags'
Expand Down
1 change: 0 additions & 1 deletion ui/src/Dashboard/Flags.less
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
.search-flags {
color: #141414;
width: 800px;
position: fixed;
z-index: 90;
border: 1px solid rgba(255, 255, 0, 0.85);
}
Expand Down
Loading

0 comments on commit 207ada5

Please sign in to comment.